use core::mem::MaybeUninit; use bit_field::BitField; use self::ble::Ble; use self::cmd::{AclDataPacket, CmdPacket}; use self::evt::CsEvt; use self::mm::MemoryManager; use self::sys::Sys; use self::unsafe_linked_list::LinkedListNode; use crate::ipcc::Ipcc; mod ble; mod channels; mod cmd; mod evt; mod mm; mod sys; mod unsafe_linked_list; pub type PacketHeader = LinkedListNode; const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::(); const TL_EVT_HEADER_SIZE: usize = 3; const TL_CS_EVT_SIZE: usize = core::mem::size_of::(); const CFG_TL_BLE_EVT_QUEUE_LENGTH: usize = 5; const CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255; const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TL_BLE_MOST_EVENT_PAYLOAD_SIZE; const POOL_SIZE: usize = CFG_TL_BLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4); const fn divc(x: usize, y: usize) -> usize { (x + y - 1) / y } #[repr(C, packed)] #[derive(Copy, Clone)] pub struct SafeBootInfoTable { version: u32, } #[repr(C, packed)] #[derive(Copy, Clone)] pub struct RssInfoTable { version: u32, memory_size: u32, rss_info: u32, } /// # Version /// - 0 -> 3 = Build - 0: Untracked - 15:Released - x: Tracked version /// - 4 -> 7 = branch - 0: Mass Market - x: ... /// - 8 -> 15 = Subversion /// - 16 -> 23 = Version minor /// - 24 -> 31 = Version major /// # Memory Size /// - 0 -> 7 = Flash ( Number of 4k sector) /// - 8 -> 15 = Reserved ( Shall be set to 0 - may be used as flash extension ) /// - 16 -> 23 = SRAM2b ( Number of 1k sector) /// - 24 -> 31 = SRAM2a ( Number of 1k sector) #[repr(C, packed)] #[derive(Copy, Clone)] pub struct WirelessFwInfoTable { version: u32, memory_size: u32, thread_info: u32, ble_info: u32, } impl WirelessFwInfoTable { pub fn version_major(&self) -> u8 { let version = self.version; (version.get_bits(24..31) & 0xff) as u8 } pub fn version_minor(&self) -> u8 { let version = self.version; (version.get_bits(16..23) & 0xff) as u8 } pub fn subversion(&self) -> u8 { let version = self.version; (version.get_bits(8..15) & 0xff) as u8 } /// size of FLASH, expressed in number of 4K sectors pub fn flash_size(&self) -> u8 { let memory_size = self.memory_size; (memory_size.get_bits(0..7) & 0xff) as u8 } /// size for SRAM2a, expressed in number of 1K sectors pub fn sram2a_size(&self) -> u8 { let memory_size = self.memory_size; (memory_size.get_bits(24..31) & 0xff) as u8 } /// size of SRAM2b, expressed in number of 1K sectors pub fn sram2b_size(&self) -> u8 { let memory_size = self.memory_size; (memory_size.get_bits(16..23) & 0xff) as u8 } } #[repr(C, packed)] #[derive(Copy, Clone)] pub struct DeviceInfoTable { pub safe_boot_info_table: SafeBootInfoTable, pub rss_info_table: RssInfoTable, pub wireless_fw_info_table: WirelessFwInfoTable, } #[repr(C, packed)] struct BleTable { pcmd_buffer: *const CmdPacket, pcs_buffer: *const u8, pevt_queue: *const u8, phci_acl_data_buffer: *mut AclDataPacket, } #[repr(C, packed)] struct ThreadTable { no_stack_buffer: *const u8, cli_cmd_rsp_buffer: *const u8, ot_cmd_rsp_buffer: *const u8, } #[repr(C, packed)] struct SysTable { pcmd_buffer: *mut CmdPacket, sys_queue: *const LinkedListNode, } #[allow(dead_code)] // Not used currently but reserved #[repr(C, packed)] struct LldTestTable { cli_cmd_rsp_buffer: *const u8, m0_cmd_buffer: *const u8, } #[allow(dead_code)] // Not used currently but reserved #[repr(C, packed)] struct BleLldTable { cmd_rsp_buffer: *const u8, m0_cmd_buffer: *const u8, } #[allow(dead_code)] // Not used currently but reserved #[repr(C, packed)] struct ZigbeeTable { notif_m0_to_m4_buffer: *const u8, appli_cmd_m4_to_m0_buffer: *const u8, request_m0_to_m4_buffer: *const u8, } #[repr(C, packed)] struct MemManagerTable { spare_ble_buffer: *const u8, spare_sys_buffer: *const u8, ble_pool: *const u8, ble_pool_size: u32, pevt_free_buffer_queue: *mut LinkedListNode, traces_evt_pool: *const u8, traces_pool_size: u32, } #[repr(C, packed)] struct TracesTable { traces_queue: *const u8, } #[repr(C, packed)] struct Mac802_15_4Table { pcmd_rsp_buffer: *const u8, pnotack_buffer: *const u8, evt_queue: *const u8, } /// reference table. Contains pointers to all other tables #[repr(C, packed)] #[derive(Copy, Clone)] pub struct RefTable { pub device_info_table: *const DeviceInfoTable, ble_table: *const BleTable, thread_table: *const ThreadTable, sys_table: *const SysTable, mem_manager_table: *const MemManagerTable, traces_table: *const TracesTable, mac_802_15_4_table: *const Mac802_15_4Table, } #[link_section = "TL_REF_TABLE"] pub static mut TL_REF_TABLE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "TL_DEVICE_INFO_TABLE"] static mut TL_DEVICE_INFO_TABLE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "TL_BLE_TABLE"] static mut TL_BLE_TABLE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "TL_THREAD_TABLE"] static mut TL_THREAD_TABLE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "TL_SYS_TABLE"] static mut TL_SYS_TABLE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "TL_MEM_MANAGER_TABLE"] static mut TL_MEM_MANAGER_TABLE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "TL_TRACES_TABLE"] static mut TL_TRACES_TABLE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "TL_MAC_802_15_4_TABLE"] static mut TL_MAC_802_15_4_TABLE: MaybeUninit = MaybeUninit::uninit(); #[allow(dead_code)] // Not used currently but reserved #[link_section = "FREE_BUF_QUEUE"] static mut FREE_BUFF_QUEUE: MaybeUninit = MaybeUninit::uninit(); // not in shared RAM static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit(); #[allow(dead_code)] // Not used currently but reserved #[link_section = "TRACES_EVT_QUEUE"] static mut TRACES_EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "CS_BUFFER"] static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> = MaybeUninit::uninit(); #[link_section = "EVT_QUEUE"] static mut EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "SYSTEM_EVT_QUEUE"] static mut SYSTEM_EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); #[link_section = "SYS_CMD_BUF"] static mut SYS_CMD_BUF: MaybeUninit = MaybeUninit::uninit(); #[link_section = "EVT_POOL"] static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); #[link_section = "SYS_SPARE_EVT_BUF"] static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = MaybeUninit::uninit(); #[link_section = "BLE_SPARE_EVT_BUF"] static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> = MaybeUninit::uninit(); #[link_section = "BLE_CMD_BUFFER"] static mut BLE_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit(); #[link_section = "HCI_ACL_DATA_BUFFER"] // "magic" numbers from ST ---v---v static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit(); pub struct TlMbox { _sys: Sys, _ble: Ble, _mm: MemoryManager, } impl TlMbox { /// initializes low-level transport between CPU1 and BLE stack on CPU2 pub fn init(ipcc: &mut Ipcc) -> TlMbox { unsafe { TL_REF_TABLE = MaybeUninit::new(RefTable { device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), ble_table: TL_BLE_TABLE.as_ptr(), thread_table: TL_THREAD_TABLE.as_ptr(), sys_table: TL_SYS_TABLE.as_ptr(), mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(), traces_table: TL_TRACES_TABLE.as_ptr(), mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(), }); TL_SYS_TABLE = MaybeUninit::zeroed(); TL_DEVICE_INFO_TABLE = MaybeUninit::zeroed(); TL_BLE_TABLE = MaybeUninit::zeroed(); TL_THREAD_TABLE = MaybeUninit::zeroed(); TL_MEM_MANAGER_TABLE = MaybeUninit::zeroed(); TL_TRACES_TABLE = MaybeUninit::zeroed(); TL_MAC_802_15_4_TABLE = MaybeUninit::zeroed(); EVT_POOL = MaybeUninit::zeroed(); SYS_SPARE_EVT_BUF = MaybeUninit::zeroed(); BLE_SPARE_EVT_BUF = MaybeUninit::zeroed(); CS_BUFFER = MaybeUninit::zeroed(); BLE_CMD_BUFFER = MaybeUninit::zeroed(); HCI_ACL_DATA_BUFFER = MaybeUninit::zeroed(); } ipcc.init(); let _sys = Sys::new(ipcc); let _ble = Ble::new(ipcc); let _mm = MemoryManager::new(); TlMbox { _sys, _ble, _mm } } pub fn wireless_fw_info(&self) -> Option { let info = unsafe { &(*(*TL_REF_TABLE.as_ptr()).device_info_table).wireless_fw_info_table }; // zero version indicates that CPU2 wasn't active and didn't fill the information table if info.version != 0 { Some(*info) } else { None } } }