use core::ffi::CStr;
use core::mem::MaybeUninit;
use core::num::NonZeroU8;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::pubsub::{PubSubBehavior, PubSubChannel, Subscriber};
use self::ffi::{tmos_event_hdr_t, tmos_msg_deallocate, tmos_msg_receive, BLE_PAControlInit, SYS_EVENT_MSG};
use crate::ble::ffi::{blePaControlConfig_t, tmos_start_task, BLE_RegInit};
use crate::gpio::sealed::Pin;
use crate::gpio::{AnyPin, Level, Output, OutputDrive};
use crate::{pac, println};
pub mod ffi;
pub mod gap;
pub mod gatt;
pub mod gatt_uuid;
pub mod gattservapp;
pub mod linkdb;
const HEAP_SIZE: usize = 1024 * 6;
#[repr(C, align(4))]
struct BLEHeap([MaybeUninit<u8>; HEAP_SIZE]);
static mut BLE_HEAP: BLEHeap = BLEHeap([MaybeUninit::uninit(); HEAP_SIZE]);
static CHANNEL: PubSubChannel<CriticalSectionRawMutex, TmosEvent, 4, 2, 2> = PubSubChannel::new();
pub type EventSubscriber = Subscriber<'static, CriticalSectionRawMutex, TmosEvent, 4, 2, 2>;
static mut PA_CONFIG: blePaControlConfig_t = blePaControlConfig_t {
txEnableGPIO: 0,
txDisableGPIO: 0,
tx_pin: 0,
rxEnableGPIO: 0,
rxDisableGPIO: 0,
rx_pin: 0,
};
#[derive(Clone, Debug)]
pub struct TmosEvent(pub *mut tmos_event_hdr_t);
unsafe impl Send for TmosEvent {}
unsafe impl Sync for TmosEvent {}
impl TmosEvent {
pub const GATT_MSG_EVENT: u8 = 0xB0;
pub const GATT_SERV_MSG_EVENT: u8 = 0xB1;
pub const GAP_MSG_EVENT: u8 = 0xD0;
#[inline(always)]
pub fn message_id(&self) -> u8 {
unsafe { (*self.0).event }
}
}
impl Drop for TmosEvent {
fn drop(&mut self) {
unsafe {
let _ = tmos_msg_deallocate(self.0 as *mut u8);
}
}
}
pub struct PaConfig {
pub pa_tx_pin: AnyPin,
pub pa_rx_pin: AnyPin,
pub pa_tx_active_high: bool,
pub pa_rx_active_high: bool,
}
fn configure_pa(pa_config: PaConfig) {
let tx_pin = pa_config.pa_tx_pin;
let rx_pin = pa_config.pa_rx_pin;
unsafe {
PA_CONFIG.tx_pin = tx_pin._pin() as u32;
PA_CONFIG.txEnableGPIO = tx_pin.block().out().as_ptr() as u32;
PA_CONFIG.txDisableGPIO = tx_pin.block().clr().as_ptr() as u32;
PA_CONFIG.rx_pin = rx_pin._pin() as u32;
PA_CONFIG.rxEnableGPIO = rx_pin.block().out().as_ptr() as u32;
PA_CONFIG.rxDisableGPIO = rx_pin.block().clr().as_ptr() as u32;
let tx_pin = Output::new(tx_pin, Level::High, OutputDrive::_5mA);
let rx_pin = Output::new(rx_pin, Level::Low, OutputDrive::_5mA);
core::mem::forget(tx_pin);
core::mem::forget(rx_pin);
}
}
pub struct Config {
pub mac_addr: MacAddress,
pub pa_config: Option<PaConfig>,
}
impl Config {
pub fn use_factory_mac_address(&mut self) -> &mut Self {
self.mac_addr = MacAddress::from_raw(crate::isp::get_mac_address());
self
}
pub fn enbale_pa(&mut self, tx_pin: AnyPin, rx_pin: AnyPin) -> &mut Self {
self.pa_config = Some(PaConfig {
pa_tx_pin: tx_pin,
pa_rx_pin: rx_pin,
pa_tx_active_high: true,
pa_rx_active_high: true,
});
self
}
}
impl Default for Config {
fn default() -> Self {
let mac_addr = MacAddress::from_msb([0x11, 0x22, 0x33, 0x44, 0x55, 0x66]);
Config {
mac_addr,
pa_config: None,
}
}
}
const HAL_REG_INIT_EVENT: u16 = 0x2000;
const HAL_PA_INIT_EVENT: u16 = 0x1000;
const HAL_TMOS_TASK_INTERVAL: u32 = (120000) * 1000 / 625;
unsafe extern "C" fn hal_tmos_task(task_id: u8, events: u16) -> u16 {
if events & SYS_EVENT_MSG != 0 {
let msg = tmos_msg_receive(task_id);
if !msg.is_null() {
let event = TmosEvent(msg as _);
CHANNEL.publish_immediate(event);
}
return events ^ SYS_EVENT_MSG;
} else if events & HAL_REG_INIT_EVENT != 0 {
BLE_RegInit();
tmos_start_task(task_id, HAL_REG_INIT_EVENT, HAL_TMOS_TASK_INTERVAL);
return events ^ HAL_REG_INIT_EVENT;
} else if events & HAL_PA_INIT_EVENT != 0 {
BLE_PAControlInit(&PA_CONFIG);
return events ^ HAL_PA_INIT_EVENT;
} else {
crate::println!("!! hal_tmos_task: task_id: {}, events: 0x{:04x}", task_id, events);
return 0;
}
}
pub fn init(
config: Config,
) -> Result<(u8, Subscriber<'static, CriticalSectionRawMutex, TmosEvent, 4, 2, 2>), NonZeroU8> {
use ffi::{bleConfig_t, BLE_LibInit, TMOS_ProcessEventRegister, TMOS_TimerInit, LL_TX_POWEER_6_DBM};
const BLE_TX_NUM_EVENT: u8 = 1;
const BLE_BUFF_NUM: u8 = 5;
const BLE_BUFF_MAX_LEN: u16 = 27;
const BLE_TX_POWER: u8 = LL_TX_POWEER_6_DBM;
const PERIPHERAL_MAX_CONNECTION: u8 = 1;
const CENTRAL_MAX_CONNECTION: u8 = 3;
let mut cfg: bleConfig_t = unsafe { core::mem::zeroed() };
cfg.MEMAddr = unsafe { BLE_HEAP.0.as_ptr() as u32 };
cfg.MEMLen = HEAP_SIZE as _;
cfg.BufMaxLen = BLE_BUFF_MAX_LEN;
cfg.BufNumber = BLE_BUFF_NUM;
cfg.TxNumEvent = BLE_TX_NUM_EVENT;
cfg.TxPower = BLE_TX_POWER;
cfg.SelRTCClock = 0;
cfg.ConnectNumber = (PERIPHERAL_MAX_CONNECTION & 3) | (CENTRAL_MAX_CONNECTION << 2);
cfg.srandCB = Some(srand);
cfg.rcCB = None; cfg.tsCB = Some(temperature_raw);
cfg.MacAddr = config.mac_addr.0;
unsafe {
BLE_LibInit(&cfg)?;
TMOS_TimerInit(core::ptr::null_mut())?;
let hal_task_id = TMOS_ProcessEventRegister(Some(hal_tmos_task));
tmos_start_task(hal_task_id, HAL_REG_INIT_EVENT, HAL_TMOS_TASK_INTERVAL);
if let Some(pa_config) = config.pa_config {
configure_pa(pa_config);
tmos_start_task(hal_task_id, HAL_PA_INIT_EVENT, 0);
}
Ok((hal_task_id, CHANNEL.subscriber().unwrap()))
}
}
pub unsafe extern "C" fn srand() -> u32 {
let systick = unsafe { &*pac::SYSTICK::PTR };
systick.cnt().read().bits() as u32
}
pub unsafe extern "C" fn temperature_raw() -> u16 {
let mut regs: [u8; 4] = [0; 4];
let rb = &*pac::ADC::PTR;
let sys = &*pac::SYS::PTR; regs[0] = sys.tkey_cfg().read().bits();
regs[1] = rb.tem_sensor().read().bits();
regs[2] = rb.channel().read().bits();
regs[3] = rb.cfg().read().bits();
let peri = crate::peripherals::ADC::steal();
let mut adc = crate::adc::Adc::new(peri, crate::adc::Config::for_temperature());
let mut temp_sensor = adc.enable_temperature();
let data = adc.read(&mut temp_sensor);
core::mem::forget(adc);
sys.tkey_cfg().write(|w| w.bits(regs[0]));
rb.tem_sensor().write(|w| w.bits(regs[1]));
rb.channel().write(|w| w.bits(regs[2]));
rb.cfg().write(|w| w.bits(regs[3]));
data
}
pub fn lib_version() -> &'static str {
unsafe {
let version = CStr::from_ptr(ffi::VER_LIB.as_ptr());
version.to_str().unwrap()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MacAddress([u8; 6]);
impl MacAddress {
#[inline(always)]
pub fn from_raw(addr: [u8; 6]) -> Self {
MacAddress(addr)
}
pub fn from_msb(addr: [u8; 6]) -> Self {
MacAddress([addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]])
}
}
impl core::fmt::Display for MacAddress {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let MacAddress(addr) = self;
write!(
f,
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]
)
}
}
impl From<[u8; 6]> for MacAddress {
fn from(addr: [u8; 6]) -> Self {
MacAddress::from_msb(addr)
}
}