├── .gitignore ├── rfparams ├── run.bat ├── flash.bat ├── libs ├── libbl602_wifi.a ├── libblecontroller.a └── libbl602_wifi_manage.a ├── make.bat ├── src ├── binary │ ├── mod.rs │ ├── c_types.rs │ └── bl_wifi.rs ├── lib.rs ├── compat │ ├── mod.rs │ ├── queue.rs │ ├── work_queue.rs │ ├── malloc.rs │ ├── bl602.rs │ ├── circbuf.rs │ └── common.rs ├── ble │ ├── controller │ │ └── mod.rs │ └── mod.rs ├── log │ └── mod.rs ├── timer.rs ├── preemt │ └── mod.rs ├── wifi │ └── mod.rs └── os_adapter.rs ├── examples ├── simple │ ├── wifi_config.rs │ └── main.rs ├── dhcp │ ├── wifi_config.rs │ └── main.rs ├── scan │ └── main.rs └── ble_advertising │ └── main.rs ├── .vscode └── settings.json ├── .cargo └── config ├── riscv32imfc-unknown-none-elf.json ├── Cargo.toml ├── mkbinding.bat ├── nuttx ├── ints.h ├── wifi_manager │ ├── bl_wifi.h │ ├── wifi_mgmr_api.h │ ├── include │ │ ├── wifi_mgmr_ext.h │ │ └── bitset.h │ ├── wifi_mgmr.h │ └── stateMachine.h └── bl_os_adapter │ ├── bl_os_private.h │ ├── bl_os_system.h │ ├── bl_os_log.h │ └── bl_os_adapter.h ├── README.md ├── memory.x └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /rfparams: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/bl602-wifi-rs/main/rfparams -------------------------------------------------------------------------------- /run.bat: -------------------------------------------------------------------------------- 1 | cargo run -Z build-std --target riscv32imfc-unknown-none-elf.json --example %1% 2 | -------------------------------------------------------------------------------- /flash.bat: -------------------------------------------------------------------------------- 1 | blflash flash target\riscv32imfc-unknown-none-elf\debug\examples\simple -p com3 2 | -------------------------------------------------------------------------------- /libs/libbl602_wifi.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/bl602-wifi-rs/main/libs/libbl602_wifi.a -------------------------------------------------------------------------------- /libs/libblecontroller.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/bl602-wifi-rs/main/libs/libblecontroller.a -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | cargo build -Z build-std --target riscv32imfc-unknown-none-elf.json --example simple && flash.bat -------------------------------------------------------------------------------- /libs/libbl602_wifi_manage.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bjoernQ/bl602-wifi-rs/main/libs/libbl602_wifi_manage.a -------------------------------------------------------------------------------- /src/binary/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bl_wifi; 2 | pub mod c_types; 3 | pub mod wifi_mgmr; 4 | pub mod wifi_mgmr_api; 5 | -------------------------------------------------------------------------------- /examples/simple/wifi_config.rs: -------------------------------------------------------------------------------- 1 | pub const WIFI_SSID: &str = "YOUR_APS_SSID"; 2 | pub const WIFI_PASSWORD: &str = "YOUR_PSK"; 3 | -------------------------------------------------------------------------------- /examples/dhcp/wifi_config.rs: -------------------------------------------------------------------------------- 1 | pub const WIFI_SSID: &str = "YOUR-AP-SSID"; 2 | pub const WIFI_PASSWORD: &str = "YOUR-AP-PASSWORD"; 3 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![feature(c_variadic)] 3 | pub mod binary; 4 | pub mod ble; 5 | pub mod compat; 6 | pub mod log; 7 | pub mod os_adapter; 8 | #[allow(non_camel_case_types, non_snake_case)] 9 | pub mod preemt; 10 | pub mod timer; 11 | pub mod wifi; 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.cargo.allTargets": false, 3 | "rust-analyzer.checkOnSave.allTargets": true, 4 | "rust-analyzer.checkOnSave.overrideCommand": [ 5 | "cargo", 6 | "check", 7 | "-Z", 8 | "build-std", 9 | "--target", 10 | "riscv32imfc-unknown-none-elf.json", 11 | "--message-format", 12 | "json", 13 | "--examples" 14 | ] 15 | } -------------------------------------------------------------------------------- /.cargo/config: -------------------------------------------------------------------------------- 1 | [target.riscv32imfc-unknown-none-elf] 2 | rustflags = [ 3 | "-C", "link-arg=-Tmemory.x", 4 | # "-C", "link-arg=-Tlink.x", 5 | "-C", "link-arg=-Thal_defaults.x", 6 | 7 | "-C", "link-arg=-L", 8 | "-C", "link-arg=./libs/", 9 | "-C", "link-arg=-lbl602_wifi", 10 | "-C", "link-arg=-lbl602_wifi_manage", 11 | "-C", "link-arg=-lblecontroller", 12 | ] 13 | runner = "blash --" 14 | 15 | [build] 16 | target = "riscv32imfc-unknown-none-elf" 17 | -------------------------------------------------------------------------------- /src/binary/c_types.rs: -------------------------------------------------------------------------------- 1 | #![allow( 2 | non_camel_case_types, 3 | non_snake_case, 4 | non_upper_case_globals, 5 | dead_code 6 | )] 7 | 8 | pub type c_uint = u32; 9 | pub type c_int = i32; 10 | pub type c_ulonglong = u64; 11 | pub type c_longlong = i64; 12 | pub type c_uchar = u8; 13 | 14 | pub type c_short = i16; 15 | pub type c_ushort = u16; 16 | pub type c_schar = i8; 17 | pub type c_char = u8; 18 | pub type c_long = i32; 19 | pub type c_ulong = u32; 20 | 21 | pub enum c_void {} 22 | -------------------------------------------------------------------------------- /riscv32imfc-unknown-none-elf.json: -------------------------------------------------------------------------------- 1 | { 2 | "arch": "riscv32", 3 | "cpu": "generic-rv32", 4 | "data-layout": "e-m:e-p:32:32-i64:64-n32-S128", 5 | "eh-frame-header": false, 6 | "emit-debug-gdb-scripts": false, 7 | "executables": true, 8 | "features": "+m,+f,+c", 9 | "linker": "rust-lld", 10 | "linker-flavor": "ld.lld", 11 | "llvm-abiname": "ilp32f", 12 | "llvm-target": "riscv32", 13 | "max-atomic-width": 32, 14 | "panic-strategy": "abort", 15 | "relocation-model": "static", 16 | "target-pointer-width": "32" 17 | } 18 | -------------------------------------------------------------------------------- /src/compat/mod.rs: -------------------------------------------------------------------------------- 1 | use embedded_time::duration::Milliseconds; 2 | 3 | pub mod bl602; 4 | pub mod circbuf; 5 | pub mod common; 6 | pub mod malloc; 7 | pub mod queue; 8 | pub mod work_queue; 9 | 10 | static mut TIME_SOURCE: Option Milliseconds> = None; 11 | 12 | pub fn set_time_source(time_source: fn() -> Milliseconds) { 13 | unsafe { 14 | TIME_SOURCE = Some(time_source); 15 | } 16 | } 17 | 18 | pub fn get_time() -> Milliseconds { 19 | unsafe { 20 | match TIME_SOURCE { 21 | Some(time_source) => time_source(), 22 | None => panic!("TIME_SOURCE is none"), 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ble/controller/mod.rs: -------------------------------------------------------------------------------- 1 | use ble_hci::HciConnector; 2 | 3 | use crate::timer::timestamp; 4 | 5 | use super::{read_hci, send_hci}; 6 | 7 | pub struct BleConnector {} 8 | 9 | impl HciConnector for BleConnector { 10 | fn read(&self) -> Option { 11 | let mut buffer = [0u8]; 12 | let len = read_hci(&mut buffer); 13 | 14 | if len == 0 { 15 | None 16 | } else { 17 | Some(buffer[0]) 18 | } 19 | } 20 | 21 | fn write(&self, data: u8) { 22 | send_hci(&[data]); 23 | } 24 | 25 | fn millis(&self) -> u64 { 26 | timestamp().millis as u64 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bl602wifi" 3 | version = "0.1.0" 4 | authors = ["bjoern "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | riscv-rt = "0.8.0" 9 | bl602-hal = { git = " https://github.com/sipeed/bl602-hal", rev = "dfc9946e79ea4dac18be11efce11d0592a8517fb" } 10 | #panic-halt = "0.2.0" 11 | riscv = "0.7.0" 12 | embedded-time = "0.12.0" 13 | nb = "1.0.0" 14 | smoltcp = { version = "0.7.3", default-features=false, features = ["proto-igmp", "proto-ipv4", "socket-tcp", "socket-icmp", "socket-udp", "ethernet", "proto-dhcpv4", "socket-raw"] } 15 | #ble-hci = { path = "../ble-hci" } 16 | ble-hci = { git = "https://github.com/bjoernQ/ble-hci" } 17 | 18 | [profile.release] 19 | debug = true 20 | 21 | [patch.crates-io] 22 | riscv-rt = { git = "https://github.com/bjoernQ/riscv-rt", branch = "support-ilp32f" } 23 | -------------------------------------------------------------------------------- /mkbinding.bat: -------------------------------------------------------------------------------- 1 | REM Problem: pub type WIFI_MGMR_CONNECTION_STATUS = crate::c_types::c_int; should be a u8 2 | REM To match what the real representation is 3 | REM There are some options but none seem to fit? 4 | REM Maybe just do some regex? 5 | REM 6 | 7 | bindgen --no-derive-debug --raw-line "#![allow(non_camel_case_types,non_snake_case,non_upper_case_globals,dead_code)]" --use-core --ctypes-prefix "crate::binary::c_types" --no-layout-tests nuttx\wifi_manager\bl_wifi.h >src\binary\bl_wifi.rs 8 | bindgen --no-derive-debug --raw-line "#![allow(non_camel_case_types,non_snake_case,non_upper_case_globals,dead_code)]" --use-core --ctypes-prefix "crate::binary::c_types" --no-layout-tests nuttx\wifi_manager\wifi_mgmr.h >src\binary\wifi_mgmr.rs -- -I./nuttx/ 9 | bindgen --no-derive-debug --raw-line "#![allow(non_camel_case_types,non_snake_case,non_upper_case_globals,dead_code)]" --use-core --ctypes-prefix "crate::binary::c_types" --no-layout-tests nuttx\wifi_manager\wifi_mgmr_api.h >src\binary\wifi_mgmr_api.rs -- -I./nuttx/ 10 | -------------------------------------------------------------------------------- /nuttx/ints.h: -------------------------------------------------------------------------------- 1 | typedef signed char int8_t; 2 | typedef short int int16_t; 3 | typedef int int32_t; 4 | typedef long long int int64_t; 5 | 6 | typedef unsigned char uint8_t; 7 | typedef unsigned short int uint16_t; 8 | typedef unsigned int uint32_t; 9 | typedef unsigned long long int uint64_t; 10 | 11 | typedef int int_fast16_t; 12 | typedef int int_fast32_t; 13 | 14 | typedef unsigned int uint_fast16_t; 15 | typedef unsigned int uint_fast32_t; 16 | 17 | //typedef int intptr_t; 18 | //typedef unsigned int uintptr_t; 19 | 20 | #define __INT64_C(c) c ## LL 21 | #define __UINT64_C(c) c ## ULL 22 | 23 | #define __PRI64_RANK "ll" 24 | #define __PRIFAST_RANK "" 25 | #define __PRIPTR_RANK "" 26 | typedef int8_t int_least8_t; 27 | typedef int16_t int_least16_t; 28 | typedef int32_t int_least32_t; 29 | typedef int64_t int_least64_t; 30 | 31 | typedef uint8_t uint_least8_t; 32 | typedef uint16_t uint_least16_t; 33 | typedef uint32_t uint_least32_t; 34 | typedef uint64_t uint_least64_t; 35 | 36 | typedef int8_t int_fast8_t; 37 | typedef int64_t int_fast64_t; 38 | 39 | typedef uint8_t uint_fast8_t; 40 | typedef uint64_t uint_fast64_t; 41 | 42 | typedef int64_t intmax_t; 43 | typedef uint64_t uintmax_t; 44 | -------------------------------------------------------------------------------- /src/compat/queue.rs: -------------------------------------------------------------------------------- 1 | const QUEUE_SIZE: usize = 10; 2 | 3 | pub struct SimpleQueue { 4 | data: [Option; QUEUE_SIZE], 5 | read_index: usize, 6 | write_index: usize, 7 | } 8 | 9 | impl SimpleQueue { 10 | pub const fn new() -> SimpleQueue { 11 | SimpleQueue { 12 | data: [None, None, None, None, None, None, None, None, None, None], 13 | read_index: 0, 14 | write_index: 0, 15 | } 16 | } 17 | 18 | pub fn enqueue(&mut self, e: T) -> bool { 19 | self.data[self.write_index] = Some(e); 20 | 21 | self.write_index += 1; 22 | self.write_index %= QUEUE_SIZE; 23 | 24 | if self.write_index == self.read_index { 25 | return false; 26 | } 27 | 28 | true 29 | } 30 | 31 | pub fn dequeue(&mut self) -> Option { 32 | if self.write_index == self.read_index { 33 | None 34 | } else { 35 | let result = self.data[self.read_index].take(); 36 | self.read_index += 1; 37 | self.read_index %= QUEUE_SIZE; 38 | result 39 | } 40 | } 41 | 42 | pub fn is_empty(&self) -> bool { 43 | self.read_index == self.write_index 44 | } 45 | 46 | pub fn is_full(&self) -> bool { 47 | let mut next_write = self.read_index + 1; 48 | next_write %= QUEUE_SIZE; 49 | 50 | next_write == self.read_index 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /nuttx/wifi_manager/bl_wifi.h: -------------------------------------------------------------------------------- 1 | #ifndef __BL_WIFI_H__ 2 | #define __BL_WIFI_H__ 3 | #include 4 | 5 | typedef struct bl_wifi_ap_info { 6 | uint8_t ssid[33]; 7 | uint8_t psk[65]; 8 | uint8_t chan; 9 | } bl_wifi_ap_info_t; 10 | 11 | typedef struct _bl_wifi_env { 12 | uint8_t sta_mac_addr_board[6]; 13 | uint8_t sta_mac_addr_usr[6]; 14 | uint8_t ap_mac_addr_board[6]; 15 | uint8_t ap_mac_addr_usr[6]; 16 | uint8_t country_code; 17 | 18 | bl_wifi_ap_info_t ap_info; 19 | uint8_t ap_info_en; 20 | 21 | bl_wifi_ap_info_t sta_info; 22 | uint8_t sta_info_en; 23 | } bl_wifi_env_t; 24 | 25 | struct net_device 26 | { 27 | struct bl_hw *bl_hw; 28 | }; 29 | 30 | int bl_wifi_enable_irq(void); 31 | int bl_wifi_clock_enable(void); 32 | int bl_wifi_sta_mac_addr_set(uint8_t mac[6]); 33 | int bl_wifi_ap_mac_addr_set(uint8_t mac[6]); 34 | int bl_wifi_ap_mac_addr_get(uint8_t mac[6]); 35 | int bl_wifi_mac_addr_set(uint8_t mac[6]); 36 | int bl_wifi_country_code_set(uint8_t country_code); 37 | int bl_wifi_ap_info_set(uint8_t* ssid, uint8_t ssid_len, 38 | uint8_t* psk, uint8_t psk_len, 39 | uint8_t chan); 40 | int bl_wifi_mac_addr_get(uint8_t mac[6]); 41 | int bl_wifi_ap_info_get(bl_wifi_ap_info_t* ap_info); 42 | int bl_wifi_sta_info_set(uint8_t* ssid, uint8_t ssid_len, uint8_t* psk, uint8_t psk_len, int autoconnect); 43 | int bl_wifi_sta_info_get(bl_wifi_ap_info_t* sta_info); 44 | #endif 45 | -------------------------------------------------------------------------------- /src/log/mod.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::Write; 2 | 3 | pub const LOG: bool = false; 4 | 5 | pub static mut WRITER: Option &'static mut dyn Write> = None; 6 | 7 | pub fn set_writer(writer: fn() -> &'static mut dyn Write) { 8 | unsafe { 9 | WRITER.replace(writer); 10 | } 11 | } 12 | 13 | #[macro_export] 14 | macro_rules! log { 15 | ($($arg:tt)*) => { 16 | if $crate::log::LOG { 17 | #[allow(unused_unsafe)] 18 | unsafe { 19 | if let Some(writer) = $crate::log::WRITER { 20 | riscv::interrupt::free(|_|{ 21 | let writer = writer(); 22 | write!(writer, $($arg)*).ok(); 23 | write!(writer, "\r\n").ok(); 24 | }); 25 | } 26 | }; 27 | } 28 | }; 29 | } 30 | 31 | #[macro_export] 32 | macro_rules! println { 33 | ($($arg:tt)*) => { 34 | #[allow(unused_unsafe)] 35 | unsafe { 36 | if let Some(writer) = $crate::log::WRITER { 37 | let writer = writer(); 38 | write!(writer, $($arg)*).ok(); 39 | write!(writer, "\r\n").ok(); 40 | } 41 | } 42 | }; 43 | } 44 | 45 | #[macro_export] 46 | macro_rules! print { 47 | ($($arg:tt)*) => { 48 | #[allow(unused_unsafe)] 49 | unsafe { 50 | if let Some(writer) = $crate::log::WRITER { 51 | let writer = writer(); 52 | write!(writer, $($arg)*).ok(); 53 | } 54 | } 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /nuttx/bl_os_adapter/bl_os_private.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * arch/risc-v/src/bl602/bl_os_private.h 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. The 7 | * ASF licenses this file to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance with the 9 | * License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 16 | * License for the specific language governing permissions and limitations 17 | * under the License. 18 | * 19 | ****************************************************************************/ 20 | 21 | #ifndef _BL_OS_PRIVATE_H_ 22 | #define _BL_OS_PRIVATE_H_ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /**************************************************************************** 33 | * Private Types 34 | ****************************************************************************/ 35 | 36 | #ifdef __cplusplus 37 | } 38 | #endif 39 | 40 | #endif /* _BL_OS_PRIVATE_H_ */ -------------------------------------------------------------------------------- /src/timer.rs: -------------------------------------------------------------------------------- 1 | use core::mem::MaybeUninit; 2 | 3 | use bl602_hal as hal; 4 | use bl602_hal::timer::ClockSource; 5 | use embedded_time::duration::Milliseconds; 6 | use hal::interrupts::TrapFrame; 7 | use hal::pac::HBN; 8 | use hal::prelude::Extensions; 9 | use hal::rtc; 10 | use hal::timer::{ConfiguredTimerChannel0, TimerChannel0}; 11 | 12 | use crate::compat::set_time_source; 13 | use crate::preemt::{task_create, task_switch}; 14 | use crate::wifi::{wifi_worker_task1, wifi_worker_task2}; 15 | 16 | static mut CH0: MaybeUninit = MaybeUninit::uninit(); 17 | static mut RTC: MaybeUninit = MaybeUninit::uninit(); 18 | 19 | pub fn wifi_timer_init(channel0: TimerChannel0, hbn: HBN) { 20 | unsafe { 21 | *(RTC.as_mut_ptr()) = rtc::Rtc::new(hbn); 22 | } 23 | 24 | let ch0 = channel0.set_clock_source(ClockSource::Clock1Khz, 1_000u32.Hz()); 25 | ch0.enable_match0_interrupt(); 26 | ch0.set_preload_value(Milliseconds::new(0)); 27 | ch0.set_preload(hal::timer::Preload::PreloadMatchComparator0); 28 | ch0.set_match0(Milliseconds::new(1u32)); 29 | 30 | hal::interrupts::enable_interrupt(hal::interrupts::Interrupt::TimerCh0); 31 | unsafe { 32 | *(CH0.as_mut_ptr()) = ch0; 33 | } 34 | 35 | set_time_source(get_time); 36 | 37 | task_create(wifi_worker_task1); 38 | task_create(wifi_worker_task2); 39 | 40 | get_ch0().enable(); // start timer for tasks 41 | 42 | unsafe { 43 | riscv::interrupt::enable(); 44 | } 45 | } 46 | 47 | pub fn timestamp() -> smoltcp::time::Instant { 48 | smoltcp::time::Instant::from_millis(get_time().0) 49 | } 50 | 51 | #[allow(non_snake_case)] 52 | #[no_mangle] 53 | fn TimerCh0(trap_frame: &mut TrapFrame) { 54 | get_ch0().clear_match0_interrupt(); 55 | task_switch(trap_frame); 56 | } 57 | 58 | fn get_ch0() -> &'static mut ConfiguredTimerChannel0 { 59 | unsafe { &mut *CH0.as_mut_ptr() } 60 | } 61 | 62 | fn get_rtc() -> &'static mut rtc::Rtc { 63 | unsafe { &mut *RTC.as_mut_ptr() } 64 | } 65 | 66 | fn get_time() -> Milliseconds { 67 | Milliseconds(get_rtc().get_millis() as u32) 68 | } 69 | -------------------------------------------------------------------------------- /nuttx/bl_os_adapter/bl_os_system.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * arch/risc-v/src/bl602/bl_os_adapter/bl_os_system.h 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. The 7 | * ASF licenses this file to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance with the 9 | * License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 16 | * License for the specific language governing permissions and limitations 17 | * under the License. 18 | * 19 | ****************************************************************************/ 20 | 21 | #ifndef _BL_OS_SYSTEM_H_ 22 | #define _BL_OS_SYSTEM_H_ 23 | 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /**************************************************************************** 31 | * Definition 32 | ****************************************************************************/ 33 | 34 | #undef assert 35 | #define assert(f) \ 36 | do { \ 37 | if (!(f)) { \ 38 | g_bl_ops_funcs._assert(__FILE__, __LINE__, __FUNCTION__, #f); \ 39 | } \ 40 | } while (0) 41 | 42 | // #define bl_os_printf g_bl_ops_funcs._printf 43 | 44 | /**************************************************************************** 45 | * Private Types 46 | ****************************************************************************/ 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | 52 | #endif /* _BL_OS_SYSTEM_H_ */ -------------------------------------------------------------------------------- /src/compat/work_queue.rs: -------------------------------------------------------------------------------- 1 | use crate::log; 2 | 3 | use super::queue::SimpleQueue; 4 | 5 | #[repr(C)] 6 | pub struct dq_entry_s { 7 | flink: *mut u8, 8 | blink: *mut u8, 9 | } 10 | 11 | #[repr(C)] 12 | pub struct work_s { 13 | dq: dq_entry_s, /* Implements a doubly linked list */ 14 | worker: *const u8, /* Work callback */ 15 | arg: *const u8, /* Callback argument */ 16 | qtime: i64, /* Time work queued */ 17 | delay: i64, /* Delay until work performed */ 18 | } 19 | 20 | static mut WORKER_HIGH: SimpleQueue = SimpleQueue::new(); 21 | static mut WORKER_LOW: SimpleQueue = SimpleQueue::new(); 22 | 23 | #[no_mangle] 24 | pub unsafe extern "C" fn work_queue( 25 | qid: i32, 26 | _work: *mut work_s, 27 | worker: extern "C" fn(), 28 | arg: *mut u8, 29 | delay: i32, 30 | ) -> i32 { 31 | log!("work_queue qid={} arg={:p} delay={}", qid, arg, delay); 32 | 33 | if qid == 0 { 34 | riscv::interrupt::free(|_| { 35 | WORKER_HIGH.enqueue(worker); 36 | }); 37 | } else { 38 | riscv::interrupt::free(|_| { 39 | WORKER_LOW.enqueue(worker); 40 | }); 41 | } 42 | 43 | 0 44 | } 45 | 46 | pub fn do_work(qid: i32) { 47 | unsafe { 48 | let mut todo: [Option; 10] = [None; 10]; 49 | 50 | riscv::interrupt::free(|_| { 51 | todo.iter_mut().for_each(|e| { 52 | let work = if qid == 0 { 53 | WORKER_HIGH.dequeue() 54 | } else { 55 | WORKER_LOW.dequeue() 56 | }; 57 | match work { 58 | Some(worker) => { 59 | e.replace(worker); 60 | } 61 | None => {} 62 | } 63 | }); 64 | }); 65 | 66 | for worker in todo.iter() { 67 | match worker { 68 | core::option::Option::Some(f) => { 69 | log!("before worker"); 70 | 71 | f(); 72 | 73 | log!("after worker"); 74 | } 75 | core::option::Option::None => {} 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BL602 Wifi Rust 2 | 3 | This is work in progress and currently more a proof of concept. 4 | The code is awfully hacked together - just enough to make it work. However it seems to work so far for me. 5 | 6 | It uses the NuttX wifi blob from https://github.com/bouffalolab/bl_blob 7 | 8 | ## Status 9 | 10 | |What|Status| 11 | |---|---| 12 | |Wifi Connect to Access Point|Works| 13 | |Wifi Scan|Works| 14 | |Wifi Start Access Point|Doesn't work| 15 | |Wifi Automatic Reconnect|Not implemented yet| 16 | |BLE|HCI Communication works and there is a minimal BLE stack| 17 | 18 | ## Examples 19 | 20 | See the `examples` folder. 21 | 22 | ### Example: _simple_ 23 | 24 | This connects to an access point and provides a minimal TCP server on port 4321. 25 | You can ping the BL602 and telnet to port 4321. 26 | 27 | Sometimes it fails to connect (there is no retry currently). 28 | 29 | In `examples/simple/wifi_config.rs` change the SSID and PSK for your access point. 30 | 31 | Maybe you need to change the IP address (currently 192.168.2.191) and the IP of the default gateway (192.168.2.1) in `examples/simple/main.rs`. 32 | 33 | Compile with `cargo build -Z build-std --target riscv32imfc-unknown-none-elf.json --example simple` and flash the resulting binary. 34 | 35 | ### Example: _scan_ 36 | 37 | This scans for wifi networks. 38 | 39 | ### Example: _dhcp_ 40 | 41 | Similar to _simple_ but uses DHCP - so no need to configure an IP address or gateway. 42 | 43 | ### Example: _ble_advertising_ 44 | 45 | This starts BLE advertising. It should show up as _BL-602 BLE_ when scanning for Bluetooth devices. 46 | It's possible to connect to it and discover two services. One is read and writeable and one is just writeable. Read and write should also work. 47 | 48 | ## Implementation Notes 49 | 50 | This needs some modifications to the following crates (done in my forks referenced in `Cargo.toml`) 51 | - _riscv-rt_ - needs support for ILP32F and initialization of the FPU 52 | 53 | Also it needs a very special linker script. 54 | 55 | It uses one of the timers which can't be used for other things. 56 | 57 | You'll need nightly Rust. (I use `rustc 1.57.0-nightly (9bb77da74 2021-09-13)` currently) 58 | 59 | ## Things to change / improve 60 | 61 | - [ ] especially the code in `compat` can be improved 62 | - [ ] make it more stable 63 | - [ ] use a queue for tx for improved performance 64 | - [ ] implement more BLE stack functionality 65 | 66 | and many more ... 67 | -------------------------------------------------------------------------------- /nuttx/wifi_manager/wifi_mgmr_api.h: -------------------------------------------------------------------------------- 1 | #ifndef __WIFI_MGMR_API_H__ 2 | #define __WIFI_MGMR_API_H__ 3 | #include 4 | #include "wifi_manager/wifi_mgmr.h" 5 | /** 6 | **************************************************************************************** 7 | * 8 | * @file wifi_mgmr_api.h 9 | * Copyright (C) Bouffalo Lab 2016-2018 10 | * 11 | **************************************************************************************** 12 | */ 13 | 14 | typedef struct 15 | { 16 | uint8_t wep40 : 1; 17 | uint8_t wep104 : 1; 18 | uint8_t tkip : 1; 19 | uint8_t ccmp : 1; 20 | uint8_t rsvd : 4; 21 | } wifi_mgmr_api_cipher_t; 22 | 23 | int wifi_mgmr_api_common_msg(WIFI_MGMR_EVENT_T ev, void *data1, void *data2); 24 | int wifi_mgmr_api_connect(char *ssid, char *passphr, const ap_connect_adv_t *ext_param); 25 | int wifi_mgmr_api_cfg_req(uint32_t ops, uint32_t task, uint32_t element, uint32_t type, uint32_t length, uint32_t *buf); 26 | int wifi_mgmr_api_ip_got(uint32_t ip, uint32_t mask, uint32_t gw, uint32_t dns1, uint32_t dns2); 27 | int wifi_mgmr_api_ip_update(void); 28 | int wifi_mgmr_api_reconnect(void); 29 | int wifi_mgmr_api_disconnect(void); 30 | int wifi_mgmr_api_rate_config(uint16_t config); 31 | int wifi_mgmr_api_conf_max_sta(uint8_t max_sta_supported); 32 | int wifi_mgmr_api_ifaceup(void); 33 | int wifi_mgmr_api_sniffer_enable(void); 34 | int wifi_mgmr_api_ap_start(char *ssid, char *passwd, int channel, uint8_t hidden_ssid); 35 | int wifi_mgmr_api_ap_stop(void); 36 | int wifi_mgmr_api_idle(void); 37 | int wifi_mgmr_api_channel_set(int channel, int use_40Mhz); 38 | int wifi_mgmr_api_raw_send(uint8_t *pkt, int len); 39 | int wifi_mgmr_api_set_country_code(char *country_code); 40 | 41 | /*section for fw api*/ 42 | int wifi_mgmr_api_fw_disconnect(void); 43 | int wifi_mgmr_api_fw_scan(uint16_t *channels, uint16_t channel_num, const char *ssid); 44 | #define WIFI_MGMR_API_FW_POWERSAVING_MODE_OFF (1) 45 | #define WIFI_MGMR_API_FW_POWERSAVING_MODE_ON (2) 46 | #define WIFI_MGMR_API_FW_POWERSAVING_MODE_DYNAMIC_ON (3) 47 | int wifi_mgmr_api_fw_powersaving(int mode); 48 | int wifi_mgmr_api_disable_autoreconnect(void); 49 | int wifi_mgmr_api_enable_autoreconnect(void); 50 | int wifi_mgmr_api_denoise_enable(void); 51 | int wifi_mgmr_api_denoise_disable(void); 52 | 53 | /*section for global event*/ 54 | int wifi_mgmr_api_scan_item_beacon(uint8_t channel, int8_t rssi, uint8_t auth, uint8_t mac[], uint8_t ssid[], int len, int8_t ppm_abs, int8_t ppm_rel, uint8_t cipher); 55 | #endif 56 | -------------------------------------------------------------------------------- /nuttx/bl_os_adapter/bl_os_log.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * components/platform/soc/bl602/bl602_wifidrv/bl60x_wifi_driver/include/bl_os_log.h 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. The 7 | * ASF licenses this file to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance with the 9 | * License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 16 | * License for the specific language governing permissions and limitations 17 | * under the License. 18 | * 19 | ****************************************************************************/ 20 | 21 | #ifndef _BL_OS_LOG_H_ 22 | #define _BL_OS_LOG_H_ 23 | 24 | #include 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | /**************************************************************************** 31 | * Definition 32 | ****************************************************************************/ 33 | 34 | typedef enum _bl_os_log_leve 35 | { 36 | LOG_LEVEL_ALL = 0, 37 | LOG_LEVEL_DEBUG, 38 | LOG_LEVEL_INFO, 39 | LOG_LEVEL_WARN, 40 | LOG_LEVEL_ERROR, 41 | LOG_LEVEL_ASSERT, 42 | LOG_LEVEL_NEVER, 43 | } bl_os_log_level_t; 44 | 45 | #define bl_os_log_printf g_bl_ops_funcs._log_write 46 | 47 | #define bl_os_log_debug(M, ...) \ 48 | bl_os_log_printf(LOG_LEVEL_DEBUG, NULL, __FILE__, __LINE__, M, ##__VA_ARGS__); 49 | 50 | #define bl_os_log_info(M, ...) \ 51 | bl_os_log_printf(LOG_LEVEL_INFO, NULL, __FILE__, __LINE__, M, ##__VA_ARGS__); 52 | 53 | #define bl_os_log_warn(M, ...) \ 54 | bl_os_log_printf(LOG_LEVEL_WARN, NULL, __FILE__, __LINE__, M, ##__VA_ARGS__); 55 | 56 | #define bl_os_log_error(M, ...) \ 57 | bl_os_log_printf(LOG_LEVEL_ERROR, NULL, __FILE__, __LINE__, M, ##__VA_ARGS__); 58 | 59 | /**************************************************************************** 60 | * Private Types 61 | ****************************************************************************/ 62 | 63 | #ifdef __cplusplus 64 | } 65 | #endif 66 | 67 | #endif /* _BL_OS_LOG_H_ */ -------------------------------------------------------------------------------- /src/compat/malloc.rs: -------------------------------------------------------------------------------- 1 | use crate::log; 2 | 3 | extern "C" { 4 | static _sheap: u8; 5 | } 6 | 7 | #[derive(Debug, Copy, Clone)] 8 | struct Allocation { 9 | address: *const u8, 10 | size: usize, 11 | free: bool, 12 | } 13 | 14 | static mut ALLOCATIONS: [Option; 128] = [None; 128]; 15 | static mut ALLOC_INDEX: isize = -1; 16 | 17 | #[no_mangle] 18 | pub unsafe extern "C" fn malloc(size: u32) -> *const u8 { 19 | log!("malloc called {}", size); 20 | 21 | let mut candidate_addr = &_sheap as *const u8; 22 | 23 | riscv::interrupt::free(|_critical_section| { 24 | let aligned_size = size + if size % 8 != 0 { 8 - size % 8 } else { 0 }; 25 | 26 | // try to find a previously freed block 27 | let mut reused = 0 as *const u8; 28 | for allocation in ALLOCATIONS.iter_mut() { 29 | match allocation { 30 | Some(ref mut allocation) => { 31 | if allocation.free && aligned_size <= allocation.size as u32 { 32 | allocation.free = false; 33 | reused = allocation.address; 34 | break; 35 | } 36 | } 37 | None => {} 38 | } 39 | } 40 | 41 | if reused.is_null() { 42 | // otherwise allocate after the highest allocated block 43 | if ALLOC_INDEX != -1 { 44 | candidate_addr = ALLOCATIONS[ALLOC_INDEX as usize] 45 | .unwrap() 46 | .address 47 | .offset(ALLOCATIONS[ALLOC_INDEX as usize].unwrap().size as isize); 48 | } 49 | 50 | ALLOC_INDEX += 1; 51 | 52 | ALLOCATIONS[ALLOC_INDEX as usize] = Some(Allocation { 53 | address: candidate_addr, 54 | size: aligned_size as usize, 55 | free: false, 56 | }); 57 | log!("new allocation idx = {}", ALLOC_INDEX); 58 | } else { 59 | log!("new allocation at reused block"); 60 | candidate_addr = reused; 61 | } 62 | 63 | log!("malloc at {:p}", candidate_addr); 64 | }); 65 | 66 | return candidate_addr; 67 | } 68 | 69 | #[no_mangle] 70 | pub unsafe extern "C" fn free(ptr: *const u8) { 71 | log!("free called {:p}", ptr); 72 | 73 | if ptr.is_null() { 74 | return; 75 | } 76 | 77 | riscv::interrupt::free(|_critical_section| { 78 | let alloced_idx = ALLOCATIONS 79 | .iter() 80 | .enumerate() 81 | .find(|(_, allocation)| allocation.is_some() && allocation.unwrap().address == ptr); 82 | 83 | if alloced_idx.is_some() { 84 | let alloced_idx = alloced_idx.unwrap().0; 85 | log!("free idx {}", alloced_idx); 86 | 87 | if alloced_idx as isize == ALLOC_INDEX { 88 | ALLOCATIONS[alloced_idx] = None; 89 | ALLOC_INDEX -= 1; 90 | } else { 91 | ALLOCATIONS[alloced_idx] = ALLOCATIONS[alloced_idx as usize] 92 | .take() 93 | .and_then(|v| Some(Allocation { free: true, ..v })); 94 | } 95 | } else { 96 | panic!("freeing a memory area we don't know of"); 97 | } 98 | }); 99 | } 100 | -------------------------------------------------------------------------------- /examples/scan/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(c_variadic)] 4 | 5 | #[allow(non_camel_case_types, non_snake_case)] 6 | use core::{fmt::Write, mem::MaybeUninit}; 7 | 8 | use bl602_hal as hal; 9 | use core::panic::PanicInfo; 10 | use hal::{ 11 | clock::{Strict, SysclkFreq, UART_PLL_FREQ}, 12 | gpio::{Pin16, Pin7, Uart, Uart0Rx, Uart0Tx, UartMux0, UartMux7}, 13 | pac::{self, UART}, 14 | prelude::*, 15 | serial::*, 16 | }; 17 | 18 | use bl602_hal::timer::TimerExt; 19 | 20 | static mut GLOBAL_SERIAL: MaybeUninit< 21 | bl602_hal::serial::Serial< 22 | UART, 23 | ( 24 | (Pin16, UartMux0), 25 | (Pin7, UartMux7), 26 | ), 27 | >, 28 | > = MaybeUninit::uninit(); 29 | 30 | use bl602wifi::println; 31 | use bl602wifi::timer::wifi_timer_init; 32 | use bl602wifi::wifi::*; 33 | use bl602wifi::{compat::common::StrBuf, log::set_writer}; 34 | 35 | #[riscv_rt::entry] 36 | fn main() -> ! { 37 | let dp = pac::Peripherals::take().unwrap(); 38 | let mut parts = dp.GLB.split(); 39 | 40 | let clocks = Strict::new() 41 | .use_pll(40_000_000u32.Hz()) 42 | .sys_clk(SysclkFreq::Pll160Mhz) 43 | .uart_clk(UART_PLL_FREQ.Hz()) 44 | .freeze(&mut parts.clk_cfg); 45 | 46 | // Set up uart output. Since this microcontroller has a pin matrix, 47 | // we need to set up both the pins and the muxs 48 | let pin16 = parts.pin16.into_uart_sig0(); 49 | let pin7 = parts.pin7.into_uart_sig7(); 50 | let mux0 = parts.uart_mux0.into_uart0_tx(); 51 | let mux7 = parts.uart_mux7.into_uart0_rx(); 52 | 53 | // Configure our UART to 115200 Baud, and use the pins we configured above 54 | let serial = Serial::uart0( 55 | dp.UART, 56 | Config::default().baudrate(115_200.Bd()), 57 | ((pin16, mux0), (pin7, mux7)), 58 | clocks, 59 | ); 60 | unsafe { 61 | *(GLOBAL_SERIAL.as_mut_ptr()) = serial; 62 | } 63 | 64 | set_writer(get_serial); 65 | 66 | println!("init"); 67 | 68 | wifi_pre_init(); 69 | 70 | let timers = dp.TIMER.split(); 71 | wifi_timer_init(timers.channel0, dp.HBN); 72 | 73 | wifi_init(); 74 | 75 | for _ in 0..150000 {} 76 | 77 | let scan_result = wifi_scan(); 78 | 79 | match scan_result { 80 | Ok(scan_result) => { 81 | for item in &scan_result { 82 | match item { 83 | Some(item) => { 84 | let ssid = unsafe { StrBuf::from(&item.ssid as *const u8) }; 85 | println!("SSID: {}", ssid.as_str_ref()); 86 | println!("BSSID: {:x?}", item.bssid); 87 | println!("CHANNEL: {}", item.channel); 88 | println!("RSSI: {}", item.rssi); 89 | println!(""); 90 | } 91 | None => (), 92 | } 93 | } 94 | } 95 | Err(_) => { 96 | println!("Some error occured") 97 | } 98 | } 99 | 100 | loop {} 101 | } 102 | 103 | #[export_name = "ExceptionHandler"] 104 | fn custom_exception_handler(_trap_frame: &riscv_rt::TrapFrame) -> ! { 105 | /* 106 | 0 0 Instruction address misaligned 107 | 0 1 Instruction access fault 108 | 0 2 Illegal instruction 109 | 0 3 Breakpoint 110 | 0 4 Load address misaligned 111 | 0 5 Load access fault 112 | 0 6 Store/AMO address misaligned 113 | 0 7 Store/AMO access fault 114 | 0 8 Environment call from U-mode 115 | 0 9 Environment call from S-mode 116 | 0 10 Reserved 117 | 0 11 Environment call from M-mode 118 | 0 12 Instruction page fault 119 | 0 13 Load page fault 120 | 0 14 Reserved 121 | 0 15 Store/AMO page fault 122 | */ 123 | 124 | let mepc = riscv::register::mepc::read(); 125 | let code = riscv::register::mcause::read().code() & 0xff; 126 | println!("exception code {} at {:x}", code, mepc); 127 | loop {} 128 | } 129 | 130 | fn get_serial() -> &'static mut dyn core::fmt::Write { 131 | unsafe { &mut *GLOBAL_SERIAL.as_mut_ptr() } 132 | } 133 | 134 | #[panic_handler] 135 | fn panic_handler(info: &PanicInfo) -> ! { 136 | let serial = unsafe { &mut *(GLOBAL_SERIAL.as_mut_ptr()) }; 137 | write!(serial, "PANIC! {:?}", info).ok(); 138 | loop {} 139 | } 140 | -------------------------------------------------------------------------------- /src/compat/bl602.rs: -------------------------------------------------------------------------------- 1 | use crate::log; 2 | 3 | pub static mut ATTACHED_IRQ_HANDLER: [Option; 64 + 16] = [None; 64 + 16]; 4 | 5 | #[derive(Clone, Copy)] 6 | pub struct InterruptAttach { 7 | pub isr: extern "C" fn(*const u8, *const u8), 8 | pub arg: *const u8, 9 | } 10 | 11 | pub fn hbn_config_aon_pad_input_and_smt() { 12 | // HBN Config AON pad input and SMT 13 | // see bl602_start.c 14 | unsafe { 15 | const BL602_HBN_BASE: u32 = 0x4000f000; 16 | const BL602_HBN_IRQ_MODE_OFFSET: u32 = 0x000014; 17 | const BL602_HBN_IRQ_MODE: u32 = BL602_HBN_BASE + BL602_HBN_IRQ_MODE_OFFSET; 18 | const HBN_IRQ_MODE_REG_AON_PAD_IE_SMT: u32 = 1 << 8; 19 | 20 | let ptr = BL602_HBN_IRQ_MODE as *mut u32; 21 | let mut regval = ptr.read_volatile(); 22 | regval &= !0; 23 | regval |= HBN_IRQ_MODE_REG_AON_PAD_IE_SMT; 24 | ptr.write_volatile(regval); 25 | } 26 | } 27 | 28 | pub fn bl602_set_em_sel_bl602_glb_em_8kb() { 29 | // see bl602_bringup.c 30 | // Set how much wifi ram is allocated to ble. 31 | unsafe { 32 | const BL602_GLB_EM_8KB: u32 = 0x3 /* 8KB */; 33 | const BL602_GLB_BASE: u32 = 0x40000000; 34 | const BL602_SEAM_MISC_OFFSET: u32 = 0x00007c; 35 | const BL602_SEAM_MISC: u32 = BL602_GLB_BASE + BL602_SEAM_MISC_OFFSET; 36 | const SEAM_MISC_EM_SEL_MASK: u32 = 0x0f; 37 | let ptr = BL602_SEAM_MISC as *mut u32; 38 | let mut regval = ptr.read_volatile(); 39 | regval &= !SEAM_MISC_EM_SEL_MASK; 40 | regval |= BL602_GLB_EM_8KB; 41 | ptr.write_volatile(regval); 42 | } 43 | } 44 | 45 | #[no_mangle] 46 | pub unsafe extern "C" fn bl602_aon_pad_iesmt_cfg(pad_cfg: u8) { 47 | riscv::interrupt::free(|_| { 48 | log!("bl602_aon_pad_iesmt_cfg called {}", pad_cfg); 49 | 50 | const BL602_HBN_BASE: u32 = 0x4000f000; 51 | const BL602_HBN_IRQ_MODE_OFFSET: u32 = 0x000014; 52 | const BL602_HBN_IRQ_MODE: u32 = BL602_HBN_BASE + BL602_HBN_IRQ_MODE_OFFSET; 53 | const HBN_IRQ_MODE_REG_AON_PAD_IE_SMT: u32 = 1 << 8; 54 | 55 | let ptr = BL602_HBN_IRQ_MODE as *mut u32; 56 | let mut regval = ptr.read_volatile(); 57 | regval &= HBN_IRQ_MODE_REG_AON_PAD_IE_SMT; 58 | regval |= (pad_cfg as u32) << 8; 59 | ptr.write_volatile(regval); 60 | }); 61 | } 62 | 63 | #[no_mangle] 64 | pub unsafe extern "C" fn up_enable_irq(irq: i32) { 65 | // Enable the IRQ specified by 'irq' 66 | 67 | log!("up_enable_irq called for irq {}", irq); 68 | 69 | ((0x02800000 + 0x400 + irq - 16) as *mut u8).write_volatile(1); 70 | } 71 | 72 | #[no_mangle] 73 | pub unsafe extern "C" fn irq_attach( 74 | irq: i32, 75 | isr: extern "C" fn(*const u8, *const u8), 76 | arg: *const u8, 77 | ) -> i32 { 78 | // Configure the IRQ subsystem so that IRQ number 'irq' is dispatched to 'isr' 79 | 80 | log!("irq_attach called {} {:p} {:p}", irq, isr, arg); 81 | 82 | ATTACHED_IRQ_HANDLER[(irq - 16) as usize] = Some(InterruptAttach { isr, arg }); 83 | 84 | 0 85 | } 86 | 87 | #[no_mangle] 88 | pub unsafe extern "C" fn up_irq_save() -> u32 { 89 | // this is not what the original function does but seems to be good enough 90 | 91 | log!("up_irq_save"); 92 | 93 | let res = riscv::register::mstatus::read().mie(); 94 | riscv::register::mstatus::clear_mie(); 95 | 96 | if res { 97 | 1 98 | } else { 99 | 0 100 | } 101 | } 102 | 103 | #[no_mangle] 104 | pub unsafe extern "C" fn up_irq_restore(flags: u32) { 105 | // this is not what the original function does but seems to be good enough 106 | log!("up_irq_restore {}", flags); 107 | 108 | if flags == 1 { 109 | riscv::register::mstatus::set_mie(); 110 | } else { 111 | riscv::register::mstatus::clear_mie(); 112 | }; 113 | } 114 | 115 | pub fn dispatch_irq(irq: usize) { 116 | unsafe { 117 | match ATTACHED_IRQ_HANDLER[irq] { 118 | core::option::Option::Some(data) => { 119 | let f = data.isr; 120 | log!("Handling interrupt {} @ {:p} {:p}", irq, f, data.arg); 121 | f(core::ptr::null(), data.arg); 122 | 123 | log!("Handling interrupt done"); 124 | } 125 | core::option::Option::None => { 126 | log!("ooops! unhandled interrupt cause={}", irq); 127 | loop {} 128 | } 129 | } 130 | } 131 | } 132 | 133 | #[allow(non_snake_case)] 134 | #[no_mangle] 135 | fn DefaultHandler() { 136 | let irq = riscv::register::mcause::read().code() & 0xff; 137 | dispatch_irq(irq); 138 | } 139 | -------------------------------------------------------------------------------- /src/binary/bl_wifi.rs: -------------------------------------------------------------------------------- 1 | /* automatically generated by rust-bindgen 0.58.1 */ 2 | 3 | #![allow( 4 | non_camel_case_types, 5 | non_snake_case, 6 | non_upper_case_globals, 7 | dead_code 8 | )] 9 | 10 | pub const _SAL_VERSION: u32 = 20; 11 | pub const __SAL_H_VERSION: u32 = 180000000; 12 | pub const _USE_DECLSPECS_FOR_SAL: u32 = 0; 13 | pub const _USE_ATTRIBUTES_FOR_SAL: u32 = 0; 14 | pub const _CRT_PACKING: u32 = 8; 15 | pub const _HAS_EXCEPTIONS: u32 = 1; 16 | pub const WCHAR_MIN: u32 = 0; 17 | pub const WCHAR_MAX: u32 = 65535; 18 | pub const WINT_MIN: u32 = 0; 19 | pub const WINT_MAX: u32 = 65535; 20 | pub type va_list = *mut crate::binary::c_types::c_char; 21 | extern "C" { 22 | pub fn __va_start(arg1: *mut *mut crate::binary::c_types::c_char, ...); 23 | } 24 | pub type size_t = crate::binary::c_types::c_ulonglong; 25 | pub type __vcrt_bool = bool; 26 | pub type wchar_t = crate::binary::c_types::c_ushort; 27 | extern "C" { 28 | pub fn __security_init_cookie(); 29 | } 30 | extern "C" { 31 | pub fn __security_check_cookie(_StackCookie: usize); 32 | } 33 | extern "C" { 34 | pub fn __report_gsfailure(_StackCookie: usize); 35 | } 36 | extern "C" { 37 | pub static mut __security_cookie: usize; 38 | } 39 | pub type int_least8_t = crate::binary::c_types::c_schar; 40 | pub type int_least16_t = crate::binary::c_types::c_short; 41 | pub type int_least32_t = crate::binary::c_types::c_int; 42 | pub type int_least64_t = crate::binary::c_types::c_longlong; 43 | pub type uint_least8_t = crate::binary::c_types::c_uchar; 44 | pub type uint_least16_t = crate::binary::c_types::c_ushort; 45 | pub type uint_least32_t = crate::binary::c_types::c_uint; 46 | pub type uint_least64_t = crate::binary::c_types::c_ulonglong; 47 | pub type int_fast8_t = crate::binary::c_types::c_schar; 48 | pub type int_fast16_t = crate::binary::c_types::c_int; 49 | pub type int_fast32_t = crate::binary::c_types::c_int; 50 | pub type int_fast64_t = crate::binary::c_types::c_longlong; 51 | pub type uint_fast8_t = crate::binary::c_types::c_uchar; 52 | pub type uint_fast16_t = crate::binary::c_types::c_uint; 53 | pub type uint_fast32_t = crate::binary::c_types::c_uint; 54 | pub type uint_fast64_t = crate::binary::c_types::c_ulonglong; 55 | pub type intmax_t = crate::binary::c_types::c_longlong; 56 | pub type uintmax_t = crate::binary::c_types::c_ulonglong; 57 | #[repr(C)] 58 | #[derive(Copy, Clone)] 59 | pub struct bl_wifi_ap_info { 60 | pub ssid: [u8; 33usize], 61 | pub psk: [u8; 65usize], 62 | pub chan: u8, 63 | } 64 | pub type bl_wifi_ap_info_t = bl_wifi_ap_info; 65 | #[repr(C)] 66 | #[derive(Copy, Clone)] 67 | pub struct _bl_wifi_env { 68 | pub sta_mac_addr_board: [u8; 6usize], 69 | pub sta_mac_addr_usr: [u8; 6usize], 70 | pub ap_mac_addr_board: [u8; 6usize], 71 | pub ap_mac_addr_usr: [u8; 6usize], 72 | pub country_code: u8, 73 | pub ap_info: bl_wifi_ap_info_t, 74 | pub ap_info_en: u8, 75 | pub sta_info: bl_wifi_ap_info_t, 76 | pub sta_info_en: u8, 77 | } 78 | pub type bl_wifi_env_t = _bl_wifi_env; 79 | #[repr(C)] 80 | #[derive(Copy, Clone)] 81 | pub struct net_device { 82 | pub bl_hw: *mut bl_hw, 83 | } 84 | extern "C" { 85 | pub fn bl_wifi_enable_irq() -> crate::binary::c_types::c_int; 86 | } 87 | extern "C" { 88 | pub fn bl_wifi_clock_enable() -> crate::binary::c_types::c_int; 89 | } 90 | extern "C" { 91 | pub fn bl_wifi_sta_mac_addr_set(mac: *mut u8) -> crate::binary::c_types::c_int; 92 | } 93 | extern "C" { 94 | pub fn bl_wifi_ap_mac_addr_set(mac: *mut u8) -> crate::binary::c_types::c_int; 95 | } 96 | extern "C" { 97 | pub fn bl_wifi_ap_mac_addr_get(mac: *mut u8) -> crate::binary::c_types::c_int; 98 | } 99 | extern "C" { 100 | pub fn bl_wifi_mac_addr_set(mac: *mut u8) -> crate::binary::c_types::c_int; 101 | } 102 | extern "C" { 103 | pub fn bl_wifi_country_code_set(country_code: u8) -> crate::binary::c_types::c_int; 104 | } 105 | extern "C" { 106 | pub fn bl_wifi_ap_info_set( 107 | ssid: *mut u8, 108 | ssid_len: u8, 109 | psk: *mut u8, 110 | psk_len: u8, 111 | chan: u8, 112 | ) -> crate::binary::c_types::c_int; 113 | } 114 | extern "C" { 115 | pub fn bl_wifi_mac_addr_get(mac: *mut u8) -> crate::binary::c_types::c_int; 116 | } 117 | extern "C" { 118 | pub fn bl_wifi_ap_info_get(ap_info: *mut bl_wifi_ap_info_t) -> crate::binary::c_types::c_int; 119 | } 120 | extern "C" { 121 | pub fn bl_wifi_sta_info_set( 122 | ssid: *mut u8, 123 | ssid_len: u8, 124 | psk: *mut u8, 125 | psk_len: u8, 126 | autoconnect: crate::binary::c_types::c_int, 127 | ) -> crate::binary::c_types::c_int; 128 | } 129 | extern "C" { 130 | pub fn bl_wifi_sta_info_get(sta_info: *mut bl_wifi_ap_info_t) -> crate::binary::c_types::c_int; 131 | } 132 | #[repr(C)] 133 | #[derive(Copy, Clone)] 134 | pub struct bl_hw { 135 | pub _address: u8, 136 | } 137 | -------------------------------------------------------------------------------- /nuttx/bl_os_adapter/bl_os_adapter.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. The 7 | * ASF licenses this file to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance with the 9 | * License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 16 | * License for the specific language governing permissions and limitations 17 | * under the License. 18 | * 19 | ****************************************************************************/ 20 | 21 | #ifndef _BL_OS_ADAPTER_H_ 22 | #define _BL_OS_ADAPTER_H_ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | /**************************************************************************** 35 | * Definition 36 | ****************************************************************************/ 37 | #define BL_OS_TRUE (1) 38 | #define BL_OS_FALSE (0) 39 | 40 | #define BL_OS_WAITING_FOREVER (0xffffffffUL) 41 | #define BL_OS_NO_WAITING (0x0UL) 42 | 43 | #define BL_OS_ADAPTER_VERSION ((int)0x00000001) 44 | 45 | /**************************************************************************** 46 | * Private Types 47 | ****************************************************************************/ 48 | 49 | struct bl_ops_funcs 50 | { 51 | int _version; 52 | void (*_printf)(const char *fmt, ...); 53 | void (*_assert)(const char *file, 54 | int line, 55 | const char *func, 56 | const char *expr); 57 | int (*_init)(void); 58 | uint32_t (*_enter_critical)(void); 59 | void (*_exit_critical)(uint32_t level); 60 | int (*_msleep)(long ms); 61 | int (*_sleep)(unsigned int seconds); 62 | void *(*_event_group_create)(void); 63 | void (*_event_group_delete)(void *event); 64 | uint32_t (*_event_group_send)(void *event, uint32_t bits); 65 | uint32_t (*_event_group_wait)(void *event, 66 | uint32_t bits_to_wait_for, 67 | int clear_on_exit, 68 | int wait_for_all_bits, 69 | uint32_t block_time_tick); 70 | int (*_event_register)(int type, void *cb, void *arg); 71 | int (*_event_notify)(int evt, int val); 72 | int (*_task_create)(const char *name, 73 | void *entry, 74 | uint32_t stack_depth, 75 | void *param, 76 | uint32_t prio, 77 | void *task_handle); 78 | void (*_task_delete)(void *task_handle); 79 | void *(*_task_get_current_task)(void); 80 | void *(*_task_notify_create)(void); 81 | void (*_task_notify)(void *task_handle); 82 | void (*_task_wait)(void *task_handle, uint32_t tick); 83 | void (*_lock_gaint)(void); 84 | void (*_unlock_gaint)(void); 85 | void (*_irq_attach)(int32_t n, void *f, void *arg); 86 | void (*_irq_enable)(int32_t n); 87 | void (*_irq_disable)(int32_t n); 88 | void *(*_workqueue_create)(void); 89 | int (*_workqueue_submit_hp)(void *work, void *woker, void *argv, long tick); 90 | int (*_workqueue_submit_lp)(void *work, void *woker, void *argv, long tick); 91 | void *(*_timer_create)(void *func, void *argv); 92 | int (*_timer_delete)(void *timerid, uint32_t tick); 93 | int (*_timer_start_once)(void *timerid, long t_sec, long t_nsec); 94 | int (*_timer_start_periodic)(void *timerid, long t_sec, long t_nsec); 95 | void *(*_sem_create)(uint32_t init); 96 | void (*_sem_delete)(void *semphr); 97 | int32_t (*_sem_take)(void *semphr, uint32_t tick); 98 | int32_t (*_sem_give)(void *semphr); 99 | void *(*_mutex_create)(void); 100 | void (*_mutex_delete)(void *mutex); 101 | int32_t (*_mutex_lock)(void *mutex); 102 | int32_t (*_mutex_unlock)(void *mutex); 103 | void *(*_queue_create)(uint32_t queue_len, uint32_t item_size); 104 | void (*_queue_delete)(void *queue); 105 | int (*_queue_send_wait)(void *queue, 106 | void *item, 107 | uint32_t len, 108 | uint32_t ticks, 109 | int prio); 110 | int (*_queue_send)(void *queue, void *item, uint32_t len); 111 | int (*_queue_recv)(void *queue, void *item, uint32_t len, uint32_t tick); 112 | void *(*_malloc)(unsigned int size); 113 | void (*_free)(void *p); 114 | void *(*_zalloc)(unsigned int size); 115 | uint64_t (*_get_time_ms)(void); 116 | uint32_t (*_get_tick)(void); 117 | void (*_log_write)(uint32_t level, 118 | const char *tag, 119 | const char *file, 120 | int line, 121 | const char *format, 122 | ...); 123 | }; 124 | 125 | typedef struct bl_ops_funcs bl_ops_funcs_t; 126 | 127 | extern bl_ops_funcs_t g_bl_ops_funcs; 128 | 129 | #ifdef __cplusplus 130 | } 131 | #endif 132 | 133 | #endif /* _BL_OS_ADAPTER_H_ */ 134 | -------------------------------------------------------------------------------- /examples/ble_advertising/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(c_variadic)] 4 | 5 | #[allow(non_camel_case_types, non_snake_case)] 6 | use core::{fmt::Write, mem::MaybeUninit}; 7 | 8 | use bl602_hal as hal; 9 | use ble_hci::{ 10 | ad_structure::{ 11 | create_advertising_data, AdStructure, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE, 12 | }, 13 | att::Uuid, 14 | attribute_server::{AttributeServer, Service, ATT_READABLE, ATT_WRITEABLE}, 15 | Ble, Data, 16 | }; 17 | use core::panic::PanicInfo; 18 | use hal::{ 19 | clock::{Strict, SysclkFreq, UART_PLL_FREQ}, 20 | gpio::{Pin16, Pin7, Uart, Uart0Rx, Uart0Tx, UartMux0, UartMux7}, 21 | pac::{self, UART}, 22 | prelude::*, 23 | serial::*, 24 | }; 25 | 26 | use bl602_hal::timer::TimerExt; 27 | 28 | static mut GLOBAL_SERIAL: MaybeUninit< 29 | bl602_hal::serial::Serial< 30 | UART, 31 | ( 32 | (Pin16, UartMux0), 33 | (Pin7, UartMux7), 34 | ), 35 | >, 36 | > = MaybeUninit::uninit(); 37 | 38 | use bl602wifi::log::set_writer; 39 | use bl602wifi::wifi::*; 40 | use bl602wifi::{ble::ble_init, println}; 41 | use bl602wifi::{ble::controller::BleConnector, timer::wifi_timer_init}; 42 | 43 | #[riscv_rt::entry] 44 | fn main() -> ! { 45 | let dp = pac::Peripherals::take().unwrap(); 46 | let mut parts = dp.GLB.split(); 47 | 48 | let clocks = Strict::new() 49 | .use_pll(40_000_000u32.Hz()) 50 | .sys_clk(SysclkFreq::Pll160Mhz) 51 | .uart_clk(UART_PLL_FREQ.Hz()) 52 | .freeze(&mut parts.clk_cfg); 53 | 54 | // Set up uart output. Since this microcontroller has a pin matrix, 55 | // we need to set up both the pins and the muxs 56 | let pin16 = parts.pin16.into_uart_sig0(); 57 | let pin7 = parts.pin7.into_uart_sig7(); 58 | let mux0 = parts.uart_mux0.into_uart0_tx(); 59 | let mux7 = parts.uart_mux7.into_uart0_rx(); 60 | 61 | // Configure our UART to 115200 Baud, and use the pins we configured above 62 | let serial = Serial::uart0( 63 | dp.UART, 64 | Config::default().baudrate(115_200.Bd()), 65 | ((pin16, mux0), (pin7, mux7)), 66 | clocks, 67 | ); 68 | unsafe { 69 | *(GLOBAL_SERIAL.as_mut_ptr()) = serial; 70 | } 71 | 72 | set_writer(get_serial); 73 | 74 | println!("init"); 75 | 76 | wifi_pre_init(); 77 | 78 | let timers = dp.TIMER.split(); 79 | wifi_timer_init(timers.channel0, dp.HBN); 80 | 81 | wifi_init(); 82 | 83 | for _ in 0..20000 {} 84 | 85 | ble_init(); 86 | 87 | let connector = BleConnector {}; 88 | let mut ble = Ble::new(&connector); 89 | 90 | println!("{:?}", ble.init()); 91 | println!("{:?}", ble.cmd_set_le_advertising_parameters()); 92 | println!( 93 | "{:?}", 94 | ble.cmd_set_le_advertising_data(create_advertising_data(&[ 95 | AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED), 96 | AdStructure::ServiceUuids16(&[Uuid::Uuid16(0x1809)]), 97 | AdStructure::CompleteLocalName("BL602 BLE"), 98 | ])) 99 | ); 100 | println!("{:?}", ble.cmd_set_le_advertise_enable(true)); 101 | 102 | println!("started advertising"); 103 | 104 | let mut rf = || Data::new(&[b'H', b'e', b'l', b'l', b'o']); 105 | let mut wf = |data: Data| { 106 | println!("{:x?}", data.to_slice()); 107 | }; 108 | 109 | let srv1 = Service::new( 110 | Uuid::Uuid128([ 111 | 0xC9, 0x15, 0x15, 0x96, 0x54, 0x56, 0x64, 0xB3, 0x38, 0x45, 0x26, 0x5D, 0xF1, 0x62, 112 | 0x6A, 0xA8, 113 | ]), 114 | ATT_READABLE | ATT_WRITEABLE, 115 | &mut rf, 116 | &mut wf, 117 | ); 118 | 119 | let mut rf2 = || Data::default(); 120 | let mut wf2 = |_data| {}; 121 | 122 | let srv2 = Service::new( 123 | Uuid::Uuid128([ 124 | 0xC8, 0x15, 0x15, 0x96, 0x54, 0x56, 0x64, 0xB3, 0x38, 0x45, 0x26, 0x5D, 0xF1, 0x62, 125 | 0x6A, 0xA8, 126 | ]), 127 | ATT_WRITEABLE, 128 | &mut rf2, 129 | &mut wf2, 130 | ); 131 | 132 | let services = &mut [srv1, srv2]; 133 | let mut srv = AttributeServer::new(&mut ble, services); 134 | 135 | loop { 136 | match srv.do_work() { 137 | Ok(_) => (), 138 | Err(err) => { 139 | println!("{:?}", err); 140 | } 141 | } 142 | 143 | for _ in 0..10000 {} 144 | } 145 | } 146 | 147 | #[export_name = "ExceptionHandler"] 148 | fn custom_exception_handler(_trap_frame: &riscv_rt::TrapFrame) -> ! { 149 | /* 150 | 0 0 Instruction address misaligned 151 | 0 1 Instruction access fault 152 | 0 2 Illegal instruction 153 | 0 3 Breakpoint 154 | 0 4 Load address misaligned 155 | 0 5 Load access fault 156 | 0 6 Store/AMO address misaligned 157 | 0 7 Store/AMO access fault 158 | 0 8 Environment call from U-mode 159 | 0 9 Environment call from S-mode 160 | 0 10 Reserved 161 | 0 11 Environment call from M-mode 162 | 0 12 Instruction page fault 163 | 0 13 Load page fault 164 | 0 14 Reserved 165 | 0 15 Store/AMO page fault 166 | */ 167 | 168 | let mepc = riscv::register::mepc::read(); 169 | let code = riscv::register::mcause::read().code() & 0xff; 170 | println!("exception code {} at {:x}", code, mepc); 171 | loop {} 172 | } 173 | 174 | fn get_serial() -> &'static mut dyn core::fmt::Write { 175 | unsafe { &mut *GLOBAL_SERIAL.as_mut_ptr() } 176 | } 177 | 178 | #[panic_handler] 179 | fn panic_handler(info: &PanicInfo) -> ! { 180 | let serial = unsafe { &mut *(GLOBAL_SERIAL.as_mut_ptr()) }; 181 | write!(serial, "PANIC! {:?}\r\n", info).ok(); 182 | loop {} 183 | } 184 | -------------------------------------------------------------------------------- /examples/simple/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(c_variadic)] 4 | 5 | #[allow(non_camel_case_types, non_snake_case)] 6 | use core::{fmt::Write, mem::MaybeUninit}; 7 | 8 | use bl602_hal as hal; 9 | use core::panic::PanicInfo; 10 | use hal::{ 11 | clock::{Strict, SysclkFreq, UART_PLL_FREQ}, 12 | gpio::{Pin16, Pin7, Uart, Uart0Rx, Uart0Tx, UartMux0, UartMux7}, 13 | pac::{self, UART}, 14 | prelude::*, 15 | serial::*, 16 | }; 17 | use smoltcp::{ 18 | iface::{NeighborCache, Routes}, 19 | socket::{TcpSocket, TcpSocketBuffer}, 20 | wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address}, 21 | }; 22 | 23 | use bl602_hal::timer::TimerExt; 24 | 25 | static mut GLOBAL_SERIAL: MaybeUninit< 26 | bl602_hal::serial::Serial< 27 | UART, 28 | ( 29 | (Pin16, UartMux0), 30 | (Pin7, UartMux7), 31 | ), 32 | >, 33 | > = MaybeUninit::uninit(); 34 | 35 | use bl602wifi::log::set_writer; 36 | use bl602wifi::println; 37 | use bl602wifi::timer::{timestamp, wifi_timer_init}; 38 | use bl602wifi::wifi::*; 39 | 40 | mod wifi_config; 41 | use wifi_config::WIFI_PASSWORD; 42 | use wifi_config::WIFI_SSID; 43 | 44 | #[riscv_rt::entry] 45 | fn main() -> ! { 46 | let dp = pac::Peripherals::take().unwrap(); 47 | let mut parts = dp.GLB.split(); 48 | 49 | let clocks = Strict::new() 50 | .use_pll(40_000_000u32.Hz()) 51 | .sys_clk(SysclkFreq::Pll160Mhz) 52 | .uart_clk(UART_PLL_FREQ.Hz()) 53 | .freeze(&mut parts.clk_cfg); 54 | 55 | // Set up uart output. Since this microcontroller has a pin matrix, 56 | // we need to set up both the pins and the muxs 57 | let pin16 = parts.pin16.into_uart_sig0(); 58 | let pin7 = parts.pin7.into_uart_sig7(); 59 | let mux0 = parts.uart_mux0.into_uart0_tx(); 60 | let mux7 = parts.uart_mux7.into_uart0_rx(); 61 | 62 | // Configure our UART to 115200 Baud, and use the pins we configured above 63 | let serial = Serial::uart0( 64 | dp.UART, 65 | Config::default().baudrate(115_200.Bd()), 66 | ((pin16, mux0), (pin7, mux7)), 67 | clocks, 68 | ); 69 | unsafe { 70 | *(GLOBAL_SERIAL.as_mut_ptr()) = serial; 71 | } 72 | 73 | set_writer(get_serial); 74 | 75 | println!("init"); 76 | 77 | wifi_pre_init(); 78 | 79 | let timers = dp.TIMER.split(); 80 | wifi_timer_init(timers.channel0, dp.HBN); 81 | 82 | let mut socket_set_entries: [_; 2] = Default::default(); 83 | let mut sockets = smoltcp::socket::SocketSet::new(&mut socket_set_entries[..]); 84 | let mut neighbor_cache_storage = [None; 8]; 85 | let neighbor_cache = NeighborCache::new(&mut neighbor_cache_storage[..]); 86 | 87 | let hw_address = EthernetAddress::from_bytes(&[0, 0, 0, 0, 0, 0]); 88 | let device = WifiDevice::new(); 89 | 90 | let ip_addr = IpCidr::new(IpAddress::v4(192, 168, 2, 191), 24); 91 | let mut ip_addrs = [ip_addr]; 92 | 93 | let mut routes_storage = [None; 1]; 94 | let mut routes = Routes::new(&mut routes_storage[..]); 95 | routes 96 | .add_default_ipv4_route(Ipv4Address::new(192, 168, 2, 1)) 97 | .ok(); 98 | 99 | let mut ethernet = smoltcp::iface::EthernetInterfaceBuilder::new(device) 100 | .ethernet_addr(hw_address) 101 | .neighbor_cache(neighbor_cache) 102 | .ip_addrs(&mut ip_addrs[..]) 103 | .routes(routes) 104 | .finalize(); 105 | 106 | wifi_init(); 107 | 108 | init_mac(&mut ethernet); 109 | 110 | println!("start connect"); 111 | 112 | connect_sta(WIFI_SSID, WIFI_PASSWORD); 113 | 114 | let greet_socket = { 115 | static mut TCP_SERVER_RX_DATA: [u8; 32] = [0; 32]; 116 | static mut TCP_SERVER_TX_DATA: [u8; 32] = [0; 32]; 117 | 118 | let tcp_rx_buffer = unsafe { TcpSocketBuffer::new(&mut TCP_SERVER_RX_DATA[..]) }; 119 | let tcp_tx_buffer = unsafe { TcpSocketBuffer::new(&mut TCP_SERVER_TX_DATA[..]) }; 120 | 121 | TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer) 122 | }; 123 | let greet_handle = sockets.add(greet_socket); 124 | 125 | // task should never return 126 | loop { 127 | let timestamp = timestamp(); 128 | riscv::interrupt::free(|_| { 129 | ethernet.poll(&mut sockets, timestamp).ok(); 130 | }); 131 | 132 | trigger_transmit_if_needed(); 133 | 134 | // Control the "greeting" socket (:4321) 135 | { 136 | let mut socket = sockets.get::(greet_handle); 137 | if !socket.is_open() { 138 | println!( 139 | "Listening to port 4321 for greeting, \ 140 | please connect to the port" 141 | ); 142 | socket.listen(4321).unwrap(); 143 | } 144 | 145 | if socket.can_send() { 146 | println!("Send and close."); 147 | socket.send_slice(&b"Hello World"[..]).ok(); 148 | socket.close(); 149 | } 150 | } 151 | } 152 | } 153 | 154 | #[export_name = "ExceptionHandler"] 155 | fn custom_exception_handler(_trap_frame: &riscv_rt::TrapFrame) -> ! { 156 | /* 157 | 0 0 Instruction address misaligned 158 | 0 1 Instruction access fault 159 | 0 2 Illegal instruction 160 | 0 3 Breakpoint 161 | 0 4 Load address misaligned 162 | 0 5 Load access fault 163 | 0 6 Store/AMO address misaligned 164 | 0 7 Store/AMO access fault 165 | 0 8 Environment call from U-mode 166 | 0 9 Environment call from S-mode 167 | 0 10 Reserved 168 | 0 11 Environment call from M-mode 169 | 0 12 Instruction page fault 170 | 0 13 Load page fault 171 | 0 14 Reserved 172 | 0 15 Store/AMO page fault 173 | */ 174 | 175 | let mepc = riscv::register::mepc::read(); 176 | let code = riscv::register::mcause::read().code() & 0xff; 177 | println!("exception code {} at {:x}", code, mepc); 178 | loop {} 179 | } 180 | 181 | fn get_serial() -> &'static mut dyn core::fmt::Write { 182 | unsafe { &mut *GLOBAL_SERIAL.as_mut_ptr() } 183 | } 184 | 185 | #[panic_handler] 186 | fn panic_handler(info: &PanicInfo) -> ! { 187 | let serial = unsafe { &mut *(GLOBAL_SERIAL.as_mut_ptr()) }; 188 | write!(serial, "PANIC! {:?}\r\n", info).ok(); 189 | loop {} 190 | } 191 | -------------------------------------------------------------------------------- /src/preemt/mod.rs: -------------------------------------------------------------------------------- 1 | use bl602_hal::interrupts::TrapFrame; 2 | 3 | #[derive(Debug, Default, Clone, Copy)] 4 | pub struct Context { 5 | trap_frame: TrapFrame, 6 | pc: usize, 7 | _running: bool, 8 | } 9 | 10 | const STACK_SIZE: usize = 8192; 11 | const MAX_TASK: usize = 4; 12 | 13 | pub static mut TASK_STACK: [u8; STACK_SIZE * MAX_TASK] = [0u8; STACK_SIZE * MAX_TASK]; 14 | 15 | static mut FIRST_SWITCH: bool = true; 16 | 17 | static mut TASK_TOP: usize = 0; 18 | 19 | pub static mut CTX_NOW: usize = 0; 20 | 21 | pub static mut CTX_TASKS: [Context; MAX_TASK] = [Context { 22 | trap_frame: TrapFrame { 23 | ra: 0, 24 | t0: 0, 25 | t1: 0, 26 | t2: 0, 27 | t3: 0, 28 | t4: 0, 29 | t5: 0, 30 | t6: 0, 31 | a0: 0, 32 | a1: 0, 33 | a2: 0, 34 | a3: 0, 35 | a4: 0, 36 | a5: 0, 37 | a6: 0, 38 | a7: 0, 39 | s0: 0, 40 | s1: 0, 41 | s2: 0, 42 | s3: 0, 43 | s4: 0, 44 | s5: 0, 45 | s6: 0, 46 | s7: 0, 47 | s8: 0, 48 | s9: 0, 49 | s10: 0, 50 | s11: 0, 51 | gp: 0, 52 | tp: 0, 53 | sp: 0, 54 | }, 55 | pc: 0, 56 | _running: false, 57 | }; MAX_TASK]; 58 | 59 | pub fn task_create(task: extern "C" fn()) -> usize { 60 | unsafe { 61 | let i = TASK_TOP; 62 | TASK_TOP += 1; 63 | CTX_TASKS[i].pc = task as usize; 64 | CTX_TASKS[i].trap_frame.sp = &TASK_STACK as *const _ as usize 65 | + (STACK_SIZE as usize * i as usize) 66 | + STACK_SIZE as usize 67 | - 4; 68 | 69 | CTX_NOW = i; 70 | i 71 | } 72 | } 73 | 74 | fn task_create_from_mepc(mepc: usize) -> usize { 75 | unsafe { 76 | let i = TASK_TOP; 77 | TASK_TOP += 1; 78 | CTX_TASKS[i].pc = mepc; 79 | CTX_TASKS[i].trap_frame.sp = &TASK_STACK as *const _ as usize 80 | + (STACK_SIZE as usize * i as usize) 81 | + STACK_SIZE as usize 82 | - 4; 83 | 84 | CTX_NOW = i; 85 | i 86 | } 87 | } 88 | 89 | pub fn task_to_trap_frame(id: usize, trap_frame: &mut TrapFrame) -> usize { 90 | unsafe { 91 | trap_frame.ra = CTX_TASKS[id].trap_frame.ra; 92 | trap_frame.sp = CTX_TASKS[id].trap_frame.sp; 93 | trap_frame.a0 = CTX_TASKS[id].trap_frame.a0; 94 | trap_frame.a1 = CTX_TASKS[id].trap_frame.a1; 95 | trap_frame.a2 = CTX_TASKS[id].trap_frame.a2; 96 | trap_frame.a3 = CTX_TASKS[id].trap_frame.a3; 97 | trap_frame.a4 = CTX_TASKS[id].trap_frame.a4; 98 | trap_frame.a5 = CTX_TASKS[id].trap_frame.a5; 99 | trap_frame.a6 = CTX_TASKS[id].trap_frame.a6; 100 | trap_frame.a7 = CTX_TASKS[id].trap_frame.a7; 101 | trap_frame.t0 = CTX_TASKS[id].trap_frame.t0; 102 | trap_frame.t1 = CTX_TASKS[id].trap_frame.t1; 103 | trap_frame.t2 = CTX_TASKS[id].trap_frame.t2; 104 | trap_frame.t3 = CTX_TASKS[id].trap_frame.t3; 105 | trap_frame.t4 = CTX_TASKS[id].trap_frame.t4; 106 | trap_frame.t5 = CTX_TASKS[id].trap_frame.t5; 107 | trap_frame.t6 = CTX_TASKS[id].trap_frame.t6; 108 | trap_frame.s0 = CTX_TASKS[id].trap_frame.s0; 109 | trap_frame.s1 = CTX_TASKS[id].trap_frame.s1; 110 | trap_frame.s2 = CTX_TASKS[id].trap_frame.s2; 111 | trap_frame.s3 = CTX_TASKS[id].trap_frame.s3; 112 | trap_frame.s4 = CTX_TASKS[id].trap_frame.s4; 113 | trap_frame.s5 = CTX_TASKS[id].trap_frame.s5; 114 | trap_frame.s6 = CTX_TASKS[id].trap_frame.s6; 115 | trap_frame.s7 = CTX_TASKS[id].trap_frame.s7; 116 | trap_frame.s8 = CTX_TASKS[id].trap_frame.s8; 117 | trap_frame.s9 = CTX_TASKS[id].trap_frame.s9; 118 | trap_frame.s10 = CTX_TASKS[id].trap_frame.s10; 119 | trap_frame.s11 = CTX_TASKS[id].trap_frame.s11; 120 | trap_frame.gp = CTX_TASKS[id].trap_frame.gp; 121 | trap_frame.tp = CTX_TASKS[id].trap_frame.tp; 122 | 123 | CTX_TASKS[id].pc 124 | } 125 | } 126 | 127 | pub fn trap_frame_to_task(id: usize, pc: usize, trap_frame: &TrapFrame) { 128 | unsafe { 129 | CTX_TASKS[id].trap_frame.ra = trap_frame.ra; 130 | CTX_TASKS[id].trap_frame.sp = trap_frame.sp; 131 | CTX_TASKS[id].trap_frame.a0 = trap_frame.a0; 132 | CTX_TASKS[id].trap_frame.a1 = trap_frame.a1; 133 | CTX_TASKS[id].trap_frame.a2 = trap_frame.a2; 134 | CTX_TASKS[id].trap_frame.a3 = trap_frame.a3; 135 | CTX_TASKS[id].trap_frame.a4 = trap_frame.a4; 136 | CTX_TASKS[id].trap_frame.a5 = trap_frame.a5; 137 | CTX_TASKS[id].trap_frame.a6 = trap_frame.a6; 138 | CTX_TASKS[id].trap_frame.a7 = trap_frame.a7; 139 | CTX_TASKS[id].trap_frame.t0 = trap_frame.t0; 140 | CTX_TASKS[id].trap_frame.t1 = trap_frame.t1; 141 | CTX_TASKS[id].trap_frame.t2 = trap_frame.t2; 142 | CTX_TASKS[id].trap_frame.t3 = trap_frame.t3; 143 | CTX_TASKS[id].trap_frame.t4 = trap_frame.t4; 144 | CTX_TASKS[id].trap_frame.t5 = trap_frame.t5; 145 | CTX_TASKS[id].trap_frame.t6 = trap_frame.t6; 146 | CTX_TASKS[id].trap_frame.s0 = trap_frame.s0; 147 | CTX_TASKS[id].trap_frame.s1 = trap_frame.s1; 148 | CTX_TASKS[id].trap_frame.s2 = trap_frame.s2; 149 | CTX_TASKS[id].trap_frame.s3 = trap_frame.s3; 150 | CTX_TASKS[id].trap_frame.s4 = trap_frame.s4; 151 | CTX_TASKS[id].trap_frame.s5 = trap_frame.s5; 152 | CTX_TASKS[id].trap_frame.s6 = trap_frame.s6; 153 | CTX_TASKS[id].trap_frame.s7 = trap_frame.s7; 154 | CTX_TASKS[id].trap_frame.s8 = trap_frame.s8; 155 | CTX_TASKS[id].trap_frame.s9 = trap_frame.s9; 156 | CTX_TASKS[id].trap_frame.s10 = trap_frame.s10; 157 | CTX_TASKS[id].trap_frame.s11 = trap_frame.s11; 158 | CTX_TASKS[id].trap_frame.gp = trap_frame.gp; 159 | CTX_TASKS[id].trap_frame.tp = trap_frame.tp; 160 | 161 | CTX_TASKS[id].pc = pc; 162 | } 163 | } 164 | 165 | pub fn next_task() { 166 | unsafe { 167 | CTX_NOW = (CTX_NOW + 1) % TASK_TOP; 168 | } 169 | } 170 | 171 | pub fn task_switch(trap_frame: &mut TrapFrame) { 172 | unsafe { 173 | let old_mepc = riscv::register::mepc::read(); 174 | 175 | if FIRST_SWITCH { 176 | FIRST_SWITCH = false; 177 | let main_task = task_create_from_mepc(old_mepc); 178 | CTX_NOW = main_task; 179 | } 180 | 181 | trap_frame_to_task(CTX_NOW, old_mepc, trap_frame); 182 | 183 | next_task(); 184 | 185 | let new_pc = task_to_trap_frame(CTX_NOW, trap_frame); 186 | 187 | riscv::register::mepc::write(new_pc); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/compat/circbuf.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | binary::c_types::c_void, 3 | compat::malloc::{free, malloc}, 4 | }; 5 | 6 | use super::queue::SimpleQueue; 7 | 8 | #[derive(Debug)] 9 | #[repr(C)] 10 | pub struct CircBuf { 11 | base: *mut u8, /* The pointer to buffer space */ 12 | size: usize, /* The size of buffer space */ 13 | head: usize, /* The head of buffer space */ 14 | tail: usize, /* The tail of buffer space */ 15 | external: bool, /* The flag for external buffer */ 16 | } 17 | 18 | /**************************************************************************** 19 | * Name: circbuf_init 20 | * 21 | * Description: 22 | * Initialize a circular buffer. 23 | * 24 | * Input Parameters: 25 | * circ - Address of the circular buffer to be used. 26 | * base - A pointer to circular buffer's internal buffer. It can be 27 | * provided by caller because sometimes the creation of buffer 28 | * is special or needs to preallocated, eg: DMA buffer. 29 | * If NULL, a buffer of the given size will be allocated. 30 | * bytes - The size of the internal buffer. 31 | * 32 | * Returned Value: 33 | * Zero on success; A negated errno value is returned on any failure. 34 | * 35 | ****************************************************************************/ 36 | #[no_mangle] 37 | pub unsafe extern "C" fn circbuf_init(circ: *mut CircBuf, base: *const u8, bytes: usize) -> i32 { 38 | (*circ).external = true; 39 | 40 | if base.is_null() { 41 | let buffer = malloc(bytes as u32); 42 | (*circ).base = buffer as *mut u8; 43 | (*circ).external = false; 44 | } else { 45 | (*circ).base = base as *mut _; 46 | } 47 | 48 | (*circ).size = bytes; 49 | (*circ).head = 0; 50 | (*circ).tail = 0; 51 | 52 | 0 53 | } 54 | 55 | /**************************************************************************** 56 | * Name: circbuf_uninit 57 | * 58 | * Description: 59 | * Free the circular buffer. 60 | * 61 | * Input Parameters: 62 | * circ - Address of the circular buffer to be used. 63 | ****************************************************************************/ 64 | #[no_mangle] 65 | pub unsafe extern "C" fn circbuf_uninit(circ: *const CircBuf) { 66 | if (*circ).external { 67 | free((*circ).base); 68 | } 69 | } 70 | 71 | /**************************************************************************** 72 | * Name: circbuf_used 73 | * 74 | * Description: 75 | * Return the used bytes of the circular buffer. 76 | * 77 | * Input Parameters: 78 | * circ - Address of the circular buffer to be used. 79 | ****************************************************************************/ 80 | #[no_mangle] 81 | pub unsafe extern "C" fn circbuf_used(circ: *const CircBuf) -> usize { 82 | let mut used = (*circ).head as i32 - (*circ).tail as i32; 83 | if used < 0 { 84 | used = (*circ).size as i32 + used; 85 | } 86 | 87 | used as usize 88 | } 89 | 90 | /**************************************************************************** 91 | * Name: circbuf_read 92 | * 93 | * Description: 94 | * Get data form the circular buffer. 95 | * 96 | * Note : 97 | * That with only one concurrent reader and one concurrent writer, 98 | * you don't need extra locking to use these api. 99 | * 100 | * Input Parameters: 101 | * circ - Address of the circular buffer to be used. 102 | * dst - Address where to store the data. 103 | * bytes - Number of bytes to get. 104 | * 105 | * Returned Value: 106 | * The bytes of get data is returned if the read data is successful; 107 | * A negated errno value is returned on any failure. 108 | ****************************************************************************/ 109 | #[no_mangle] 110 | pub unsafe extern "C" fn circbuf_read(circ: *mut CircBuf, dst: *mut u8, bytes: usize) -> i32 { 111 | let count = usize::min(circbuf_used(circ), bytes) as isize; 112 | let mut t = (*circ).base.offset((*circ).tail as isize); 113 | for i in 0..count { 114 | dst.offset(i).write_volatile(t.read_volatile()); 115 | 116 | t = t.offset(1); 117 | if t > (*circ).base.offset((*circ).size as isize) { 118 | t = (*circ).base; 119 | } 120 | } 121 | 122 | (*circ).tail = t as usize - (*circ).base as usize; 123 | 124 | count as i32 125 | } 126 | 127 | /**************************************************************************** 128 | * Name: circbuf_write 129 | * 130 | * Description: 131 | * Write data to the circular buffer. 132 | * 133 | * Note: 134 | * That with only one concurrent reader and one concurrent writer, 135 | * you don't need extra locking to use these api. 136 | * 137 | * Input Parameters: 138 | * circ - Address of the circular buffer to be used. 139 | * src - The data to be added. 140 | * bytes - Number of bytes to be added. 141 | * 142 | * Returned Value: 143 | * The bytes of get data is returned if the write data is successful; 144 | * A negated errno value is returned on any failure. 145 | ****************************************************************************/ 146 | #[no_mangle] 147 | pub unsafe extern "C" fn circbuf_write(circ: *mut CircBuf, src: *const u8, bytes: usize) -> i32 { 148 | let count = bytes as isize; 149 | let mut t = (*circ).base.offset((*circ).head as isize); 150 | for i in 0..count { 151 | let b = src.offset(i).read(); 152 | t.write(b); 153 | 154 | t = t.offset(1); 155 | if t > (*circ).base.offset((*circ).size as isize) { 156 | t = (*circ).base; 157 | } 158 | } 159 | 160 | (*circ).head = t as usize - (*circ).base as usize; 161 | 162 | count as i32 163 | } 164 | 165 | /**************************************************************************** 166 | * Name: uart_bth4_register 167 | * 168 | * Description: 169 | * Register bluetooth H:4 UART driver. 170 | * 171 | ****************************************************************************/ 172 | #[no_mangle] 173 | pub unsafe extern "C" fn uart_bth4_register(_path: *const u8, drv: *mut BtDriver) -> i32 { 174 | (*drv).receive = Some(bt_receive); 175 | BT_DRIVER = Some(drv); 176 | 177 | 0 178 | } 179 | 180 | pub static mut BT_DRIVER: Option<*mut BtDriver> = None; 181 | 182 | unsafe extern "C" fn bt_receive(_drv: *mut BtDriver, buf_type: u8, dst: *mut u8, len: usize) { 183 | let mut data = [0u8; 256]; 184 | for i in 0..len { 185 | let b = dst.offset(i as isize).read(); 186 | data[i + 1] = b; 187 | } 188 | 189 | let packet = ReceivedPacket { 190 | packet_type: buf_type, 191 | len: len as u8, 192 | data, 193 | }; 194 | 195 | BT_RECEIVE_QUEUE.enqueue(packet); 196 | } 197 | 198 | #[derive(Debug)] 199 | #[repr(C)] 200 | pub struct BtDriver { 201 | head_reserve: usize, 202 | pub open: ::core::option::Option, 203 | 204 | pub send: ::core::option::Option< 205 | unsafe extern "C" fn(drv: *mut BtDriver, buf_type: u8, src: *const u8, len: usize), 206 | >, 207 | 208 | pub close: ::core::option::Option, 209 | 210 | pub receive: ::core::option::Option< 211 | unsafe extern "C" fn(drv: *mut BtDriver, buf_type: u8, dst: *mut u8, len: usize), 212 | >, 213 | 214 | pub private: *const c_void, 215 | } 216 | 217 | pub static mut BT_RECEIVE_QUEUE: SimpleQueue = SimpleQueue::new(); 218 | 219 | pub struct ReceivedPacket { 220 | pub packet_type: u8, 221 | pub len: u8, 222 | pub data: [u8; 256], 223 | } 224 | 225 | pub enum BtPacketType { 226 | BtCmd = 0, /* HCI command */ 227 | BtEvt = 1, /* HCI event */ 228 | BtAclOut = 2, /* Outgoing ACL data */ 229 | BtAclIn = 3, /* Incoming ACL data */ 230 | BtIsoOut = 4, /* Outgoing ISO data */ 231 | BtIsoIn = 5, /* Incoming ISO data */ 232 | BtDummy = 99, /* Only used for waking up kernel threads */ 233 | } 234 | -------------------------------------------------------------------------------- /src/ble/mod.rs: -------------------------------------------------------------------------------- 1 | use core::mem::MaybeUninit; 2 | 3 | use crate::compat::circbuf::{BtPacketType, BT_DRIVER, BT_RECEIVE_QUEUE}; 4 | 5 | pub mod controller; 6 | 7 | static mut BLE_INITIALIZED: bool = false; 8 | 9 | extern "C" { 10 | fn bl602_hci_uart_init(uartid: u8); 11 | } 12 | 13 | pub fn ble_init() { 14 | unsafe { 15 | *(HCI_OUT_COLLECTOR.as_mut_ptr()) = HciOutCollector::new(); 16 | 17 | bl602_hci_uart_init(0); 18 | 19 | if let Some(drv) = BT_DRIVER { 20 | let open = (*drv).open.unwrap(); 21 | open(drv); 22 | } 23 | 24 | riscv::interrupt::free(|_| { 25 | BLE_INITIALIZED = true; 26 | }); 27 | } 28 | } 29 | 30 | pub fn send_hci(data: &[u8]) { 31 | let hci_out = unsafe { &mut *HCI_OUT_COLLECTOR.as_mut_ptr() }; 32 | hci_out.push(data); 33 | 34 | if hci_out.is_ready() { 35 | let packet = hci_out.packet(); 36 | 37 | let packet_type = match packet[0] { 38 | 1 => BtPacketType::BtCmd as u8, 39 | 2 => BtPacketType::BtAclOut as u8, 40 | 3 => BtPacketType::BtAclIn as u8, 41 | 4 => BtPacketType::BtEvt as u8, 42 | _ => BtPacketType::BtCmd as u8, 43 | }; 44 | 45 | unsafe { 46 | if let Some(drv) = BT_DRIVER { 47 | let send = (*drv).send.unwrap(); 48 | 49 | let data_ptr = packet as *const _ as *const u8; 50 | let data_ptr = data_ptr.offset(1); 51 | send(drv, packet_type, data_ptr, packet.len() - 1); 52 | } 53 | } 54 | 55 | hci_out.reset(); 56 | } 57 | } 58 | 59 | static mut BLE_HCI_READ_DATA: [u8; 256] = [0u8; 256]; 60 | static mut BLE_HCI_READ_DATA_INDEX: usize = 0; 61 | static mut BLE_HCI_READ_DATA_LEN: usize = 0; 62 | 63 | pub fn read_hci(data: &mut [u8]) -> usize { 64 | unsafe { 65 | if BLE_HCI_READ_DATA_LEN == 0 { 66 | let dequeued = BT_RECEIVE_QUEUE.dequeue(); 67 | match dequeued { 68 | Some(packet) => { 69 | for i in 0..(packet.len as usize + 1) { 70 | BLE_HCI_READ_DATA[i] = packet.data[i]; 71 | } 72 | 73 | BLE_HCI_READ_DATA[0] = match packet.packet_type { 74 | 1 /*BtPacketType::BT_EVT*/ => 4, 75 | 3 /*BtPacketType::BT_ACL_IN*/ => 2, 76 | _ => 4, 77 | }; 78 | 79 | BLE_HCI_READ_DATA_LEN = packet.len as usize + 1; 80 | BLE_HCI_READ_DATA_INDEX = 0; 81 | } 82 | None => (), 83 | }; 84 | } 85 | 86 | if BLE_HCI_READ_DATA_LEN > 0 { 87 | data[0] = BLE_HCI_READ_DATA[BLE_HCI_READ_DATA_INDEX]; 88 | BLE_HCI_READ_DATA_INDEX += 1; 89 | 90 | if BLE_HCI_READ_DATA_INDEX >= BLE_HCI_READ_DATA_LEN { 91 | BLE_HCI_READ_DATA_LEN = 0; 92 | BLE_HCI_READ_DATA_INDEX = 0; 93 | } 94 | return 1; 95 | } 96 | } 97 | 98 | 0 99 | } 100 | 101 | pub extern "C" fn ble_worker() { 102 | unsafe { 103 | while !riscv::interrupt::free(|_| BLE_INITIALIZED) {} 104 | 105 | loop { 106 | // TODO ??? ble_hci_do_rx(); 107 | for _ in 0..20000 {} 108 | } 109 | } 110 | } 111 | 112 | pub struct HciPipe { 113 | wbuffer: [u8; 256], 114 | rbuffer: [u8; 256], 115 | w_write_idx: usize, 116 | w_read_idx: usize, 117 | r_write_idx: usize, 118 | r_read_idx: usize, 119 | } 120 | 121 | impl HciPipe { 122 | pub fn new() -> HciPipe { 123 | HciPipe { 124 | wbuffer: [0u8; 256], 125 | rbuffer: [0u8; 256], 126 | w_write_idx: 0, 127 | w_read_idx: 0, 128 | r_write_idx: 0, 129 | r_read_idx: 0, 130 | } 131 | } 132 | 133 | pub fn controller_read(&mut self) -> Option { 134 | riscv::interrupt::free(|_| { 135 | if self.r_write_idx == self.r_read_idx { 136 | None 137 | } else { 138 | let r = self.rbuffer[self.r_read_idx]; 139 | self.r_read_idx += 1; 140 | if self.r_read_idx >= self.rbuffer.len() { 141 | self.r_read_idx = 0; 142 | } 143 | Some(r) 144 | } 145 | }) 146 | } 147 | 148 | pub fn controller_write(&mut self, v: u8) { 149 | riscv::interrupt::free(|_| { 150 | self.wbuffer[self.w_write_idx] = v; 151 | self.w_write_idx += 1; 152 | if self.w_write_idx >= self.wbuffer.len() { 153 | self.w_write_idx = 0; 154 | } 155 | 156 | if self.w_write_idx == self.w_read_idx { 157 | panic!("Buffer overflow in controller_write"); 158 | } 159 | }) 160 | } 161 | 162 | pub fn host_read(&mut self) -> Option { 163 | riscv::interrupt::free(|_| { 164 | if self.w_write_idx == self.w_read_idx { 165 | None 166 | } else { 167 | let r = self.wbuffer[self.w_read_idx]; 168 | self.w_read_idx += 1; 169 | if self.w_read_idx >= self.wbuffer.len() { 170 | self.w_read_idx = 0; 171 | } 172 | Some(r) 173 | } 174 | }) 175 | } 176 | 177 | pub fn host_peek(&mut self, offset: usize) -> Option { 178 | riscv::interrupt::free(|_| { 179 | if self.w_write_idx == self.w_read_idx { 180 | None 181 | } else { 182 | let index = (self.w_read_idx + offset) % self.wbuffer.len(); 183 | 184 | // ??? 185 | if index > self.w_write_idx { 186 | None 187 | } else { 188 | Some(self.wbuffer[index]) 189 | } 190 | } 191 | }) 192 | } 193 | 194 | pub fn host_write(&mut self, v: u8) { 195 | riscv::interrupt::free(|_| { 196 | self.rbuffer[self.r_write_idx] = v; 197 | self.r_write_idx += 1; 198 | if self.r_write_idx >= self.rbuffer.len() { 199 | self.r_write_idx = 0; 200 | } 201 | 202 | if self.r_write_idx == self.r_read_idx { 203 | panic!("Buffer overflow in host_write"); 204 | } 205 | }) 206 | } 207 | } 208 | 209 | static mut HCI_OUT_COLLECTOR: MaybeUninit = MaybeUninit::uninit(); 210 | 211 | #[derive(PartialEq, Debug)] 212 | enum HciOutType { 213 | Unknown, 214 | Acl, 215 | Command, 216 | } 217 | 218 | struct HciOutCollector { 219 | data: [u8; 256], 220 | index: usize, 221 | ready: bool, 222 | kind: HciOutType, 223 | } 224 | 225 | impl HciOutCollector { 226 | fn new() -> HciOutCollector { 227 | HciOutCollector { 228 | data: [0u8; 256], 229 | index: 0, 230 | ready: false, 231 | kind: HciOutType::Unknown, 232 | } 233 | } 234 | 235 | fn is_ready(&self) -> bool { 236 | self.ready 237 | } 238 | 239 | fn push(&mut self, data: &[u8]) { 240 | self.data[self.index..(self.index + data.len())].copy_from_slice(data); 241 | self.index += data.len(); 242 | 243 | if self.kind == HciOutType::Unknown { 244 | self.kind = match self.data[0] { 245 | 1 => HciOutType::Command, 246 | 2 => HciOutType::Acl, 247 | _ => HciOutType::Unknown, 248 | }; 249 | } 250 | 251 | if !self.ready { 252 | if self.kind == HciOutType::Command && self.index >= 4 { 253 | if self.index == self.data[3] as usize + 4 { 254 | self.ready = true; 255 | } 256 | } else if self.kind == HciOutType::Acl && self.index >= 5 { 257 | if self.index == (self.data[3] as usize) + ((self.data[4] as usize) << 8) + 5 { 258 | self.ready = true; 259 | } 260 | } 261 | } 262 | } 263 | 264 | fn reset(&mut self) { 265 | self.index = 0; 266 | self.ready = false; 267 | self.kind = HciOutType::Unknown; 268 | } 269 | 270 | fn packet(&self) -> &[u8] { 271 | &self.data[0..(self.index as usize)] 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /nuttx/wifi_manager/include/wifi_mgmr_ext.h: -------------------------------------------------------------------------------- 1 | #ifndef __WIFI_MGMR_EXT_H__ 2 | #define __WIFI_MGMR_EXT_H__ 3 | 4 | enum ap_info_type { 5 | /* The current AP information is advisory. When the AP fails to connect 6 | * through its specified parameters, the information is no longer used 7 | * when reconnecting. If the time_to_live field is not 0, the information 8 | * will not be used after time_to_live times. 9 | */ 10 | AP_INFO_TYPE_SUGGEST, 11 | 12 | /* The current AP information is mandatory. When the AP fails to connect 13 | * through its specified parameters, the information is always used 14 | * to reconnect. 15 | */ 16 | AP_INFO_TYPE_PRESIST, 17 | }; 18 | 19 | struct ap_info { 20 | enum ap_info_type type; 21 | 22 | /* when type field is AP_INFO_TYPE_SUGGEST, this field indicates the number 23 | *of effective times 24 | */ 25 | int time_to_live; 26 | 27 | /* bssid, NULL is disable */ 28 | uint8_t *bssid; 29 | 30 | /* default 0, reserved */ 31 | uint8_t band; 32 | 33 | /* freq number, 0 is disable */ 34 | uint16_t freq; 35 | }; 36 | 37 | /* Wifi Connecting advanced prameters */ 38 | struct ap_connect_adv { 39 | /* Auth parameters */ 40 | char *psk; 41 | 42 | /* AP extended information */ 43 | struct ap_info ap_info; 44 | }; 45 | 46 | typedef struct ap_connect_adv ap_connect_adv_t; 47 | 48 | typedef struct wifi_mgmr_ap_item { 49 | char ssid[32]; 50 | char ssid_tail[1];//always put ssid_tail after ssid 51 | uint32_t ssid_len; 52 | uint8_t bssid[6]; 53 | uint8_t channel; 54 | uint8_t auth; 55 | int8_t rssi; 56 | } wifi_mgmr_ap_item_t; 57 | 58 | typedef struct wifi_mgmr_sta_connect_ind_stat_info { 59 | uint16_t status_code; 60 | /*mgmr recv ind event from fw when connect or disconnect */ 61 | uint8_t type_ind; 62 | char ssid[32]; 63 | char passphr[65]; 64 | char psk[64]; 65 | uint8_t bssid[6]; 66 | uint16_t chan_freq; 67 | uint8_t chan_band; 68 | } wifi_mgmr_sta_connect_ind_stat_info_t; 69 | 70 | typedef struct wifi_sta_basic_info { 71 | uint8_t sta_idx; 72 | uint8_t is_used; 73 | uint8_t sta_mac[6]; 74 | uint32_t tsfhi; 75 | uint32_t tsflo; 76 | int rssi; 77 | uint8_t data_rate; 78 | } wifi_sta_basic_info_t; 79 | 80 | typedef struct wifi_sta_ps_conf { 81 | /// num of beacons 82 | int listen_interval; 83 | ///wifi active ms. 84 | uint16_t wifi_active_period; 85 | }wifi_sta_ps_conf_t; 86 | 87 | typedef void *wifi_interface_t; 88 | typedef void (*sniffer_cb_t)(void *env, uint8_t *pkt, int len); 89 | typedef void (*scan_item_cb_t)(wifi_mgmr_ap_item_t *env, uint32_t *param1, wifi_mgmr_ap_item_t *item); 90 | typedef void (*scan_complete_cb_t)(void *data, void *param); 91 | 92 | /// Power Save mode setting 93 | enum 94 | { 95 | /// Power-save off 96 | PS_MODE_OFF, 97 | /// Power-save on - Normal mode 98 | PS_MODE_ON, 99 | /// Power-save on - Dynamic mode 100 | PS_MODE_ON_DYN, 101 | }; 102 | 103 | enum WIFI_STATE_ENUM_LIST { 104 | WIFI_STATE_UNKNOWN = 0x00, 105 | WIFI_STATE_IDLE = 0x01, 106 | WIFI_STATE_CONNECTING = 0x02, 107 | WIFI_STATE_CONNECTED_IP_GETTING = 0x03, 108 | WIFI_STATE_CONNECTED_IP_GOT = 0x04, 109 | WIFI_STATE_DISCONNECT = 0x05, 110 | WIFI_STATE_WITH_AP_IDLE = 0x11, 111 | WIFI_STATE_WITH_AP_CONNECTING = 0x12, 112 | WIFI_STATE_WITH_AP_CONNECTED_IP_GETTING = 0x13, 113 | WIFI_STATE_WITH_AP_CONNECTED_IP_GOT = 0x14, 114 | WIFI_STATE_WITH_AP_DISCONNECT = 0x15, 115 | WIFI_STATE_IFDOWN = 0x06, 116 | WIFI_STATE_SNIFFER = 0x07, 117 | WIFI_STATE_PSK_ERROR = 0x08, 118 | WIFI_STATE_NO_AP_FOUND = 0x09, 119 | }; 120 | #define WIFI_STATE_AP_IS_ENABLED(status) ((status) & 0x10) 121 | 122 | enum WIFI_SCAN_DONE_EVENT_TYPE { 123 | WIFI_SCAN_DONE_EVENT_OK = 0x00, 124 | WIFI_SCAN_DONE_EVENT_BUSY = 0x01, 125 | }; 126 | 127 | typedef struct wifi_conf { 128 | char country_code[3]; 129 | int channel_nums; 130 | } wifi_conf_t; 131 | 132 | //FIXME implemented in wifi_mgmr.c 133 | int wifi_mgmr_psk_cal(char *password, char *ssid, int ssid_len, char *output); 134 | int wifi_mgmr_drv_init(wifi_conf_t *conf); 135 | int wifi_mgmr_init(void); 136 | void wifi_mgmr_start(void); 137 | void wifi_mgmr_start_background(wifi_conf_t *conf); 138 | void wifi_mgmr_get_wifi_channel_conf(wifi_conf_t *wifi_chan_conf); 139 | 140 | wifi_interface_t wifi_mgmr_sta_enable(void *opaque); 141 | int wifi_mgmr_sta_disable(wifi_interface_t *interface); 142 | int wifi_mgmr_sta_mac_set(uint8_t mac[6]); 143 | int wifi_mgmr_sta_mac_get(uint8_t mac[6]); 144 | int wifi_mgmr_sta_ip_get(uint32_t *ip, uint32_t *gw, uint32_t *mask); 145 | int wifi_mgmr_sta_ip_set(uint32_t ip, uint32_t mask, uint32_t gw, uint32_t dns1, uint32_t dns2); 146 | int wifi_mgmr_sta_dns_get(uint32_t *dns1, uint32_t *dns2); 147 | int wifi_mgmr_sta_ip_unset(void); 148 | int wifi_mgmr_sta_connect_ext(wifi_interface_t *wifi_interface, char *ssid, char *passphr, const ap_connect_adv_t *conn_adv_param); 149 | int wifi_mgmr_sta_connect(wifi_interface_t *wifi_interface, char *ssid, char *psk, char *pmk, uint8_t *mac, uint8_t band, uint16_t freq); 150 | int wifi_mgmr_sta_disconnect(void); 151 | int wifi_mgmr_sta_ps_enter(uint32_t ps_level); 152 | int wifi_mgmr_sta_ps_exit(void); 153 | int wifi_mgmr_sta_autoconnect_enable(void); 154 | int wifi_mgmr_sta_autoconnect_disable(void); 155 | void wifi_mgmr_sta_ssid_set(char *ssid); 156 | void wifi_mgmr_sta_passphr_set(char *passphr); 157 | void wifi_mgmr_sta_psk_set(char *psk) __attribute__ ((deprecated ("use wifi_mgmr_sta_passphr_set instead"))); 158 | void wifi_mgmr_sta_connect_ind_stat_get(wifi_mgmr_sta_connect_ind_stat_info_t *wifi_mgmr_ind_stat); 159 | 160 | wifi_interface_t wifi_mgmr_ap_enable(void *opaque); 161 | int wifi_mgmr_ap_mac_set(uint8_t mac[6]); 162 | int wifi_mgmr_ap_mac_get(uint8_t mac[6]); 163 | int wifi_mgmr_ap_ip_get(uint32_t *ip, uint32_t *gw, uint32_t *mask); 164 | int wifi_mgmr_ap_stop(wifi_interface_t *interface); 165 | int wifi_mgmr_ap_start(wifi_interface_t *interface, char *ssid, int hidden_ssid, char *passwd, int channel); 166 | int wifi_mgmr_ap_sta_cnt_get(uint8_t *sta_cnt); 167 | int wifi_mgmr_ap_sta_info_get(struct wifi_sta_basic_info *sta_info, uint8_t idx); 168 | int wifi_mgmr_ap_sta_delete(uint8_t sta_idx); 169 | int wifi_mgmr_ap_set_gateway(char *gateway); 170 | int wifi_mgmr_sniffer_enable(void); 171 | int wifi_mgmr_sniffer_disable(void); 172 | int wifi_mgmr_rate_config(uint16_t config); 173 | int wifi_mgmr_conf_max_sta(uint8_t max_sta_supported); 174 | int wifi_mgmr_sniffer_register(void *env, sniffer_cb_t cb); 175 | int wifi_mgmr_sniffer_unregister(void *env); 176 | int wifi_mgmr_state_get(int *state); 177 | int wifi_mgmr_status_code_get(int *s_code); 178 | int wifi_mgmr_rssi_get(int *rssi); 179 | int wifi_mgmr_channel_get(int *channel); 180 | int wifi_mgmr_channel_set(int channel, int use_40Mhz); 181 | int wifi_mgmr_all_ap_scan(wifi_mgmr_ap_item_t **ap_ary, uint32_t *num); 182 | int wifi_mgmr_scan_filter_hidden_ssid(int filter); 183 | int wifi_mgmr_scan(void *data, scan_complete_cb_t cb); 184 | int wifi_mgmr_scan_fixed_channels(void *data, scan_complete_cb_t cb, uint16_t *channels, uint16_t channel_num); 185 | int wifi_mgmr_scan_adv(void *data, scan_complete_cb_t cb, uint16_t *channels, uint16_t channel_num, const char *ssid); 186 | int wifi_mgmr_cfg_req(uint32_t ops, uint32_t task, uint32_t element, uint32_t type, uint32_t length, uint32_t *buf); 187 | int wifi_mgmr_scan_complete_callback(void); 188 | int wifi_mgmr_cli_scanlist(void); 189 | int wifi_mgmr_cli_init(void); 190 | int wifi_mgmr_scan_ap(char *ssid, wifi_mgmr_ap_item_t *item); 191 | int wifi_mgmr_scan_ap_all(wifi_mgmr_ap_item_t *env, uint32_t *param1, scan_item_cb_t cb); 192 | int wifi_mgmr_raw_80211_send(uint8_t *pkt, int len); 193 | int wifi_mgmr_set_country_code(char *country_code); 194 | int wifi_mgmr_ext_dump_needed(void); 195 | void wifi_mgmr_reset(void); 196 | const char* wifi_mgmr_status_code_str(uint16_t status_code); 197 | int wifi_mgmr_beacon_interval_set(uint16_t beacon_int); 198 | void wifi_mgmr_conn_result_get(uint16_t *status_code, uint16_t *reason_code); 199 | int wifi_mgmr_set_wifi_active_time(uint32_t ms); 200 | int wifi_mgmr_set_listen_interval(uint16_t itv); 201 | int wifi_mgmr_pm_ops_register(void); 202 | int wifi_mgmr_fw_affair_ops(void); 203 | #endif 204 | -------------------------------------------------------------------------------- /examples/dhcp/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(c_variadic)] 4 | 5 | #[allow(non_camel_case_types, non_snake_case)] 6 | use core::{fmt::Write, mem::MaybeUninit}; 7 | 8 | use bl602_hal as hal; 9 | use core::panic::PanicInfo; 10 | use hal::{ 11 | clock::{Strict, SysclkFreq, UART_PLL_FREQ}, 12 | gpio::{Pin16, Pin7, Uart, Uart0Rx, Uart0Tx, UartMux0, UartMux7}, 13 | pac::{self, UART}, 14 | prelude::*, 15 | serial::*, 16 | }; 17 | use smoltcp::{ 18 | dhcp::Dhcpv4Client, 19 | iface::{NeighborCache, Routes}, 20 | socket::{RawPacketMetadata, RawSocketBuffer, TcpSocket, TcpSocketBuffer}, 21 | wire::{EthernetAddress, IpCidr, Ipv4Address, Ipv4Cidr}, 22 | }; 23 | 24 | use bl602_hal::timer::TimerExt; 25 | 26 | static mut GLOBAL_SERIAL: MaybeUninit< 27 | bl602_hal::serial::Serial< 28 | UART, 29 | ( 30 | (Pin16, UartMux0), 31 | (Pin7, UartMux7), 32 | ), 33 | >, 34 | > = MaybeUninit::uninit(); 35 | 36 | use bl602wifi::log::set_writer; 37 | use bl602wifi::println; 38 | use bl602wifi::timer::{timestamp, wifi_timer_init}; 39 | use bl602wifi::wifi::*; 40 | 41 | mod wifi_config; 42 | use wifi_config::WIFI_PASSWORD; 43 | use wifi_config::WIFI_SSID; 44 | 45 | #[riscv_rt::entry] 46 | fn main() -> ! { 47 | let dp = pac::Peripherals::take().unwrap(); 48 | let mut parts = dp.GLB.split(); 49 | 50 | let clocks = Strict::new() 51 | .use_pll(40_000_000u32.Hz()) 52 | .sys_clk(SysclkFreq::Pll160Mhz) 53 | .uart_clk(UART_PLL_FREQ.Hz()) 54 | .freeze(&mut parts.clk_cfg); 55 | 56 | // Set up uart output. Since this microcontroller has a pin matrix, 57 | // we need to set up both the pins and the muxs 58 | let pin16 = parts.pin16.into_uart_sig0(); 59 | let pin7 = parts.pin7.into_uart_sig7(); 60 | let mux0 = parts.uart_mux0.into_uart0_tx(); 61 | let mux7 = parts.uart_mux7.into_uart0_rx(); 62 | 63 | // Configure our UART to 115200 Baud, and use the pins we configured above 64 | let serial = Serial::uart0( 65 | dp.UART, 66 | Config::default().baudrate(115_200.Bd()), 67 | ((pin16, mux0), (pin7, mux7)), 68 | clocks, 69 | ); 70 | unsafe { 71 | *(GLOBAL_SERIAL.as_mut_ptr()) = serial; 72 | } 73 | 74 | set_writer(get_serial); 75 | 76 | println!("init"); 77 | 78 | wifi_pre_init(); 79 | 80 | let timers = dp.TIMER.split(); 81 | wifi_timer_init(timers.channel0, dp.HBN); 82 | 83 | let mut socket_set_entries: [_; 2] = Default::default(); 84 | let mut sockets = smoltcp::socket::SocketSet::new(&mut socket_set_entries[..]); 85 | let mut neighbor_cache_storage = [None; 8]; 86 | let neighbor_cache = NeighborCache::new(&mut neighbor_cache_storage[..]); 87 | 88 | let hw_address = EthernetAddress::from_bytes(&[0, 0, 0, 0, 0, 0]); 89 | let device = WifiDevice::new(); 90 | 91 | let ip_addr = IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0); 92 | let mut ip_addrs = [ip_addr]; 93 | 94 | let mut dhcp_rx_buff = [0u8; 900]; 95 | let mut dhcp_rx_metadata_storage = [RawPacketMetadata::EMPTY; 1]; 96 | let dhcp_rx_buffer = 97 | RawSocketBuffer::new(&mut dhcp_rx_metadata_storage[..], &mut dhcp_rx_buff[..]); 98 | let mut dhcp_tx_buff = [0u8; 600]; 99 | let mut dhcp_tx_metadata_storage = [RawPacketMetadata::EMPTY; 1]; 100 | let dhcp_tx_buffer = 101 | RawSocketBuffer::new(&mut dhcp_tx_metadata_storage[..], &mut dhcp_tx_buff[..]); 102 | let mut dhcp = Dhcpv4Client::new(&mut sockets, dhcp_rx_buffer, dhcp_tx_buffer, timestamp()); 103 | let mut prev_cidr = Ipv4Cidr::new(Ipv4Address::UNSPECIFIED, 0); 104 | 105 | let mut routes_storage = [None; 1]; 106 | let routes = Routes::new(&mut routes_storage[..]); 107 | 108 | let mut ethernet = smoltcp::iface::EthernetInterfaceBuilder::new(device) 109 | .ethernet_addr(hw_address) 110 | .neighbor_cache(neighbor_cache) 111 | .ip_addrs(&mut ip_addrs[..]) 112 | .routes(routes) 113 | .finalize(); 114 | 115 | wifi_init(); 116 | 117 | init_mac(&mut ethernet); 118 | 119 | println!("start connect"); 120 | 121 | connect_sta(WIFI_SSID, WIFI_PASSWORD); 122 | 123 | let greet_socket = { 124 | static mut TCP_SERVER_RX_DATA: [u8; 32] = [0; 32]; 125 | static mut TCP_SERVER_TX_DATA: [u8; 32] = [0; 32]; 126 | 127 | let tcp_rx_buffer = unsafe { TcpSocketBuffer::new(&mut TCP_SERVER_RX_DATA[..]) }; 128 | let tcp_tx_buffer = unsafe { TcpSocketBuffer::new(&mut TCP_SERVER_TX_DATA[..]) }; 129 | 130 | TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer) 131 | }; 132 | let greet_handle = sockets.add(greet_socket); 133 | 134 | // task should never return 135 | loop { 136 | let timestamp = timestamp(); 137 | riscv::interrupt::free(|_| { 138 | ethernet.poll(&mut sockets, timestamp).ok(); 139 | }); 140 | 141 | trigger_transmit_if_needed(); 142 | 143 | let config = dhcp 144 | .poll(&mut ethernet, &mut sockets, timestamp) 145 | .unwrap_or_else(|e| { 146 | println!("DHCP: {:?}", e); 147 | None 148 | }); 149 | 150 | config.map(|config| { 151 | println!("DHCP config: {:?}", config); 152 | if let Some(cidr) = config.address { 153 | if cidr != prev_cidr { 154 | ethernet.update_ip_addrs(|addrs| { 155 | addrs.iter_mut().next().map(|addr| { 156 | *addr = IpCidr::Ipv4(cidr); 157 | }); 158 | }); 159 | prev_cidr = cidr; 160 | println!("Assigned a new IPv4 address: {}", cidr); 161 | } 162 | } 163 | 164 | config.router.map(|router| { 165 | ethernet 166 | .routes_mut() 167 | .add_default_ipv4_route(router) 168 | .unwrap() 169 | }); 170 | ethernet.routes_mut().update(|routes_map| { 171 | routes_map 172 | .get(&IpCidr::new(Ipv4Address::UNSPECIFIED.into(), 0)) 173 | .map(|default_route| { 174 | println!("Default gateway: {}", default_route.via_router); 175 | }); 176 | }); 177 | 178 | if config.dns_servers.iter().any(|s| s.is_some()) { 179 | println!("DNS servers:"); 180 | for dns_server in config.dns_servers.iter().filter_map(|s| *s) { 181 | println!("- {}", dns_server); 182 | } 183 | } 184 | }); 185 | 186 | // Control the "greeting" socket (:4321) 187 | { 188 | let mut socket = sockets.get::(greet_handle); 189 | if !socket.is_open() { 190 | println!( 191 | "Listening to port 4321 for greeting, \ 192 | please connect to the port" 193 | ); 194 | socket.listen(4321).unwrap(); 195 | } 196 | 197 | if socket.can_send() { 198 | println!("Send and close."); 199 | socket.send_slice(SEND_RESPONSE).ok(); 200 | socket.close(); 201 | } 202 | } 203 | } 204 | } 205 | 206 | const SEND_RESPONSE: &[u8] = b"Hello BL602"; 207 | 208 | #[export_name = "ExceptionHandler"] 209 | fn custom_exception_handler(_trap_frame: &riscv_rt::TrapFrame) -> ! { 210 | /* 211 | 0 0 Instruction address misaligned 212 | 0 1 Instruction access fault 213 | 0 2 Illegal instruction 214 | 0 3 Breakpoint 215 | 0 4 Load address misaligned 216 | 0 5 Load access fault 217 | 0 6 Store/AMO address misaligned 218 | 0 7 Store/AMO access fault 219 | 0 8 Environment call from U-mode 220 | 0 9 Environment call from S-mode 221 | 0 10 Reserved 222 | 0 11 Environment call from M-mode 223 | 0 12 Instruction page fault 224 | 0 13 Load page fault 225 | 0 14 Reserved 226 | 0 15 Store/AMO page fault 227 | */ 228 | 229 | let mepc = riscv::register::mepc::read(); 230 | let code = riscv::register::mcause::read().code() & 0xff; 231 | println!("exception code {} at {:x}", code, mepc); 232 | loop {} 233 | } 234 | 235 | fn get_serial() -> &'static mut dyn core::fmt::Write { 236 | unsafe { &mut *GLOBAL_SERIAL.as_mut_ptr() } 237 | } 238 | 239 | #[panic_handler] 240 | fn panic_handler(info: &PanicInfo) -> ! { 241 | let serial = unsafe { &mut *(GLOBAL_SERIAL.as_mut_ptr()) }; 242 | write!(serial, "PANIC! {:?}\r\n", info).ok(); 243 | loop {} 244 | } 245 | -------------------------------------------------------------------------------- /nuttx/wifi_manager/wifi_mgmr.h: -------------------------------------------------------------------------------- 1 | #ifndef __WIFI_MGMR_H__ 2 | #define __WIFI_MGMR_H__ 3 | 4 | #include "bl_os_adapter/bl_os_private.h" 5 | 6 | #include "wifi_manager/include/wifi_mgmr_ext.h" 7 | #include "wifi_manager/stateMachine.h" 8 | 9 | #define WIFI_MGMR_SCAN_ITEMS_MAX (50) 10 | #define WIFI_MGMR_PROFILES_MAX (1) 11 | #define WIFI_MGMR_MQ_MSG_SIZE (128 + 64 + 32) 12 | #define WIFI_MGMR_MQ_MSG_COUNT (1) 13 | 14 | /** 15 | **************************************************************************************** 16 | * 17 | * @file wifi_mgmr.h 18 | * Copyright (C) Bouffalo Lab 2016-2018 19 | * 20 | **************************************************************************************** 21 | */ 22 | 23 | enum EVENT_TYPE { 24 | EVENT_TYPE_FW, 25 | EVENT_TYPE_APP, 26 | EVENT_TYPE_GLB, 27 | }; 28 | 29 | enum _WIFI_EVENT 30 | { 31 | CODE_WIFI_ON_INIT_DONE = 1, 32 | CODE_WIFI_ON_MGMR_DONE, 33 | CODE_WIFI_CMD_RECONNECT, 34 | CODE_WIFI_ON_CONNECTED, 35 | CODE_WIFI_ON_DISCONNECT, 36 | CODE_WIFI_ON_PRE_GOT_IP, 37 | CODE_WIFI_ON_GOT_IP, 38 | CODE_WIFI_ON_CONNECTING, 39 | CODE_WIFI_ON_SCAN_DONE, 40 | CODE_WIFI_ON_SCAN_DONE_ONJOIN, 41 | CODE_WIFI_ON_AP_STARTED, 42 | CODE_WIFI_ON_AP_STOPPED, 43 | CODE_WIFI_ON_PROV_SSID, 44 | CODE_WIFI_ON_PROV_BSSID, 45 | CODE_WIFI_ON_PROV_PASSWD, 46 | CODE_WIFI_ON_PROV_CONNECT, 47 | CODE_WIFI_ON_PROV_DISCONNECT, 48 | CODE_WIFI_ON_PROV_SCAN_START, 49 | CODE_WIFI_ON_PROV_STATE_GET, 50 | CODE_WIFI_ON_MGMR_DENOISE, 51 | CODE_WIFI_ON_AP_STA_ADD, 52 | CODE_WIFI_ON_AP_STA_DEL, 53 | CODE_WIFI_ON_EMERGENCY_MAC, 54 | }; 55 | 56 | typedef enum WIFI_MGMR_EVENT { 57 | /*section for wifi manager event*/ 58 | WIFI_MGMR_EVENT_APP_IDLE = 0, 59 | WIFI_MGMR_EVENT_APP_CONNECT, 60 | WIFI_MGMR_EVENT_APP_SNIFFER, 61 | WIFI_MGMR_EVENT_APP_CONNECTED, 62 | WIFI_MGMR_EVENT_APP_IP_GOT, 63 | WIFI_MGMR_EVENT_APP_DISCONNECT, 64 | WIFI_MGMR_EVENT_APP_RECONNECT, 65 | WIFI_MGMR_EVENT_APP_PHY_UP, 66 | WIFI_MGMR_EVENT_APP_AP_START, 67 | WIFI_MGMR_EVENT_APP_AP_STOP, 68 | WIFI_MGMR_EVENT_APP_CONF_MAX_STA, 69 | WIFI_MGMR_EVENT_APP_RC_CONFIG, 70 | WIFI_MGMR_EVENT_APP_DENOISE, 71 | WIFI_MGMR_EVENT_APP_RELOAD_TSEN, 72 | 73 | /*boundary between APP and FW*/ 74 | WIFI_MGMR_EVENT_MAXAPP_MINIFW, 75 | 76 | /*section for sending FW command event*/ 77 | WIFI_MGMR_EVENT_FW_DISCONNECT, 78 | WIFI_MGMR_EVENT_FW_POWERSAVING, 79 | WIFI_MGMR_EVENT_FW_CHANNEL_SET, 80 | WIFI_MGMR_EVENT_FW_SCAN, 81 | WIFI_MGMR_EVENT_FW_IND_DISCONNECT, 82 | WIFI_MGMR_EVENT_FW_IND_CONNECTED, 83 | WIFI_MGMR_EVENT_FW_DATA_RAW_SEND, 84 | WIFI_MGMR_EVENT_FW_CFG_REQ, 85 | 86 | /*boundary between APP and Global handled EVENT*/ 87 | WIFI_MGMR_EVENT_MAXFW_MINI_GLOBAL, 88 | 89 | /*section for sending global handled event*/ 90 | WIFI_MGMR_EVENT_GLB_SCAN_IND_BEACON, 91 | WIFI_MGMR_EVENT_GLB_SCAN_IND_PROBE_RESP, 92 | WIFI_MGMR_EVENT_GLB_AP_IND_STA_NEW, 93 | WIFI_MGMR_EVENT_GLB_AP_IND_STA_DEL, 94 | WIFI_MGMR_EVENT_GLB_DISABLE_AUTORECONNECT, 95 | WIFI_MGMR_EVENT_GLB_ENABLE_AUTORECONNECT, 96 | WIFI_MGMR_EVENT_GLB_IP_UPDATE, 97 | WIFI_MGMR_EVENT_GLB_MGMR_WAKEUP, 98 | 99 | } WIFI_MGMR_EVENT_T; 100 | 101 | typedef enum WIFI_MGMR_CONNECTION_STATUS { 102 | WIFI_MGMR_CONNECTION_STATUS_IDLE, 103 | WIFI_MGMR_CONNECTION_STATUS_CONNECTING, 104 | WIFI_MGMR_CONNECTION_STATUS_CONNECTED_IP_YES, 105 | WIFI_MGMR_CONNECTION_STATUS_CONNECTED_IP_NO, 106 | WIFI_MGMR_CONNECTION_STATUS_DISCONNECTED, 107 | } WIFI_MGMR_CONNECTION_STATUS_T; 108 | 109 | #pragma pack(push, 1) 110 | typedef struct wifi_mgmr_msg { 111 | WIFI_MGMR_EVENT_T ev; 112 | void *data1; 113 | void *data2; 114 | uint32_t len; 115 | uint8_t data[0]; 116 | } wifi_mgmr_msg_t; 117 | 118 | typedef struct wifi_mgmr_cfg_element_msg { 119 | uint32_t ops; 120 | uint32_t task; 121 | uint32_t element; 122 | uint32_t type; 123 | uint32_t length; 124 | uint32_t buf[]; 125 | } wifi_mgmr_cfg_element_msg_t; 126 | 127 | typedef struct wifi_mgmr_profile_msg { 128 | char ssid[32]; 129 | char ssid_tail[1]; 130 | uint32_t ssid_len; 131 | char passphr[64]; 132 | char passphr_tail[1]; 133 | char psk[64]; 134 | char psk_tail[1]; 135 | uint32_t passphr_len; 136 | uint32_t psk_len; 137 | 138 | uint8_t bssid[6]; 139 | uint8_t band; 140 | uint16_t freq; 141 | 142 | int ap_info_ttl; 143 | } wifi_mgmr_profile_msg_t; 144 | 145 | typedef struct wifi_mgmr_ipgot_msg { 146 | uint32_t ip; 147 | uint32_t mask; 148 | uint32_t gw; 149 | uint32_t dns1; 150 | uint32_t dns2; 151 | } wifi_mgmr_ipgot_msg_t; 152 | 153 | typedef struct wifi_mgmr_ap_msg { 154 | int32_t channel; 155 | char ssid[32]; 156 | char ssid_tail[1]; 157 | uint8_t hidden_ssid; 158 | uint32_t ssid_len; 159 | char psk[64]; 160 | char psk_tail[1]; 161 | uint32_t psk_len; 162 | } wifi_mgmr_ap_msg_t; 163 | 164 | #pragma pack(pop) 165 | 166 | typedef struct wifi_mgmr_profile { 167 | uint16_t ssid_len; 168 | uint16_t passphr_len; 169 | uint16_t psk_len; 170 | char ssid[33]; 171 | //uint8_t no_autoconnect; 172 | char passphr[65]; 173 | char psk[65]; 174 | 175 | uint8_t bssid[6]; 176 | uint8_t band; 177 | uint16_t freq; 178 | int ap_info_ttl; 179 | 180 | /*reserved field for wifi manager*/ 181 | uint8_t priority; 182 | uint8_t isActive; 183 | uint8_t isUsed; 184 | } wifi_mgmr_profile_t; 185 | 186 | 187 | typedef struct 188 | { 189 | uint8_t wep40 : 1; 190 | uint8_t wep104 : 1; 191 | uint8_t tkip : 1; 192 | uint8_t ccmp : 1; 193 | uint8_t rsvd : 4; 194 | } wifi_mgmr_cipher_t; 195 | 196 | typedef struct wifi_mgmr_scan_item { 197 | uint32_t timestamp_lastseen; 198 | uint16_t ssid_len; 199 | uint8_t channel; 200 | int8_t rssi; 201 | char ssid[32]; 202 | char ssid_tail[1];//always put ssid_tail after ssid 203 | uint8_t bssid[6]; 204 | int8_t ppm_abs; 205 | int8_t ppm_rel; 206 | uint8_t auth; 207 | uint8_t cipher; 208 | uint8_t is_used; 209 | } wifi_mgmr_scan_item_t; 210 | 211 | struct wlan_netif { 212 | int mode;//0: sta; 1: ap 213 | uint8_t vif_index; 214 | uint8_t mac[6]; 215 | /* Customer Data */ 216 | void *opaque; 217 | 218 | union { 219 | struct { 220 | int8_t rssi; 221 | } sta; 222 | }; 223 | }; 224 | 225 | #define MAX_FIXED_CHANNELS_LIMIT (14) 226 | typedef struct wifi_mgmr_scan_params { 227 | uint16_t channel_num; 228 | uint16_t channels[MAX_FIXED_CHANNELS_LIMIT]; 229 | char ssid[32]; 230 | char ssid_end; 231 | } wifi_mgmr_scan_params_t; 232 | 233 | typedef struct wifi_mgmr_connect_ind_stat_info { 234 | uint16_t status_code; 235 | uint16_t reason_code; 236 | uint16_t chan_freq; 237 | /*mgmr recv ind event from fw when connect or disconnect */ 238 | #define WIFI_MGMR_CONNECT_IND_STAT_INFO_TYPE_IND_CONNECTION (1) 239 | #define WIFI_MGMR_CONNECT_IND_STAT_INFO_TYPE_IND_DISCONNECTION (2) 240 | char ssid[32]; 241 | char passphr[65]; 242 | uint8_t bssid[6]; 243 | uint8_t type_ind; 244 | uint8_t chan_band; 245 | } wifi_mgmr_connect_ind_stat_info_t; 246 | 247 | typedef struct wifi_mgmr_sta_basic_info { 248 | uint8_t sta_idx; 249 | uint8_t is_used;; 250 | uint8_t sta_mac[6]; 251 | uint32_t tsfhi; 252 | uint32_t tsflo; 253 | int rssi; 254 | uint8_t data_rate; 255 | } wifi_mgmr_sta_basic_info_t; 256 | 257 | typedef struct wifi_mgmr { 258 | /*filed for PHY*/ 259 | int channel; 260 | int inf_ap_enabled; 261 | 262 | struct wlan_netif wlan_sta; 263 | struct wlan_netif wlan_ap; 264 | WIFI_MGMR_CONNECTION_STATUS_T status; 265 | /*profiles*/ 266 | wifi_mgmr_profile_t profiles[WIFI_MGMR_PROFILES_MAX]; 267 | int profile_active_index; 268 | 269 | wifi_mgmr_scan_item_t scan_items[WIFI_MGMR_SCAN_ITEMS_MAX]; 270 | //mqd_t mq; 271 | void *mq_f; 272 | struct stateMachine m; 273 | void *timer; 274 | wifi_mgmr_connect_ind_stat_info_t wifi_mgmr_stat_info; 275 | uint8_t ready;//TODO mgmr init process 276 | char country_code[3]; 277 | uint8_t disable_autoreconnect; 278 | uint16_t ap_bcn_int; 279 | int channel_nums; 280 | 281 | int ap_info_ttl_curr; 282 | 283 | /*pending task*/ 284 | union { 285 | uint32_t val; 286 | struct { 287 | #define WIFI_MGMR_PENDING_TASK_SCAN_BIT (1 << 0) 288 | #define WIFI_MGMR_PENDING_TASK_IP_UPDATE_BIT (1 << 1) 289 | #define WIFI_MGMR_PENDING_TASK_IP_GOT_BIT (1 << 2) 290 | unsigned int scan : 1; 291 | unsigned int ip_update : 1; 292 | unsigned int ip_got : 1; 293 | } bits; 294 | } pending_task; 295 | /*Feature Bits*/ 296 | uint32_t features; 297 | #define WIFI_MGMR_FEATURES_SCAN_SAVE_HIDDEN_SSID (1 << 0) 298 | 299 | /*Manager config*/ 300 | int scan_item_timeout; 301 | #define WIFI_MGMR_CONFIG_SCAN_ITEM_TIMEOUT (15000) 302 | #define MAX_HOSTNAME_LEN_CHECK 32 303 | char hostname[MAX_HOSTNAME_LEN_CHECK]; 304 | } wifi_mgmr_t; 305 | 306 | int wifi_mgmr_event_notify(wifi_mgmr_msg_t *msg); 307 | int wifi_mgmr_state_get_internal(int *state); 308 | int wifi_mgmr_status_code_clean_internal(void); 309 | int wifi_mgmr_status_code_get_internal(int *s_code); 310 | int wifi_mgmr_set_country_code_internal(char *country_code); 311 | int wifi_mgmr_ap_sta_cnt_get_internal(uint8_t *sta_cnt); 312 | int wifi_mgmr_ap_sta_info_get_internal(wifi_mgmr_sta_basic_info_t *sta_info_internal, uint8_t idx); 313 | int wifi_mgmr_ap_sta_delete_internal(uint8_t sta_idx); 314 | int wifi_mgmr_scan_complete_notify(void); 315 | extern wifi_mgmr_t wifiMgmr; 316 | char *wifi_mgmr_auth_to_str(uint8_t auth); 317 | char *wifi_mgmr_cipher_to_str(uint8_t cipher); 318 | int wifi_mgmr_api_fw_tsen_reload(void); 319 | 320 | static inline int wifi_mgmr_scan_item_is_timeout(wifi_mgmr_t *mgmr, wifi_mgmr_scan_item_t *item) 321 | { 322 | return ((unsigned int)g_bl_ops_funcs._get_time_ms() - (unsigned int)item->timestamp_lastseen) >= mgmr->scan_item_timeout ? 1 : 0; 323 | } 324 | #endif 325 | -------------------------------------------------------------------------------- /memory.x: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH( "riscv" ) 2 | 3 | PROVIDE(ble_controller_init, 1); 4 | 5 | __EM_SIZE = DEFINED(ble_controller_init) ? 8K : 0K; 6 | __RFTLV_SIZE_OFFSET = 1K; 7 | __RFTLV_SIZE_HOLE = 2K; 8 | __RFTLV_HEAD1_H = (0x46524C42); /* BLRF */ 9 | __RFTLV_HEAD1_L = (0x41524150); /* PAPA */ 10 | 11 | MEMORY 12 | { 13 | ROM (rx) : ORIGIN = 0x21015000, LENGTH = 44K 14 | /* ITCM (wxa) : ORIGIN = 0x22008000, LENGTH = 48K */ 15 | DTCM (wxa) : ORIGIN = 0x42010000, LENGTH = (32K + 48K + 64K - 16K) /* itcm_32 + dtcm_48 + ocram_64 */ 16 | XIP_FLASH (rwx) : ORIGIN = 0x23000000, LENGTH = 4M 17 | WIFI_RAM (wxa) : ORIGIN = 0x42030000, LENGTH = (112K - 8K) /* 8K left for em */ 18 | } 19 | 20 | REGION_ALIAS("REGION_TEXT", XIP_FLASH); 21 | REGION_ALIAS("REGION_RODATA", XIP_FLASH); 22 | REGION_ALIAS("REGION_DATA", DTCM); 23 | REGION_ALIAS("REGION_BSS", DTCM); 24 | REGION_ALIAS("REGION_HEAP", DTCM); 25 | REGION_ALIAS("REGION_STACK", DTCM); 26 | 27 | PROVIDE(_stext = ORIGIN(REGION_TEXT)); 28 | PROVIDE(_stack_start = ORIGIN(REGION_STACK) + LENGTH(REGION_STACK)); 29 | PROVIDE(_max_hart_id = 0); 30 | PROVIDE(_hart_stack_size = 2K); 31 | PROVIDE(_heap_size = 16k); 32 | 33 | PROVIDE(UserSoft = DefaultHandler); 34 | PROVIDE(SupervisorSoft = DefaultHandler); 35 | PROVIDE(MachineSoft = DefaultHandler); 36 | PROVIDE(UserTimer = DefaultHandler); 37 | PROVIDE(SupervisorTimer = DefaultHandler); 38 | PROVIDE(MachineTimer = DefaultHandler); 39 | PROVIDE(UserExternal = DefaultHandler); 40 | PROVIDE(SupervisorExternal = DefaultHandler); 41 | PROVIDE(MachineExternal = DefaultHandler); 42 | 43 | PROVIDE(DefaultHandler = DefaultInterruptHandler); 44 | PROVIDE(ExceptionHandler = DefaultExceptionHandler); 45 | 46 | /* # Pre-initialization function */ 47 | /* If the user overrides this using the `#[pre_init]` attribute or by creating a `__pre_init` function, 48 | then the function this points to will be called before the RAM is initialized. */ 49 | PROVIDE(__pre_init = default_pre_init); 50 | 51 | /* A PAC/HAL defined routine that should initialize custom interrupt controller if needed. */ 52 | PROVIDE(_setup_interrupts = default_setup_interrupts); 53 | 54 | /* # Multi-processing hook function 55 | fn _mp_hook() -> bool; 56 | 57 | This function is called from all the harts and must return true only for one hart, 58 | which will perform memory initialization. For other harts it must return false 59 | and implement wake-up in platform-dependent way (e.g. after waiting for a user interrupt). 60 | */ 61 | PROVIDE(_mp_hook = default_mp_hook); 62 | 63 | SECTIONS 64 | { 65 | 66 | .init : 67 | { 68 | KEEP (*(SORT_NONE(.init))) 69 | } > REGION_TEXT 70 | 71 | .rftlv.tool : 72 | { 73 | . = ORIGIN(REGION_TEXT) + __RFTLV_SIZE_OFFSET; 74 | PROVIDE( _ld_symbol_rftlv_address = . ); 75 | /* 76 | LONG(__RFTLV_HEAD1_H); 77 | LONG(__RFTLV_HEAD1_L); 78 | */ 79 | INCLUDE "rfparams.ld" ; 80 | /* . = ORIGIN(REGION_TEXT) + __RFTLV_SIZE_OFFSET + __RFTLV_SIZE_HOLE; */ 81 | } > REGION_TEXT 82 | 83 | .text : 84 | { 85 | PROVIDE(_stext = .); 86 | *(.text.unlikely .text.unlikely.*) 87 | *(.text.startup .text.startup.*) 88 | 89 | /* Put reset handler first in .text section so it ends up as the entry */ 90 | /* point of the program. */ 91 | KEEP(*(.init)); 92 | KEEP(*(.init.rust)); 93 | . = ALIGN(4); 94 | (*(.trap)); 95 | (*(.trap.rust)); 96 | 97 | 98 | *(.text .text.*); 99 | } > REGION_TEXT 100 | 101 | .rodata : ALIGN(4) 102 | { 103 | *(.srodata .srodata.*); 104 | *(.rodata .rodata.*); 105 | *(.rdata) 106 | *(.sdata2.*) 107 | 108 | /* static fw attribute entry */ 109 | . = ALIGN(4); 110 | _bl_static_fw_cfg_entry_start = .; 111 | KEEP(*(.wifi.cfg.entry)) 112 | _bl_static_fw_cfg_entry_end = .; 113 | 114 | /* 4-byte align the end (VMA) of this section. 115 | This is required by LLD to ensure the LMA of the following .data 116 | section will have the correct alignment. */ 117 | . = ALIGN(4); 118 | } > REGION_RODATA 119 | 120 | .preinit_array : 121 | { 122 | . = ALIGN(4); 123 | __preinit_array_start = .; 124 | KEEP (*(.preinit_array)) 125 | __preinit_array_end = .; 126 | } > REGION_RODATA 127 | 128 | .init_array : 129 | { 130 | . = ALIGN(4); 131 | __init_array_start = .; 132 | _sinit = .; 133 | KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*))) 134 | KEEP (*(.init_array)) 135 | __init_array_end = .; 136 | _einit = .; 137 | } > REGION_RODATA 138 | 139 | 140 | /*put wifibss in the first place*/ 141 | .wifibss (NOLOAD) : 142 | { 143 | __wifi_bss_start = .; 144 | /*PROVIDE( __wifi_bss_start = ADDR(.wifibss) ); 145 | PROVIDE( __wifi_bss_end = ADDR(.wifibss) + SIZEOF(.wifibss) );*/ 146 | *ipc_shared.o(COMMON) 147 | *sdu_shared.o(COMMON) 148 | *hal_desc.o(COMMON) 149 | *txl_buffer_shared.o(COMMON) 150 | *txl_frame_shared.o(COMMON) 151 | *scan_shared.o(COMMON) 152 | *scanu_shared.o(COMMON) 153 | *mfp_bip.o(COMMON) 154 | *me_mic.o(COMMON) 155 | *bl_sta_mgmt_others.o(COMMON) 156 | *bl_pmk_mgmt.o(COMMON) 157 | *bl_pmk_mgmt_internal.o(COMMON) 158 | *libwifi_drv.a:bl_utils.o(COMMON) 159 | *libwifi_drv.a:bl_utils.o(.bss*) 160 | *(.wifi_ram*) 161 | . = ALIGN(16); 162 | __wifi_bss_end = .; 163 | } > WIFI_RAM 164 | 165 | PROVIDE( _heap_wifi_start = . ); 166 | PROVIDE( _heap_wifi_size = ORIGIN(WIFI_RAM) + LENGTH(WIFI_RAM) - _heap_wifi_start ); 167 | 168 | /* 169 | .romdata : 170 | { 171 | PROVIDE( __global_pointer$ = . + 0x7F0 ); 172 | . = . + 0x498; 173 | } > REGION_DATA AT > REGION_RODATA 174 | */ 175 | 176 | .data : ALIGN(4) 177 | { 178 | _sidata = LOADADDR(.data); 179 | _sdata = .; 180 | 181 | PROVIDE( __global_pointer$ = . + 0x7F0 ); 182 | . = . + 0x498; 183 | 184 | *(.tcm_code) 185 | *(.tcm_const) 186 | *(.sclock_rlt_code) 187 | *(.sclock_rlt_const) 188 | *(.data .data.*) 189 | *(.gnu.linkonce.d.*) 190 | 191 | *(.sdata .sdata.* .sdata2 .sdata2.*); 192 | 193 | 194 | . = ALIGN(8); 195 | *(.srodata.cst16) 196 | *(.srodata.cst8) 197 | *(.srodata.cst4) 198 | *(.srodata.cst2) 199 | *(.srodata .srodata.*) 200 | 201 | . = ALIGN(8); 202 | *(._k_queue.static.*) 203 | *(._k_sem.static.*) 204 | *(._k_mutex.static.*) 205 | _net_buf_pool_list = .; 206 | KEEP(*(SORT_BY_NAME("._net_buf_pool.static.*"))) 207 | _bt_gatt_service_static_list_start = .; 208 | KEEP(*(SORT_BY_NAME("._bt_gatt_service_static.static.*"))) 209 | _bt_gatt_service_static_list_end = .; 210 | _bt_l2cap_fixed_chan_list_start = .; 211 | KEEP(*(SORT_BY_NAME("._bt_l2cap_fixed_chan.static.*"))) 212 | _bt_l2cap_fixed_chan_list_end = .; 213 | 214 | . = ALIGN(4); 215 | _edata = .; 216 | } > REGION_DATA AT > REGION_RODATA 217 | 218 | .boot2 (NOLOAD) : 219 | { 220 | PROVIDE ( __boot2_pt_addr_start = . ); 221 | *(.bss.g_boot2_partition_table) 222 | PROVIDE ( __boot2_pt_addr_end = . ); 223 | 224 | PROVIDE ( __boot2_flash_cfg_start = . ); 225 | *(.bss.g_bl602_romflash_cfg) 226 | PROVIDE ( __boot2_flash_cfg_end = . ); 227 | } > REGION_DATA 228 | 229 | 230 | .noinit (NOLOAD) : 231 | { 232 | . = ALIGN(16); 233 | *(.noinit_idle_stack*) 234 | } > REGION_DATA 235 | 236 | 237 | 238 | .bss (NOLOAD) : 239 | { 240 | _sbss = .; 241 | *(.sbss .sbss.* .bss .bss.*); 242 | *(COMMON) 243 | 244 | . = ALIGN(4); 245 | _ebss = .; 246 | } > REGION_BSS 247 | 248 | . = ALIGN(4); 249 | 250 | /* fictitious region that represents the memory available for the heap */ 251 | .heap (NOLOAD) : 252 | { 253 | _sheap = .; 254 | . += _heap_size; 255 | . = ALIGN(4); 256 | _eheap = .; 257 | } > REGION_HEAP 258 | 259 | /* fictitious region that represents the memory available for the stack */ 260 | .stack (NOLOAD) : 261 | { 262 | _estack = .; 263 | . = ABSOLUTE(_stack_start); 264 | _sstack = .; 265 | } > REGION_STACK 266 | 267 | /* fake output .got section */ 268 | /* Dynamic relocations are unsupported. This section is only used to detect 269 | relocatable code in the input files and raise an error if relocatable code 270 | is found */ 271 | .got (INFO) : 272 | { 273 | KEEP(*(.got .got.*)); 274 | } 275 | 276 | 277 | 278 | 279 | .eh_frame (INFO) : { KEEP(*(.eh_frame)) } 280 | .eh_frame_hdr (INFO) : { *(.eh_frame_hdr) } 281 | } 282 | 283 | 284 | /*CFG FW used in code*/ 285 | PROVIDE( _ld_bl_static_cfg_entry_start = _bl_static_fw_cfg_entry_start ); 286 | PROVIDE( _ld_bl_static_cfg_entry_end = _bl_static_fw_cfg_entry_end ); 287 | 288 | 289 | 290 | PROVIDE(_wifi_log_flag = 1); 291 | 292 | 293 | /* Do not exceed this mark in the error messages above | */ 294 | ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, " 295 | ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned"); 296 | 297 | ASSERT(ORIGIN(REGION_RODATA) % 4 == 0, " 298 | ERROR(riscv-rt): the start of the REGION_RODATA must be 4-byte aligned"); 299 | 300 | ASSERT(ORIGIN(REGION_DATA) % 4 == 0, " 301 | ERROR(riscv-rt): the start of the REGION_DATA must be 4-byte aligned"); 302 | 303 | ASSERT(ORIGIN(REGION_HEAP) % 4 == 0, " 304 | ERROR(riscv-rt): the start of the REGION_HEAP must be 4-byte aligned"); 305 | 306 | ASSERT(ORIGIN(REGION_TEXT) % 4 == 0, " 307 | ERROR(riscv-rt): the start of the REGION_TEXT must be 4-byte aligned"); 308 | 309 | ASSERT(ORIGIN(REGION_STACK) % 4 == 0, " 310 | ERROR(riscv-rt): the start of the REGION_STACK must be 4-byte aligned"); 311 | 312 | ASSERT(_stext % 4 == 0, " 313 | ERROR(riscv-rt): `_stext` must be 4-byte aligned"); 314 | 315 | ASSERT(_sdata % 4 == 0 && _edata % 4 == 0, " 316 | BUG(riscv-rt): .data is not 4-byte aligned"); 317 | 318 | ASSERT(_sidata % 4 == 0, " 319 | BUG(riscv-rt): the LMA of .data is not 4-byte aligned"); 320 | 321 | ASSERT(_sbss % 4 == 0 && _ebss % 4 == 0, " 322 | BUG(riscv-rt): .bss is not 4-byte aligned"); 323 | 324 | ASSERT(_sheap % 4 == 0, " 325 | BUG(riscv-rt): start of .heap is not 4-byte aligned"); 326 | 327 | ASSERT(_stext + SIZEOF(.text) < ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT), " 328 | ERROR(riscv-rt): The .text section must be placed inside the REGION_TEXT region. 329 | Set _stext to an address smaller than 'ORIGIN(REGION_TEXT) + LENGTH(REGION_TEXT)'"); 330 | 331 | ASSERT(SIZEOF(.stack) > (_max_hart_id + 1) * _hart_stack_size, " 332 | ERROR(riscv-rt): .stack section is too small for allocating stacks for all the harts. 333 | Consider changing `_max_hart_id` or `_hart_stack_size`."); 334 | 335 | ASSERT(SIZEOF(.got) == 0, " 336 | .got section detected in the input files. Dynamic relocations are not 337 | supported. If you are linking to C code compiled using the `gcc` crate 338 | then modify your build script to compile the C code _without_ the 339 | -fPIC flag. See the documentation of the `gcc::Config.fpic` method for 340 | details."); 341 | 342 | /* Do not exceed this mark in the error messages above | */ -------------------------------------------------------------------------------- /src/compat/common.rs: -------------------------------------------------------------------------------- 1 | use crate::{binary::c_types::c_void, log, print}; 2 | use core::{ffi::VaListImpl, fmt::Write}; 3 | 4 | static mut MUTEXES: [Option<*mut u8>; 1] = [None]; 5 | pub static mut EMULATED_TIMER: [Option; 2] = [None; 2]; 6 | 7 | pub struct StrBuf { 8 | buffer: [u8; 512], 9 | len: usize, 10 | } 11 | 12 | impl StrBuf { 13 | pub fn new() -> StrBuf { 14 | StrBuf { 15 | buffer: [0u8; 512], 16 | len: 0, 17 | } 18 | } 19 | 20 | pub unsafe fn from(c_str: *const u8) -> StrBuf { 21 | let mut res = StrBuf { 22 | buffer: [0u8; 512], 23 | len: 0, 24 | }; 25 | 26 | let mut idx: usize = 0; 27 | while *(c_str.offset(idx as isize)) != 0 { 28 | res.buffer[idx] = *(c_str.offset(idx as isize)); 29 | idx += 1; 30 | } 31 | 32 | res.len = idx; 33 | res 34 | } 35 | 36 | pub unsafe fn append_from(&mut self, c_str: *const u8) { 37 | let mut src_idx: usize = 0; 38 | let mut idx: usize = self.len; 39 | while *(c_str.offset(src_idx as isize)) != 0 { 40 | self.buffer[idx] = *(c_str.offset(src_idx as isize)); 41 | idx += 1; 42 | src_idx += 1; 43 | } 44 | 45 | self.len = idx; 46 | } 47 | 48 | pub fn append(&mut self, s: &str) { 49 | let mut idx: usize = self.len; 50 | s.chars().for_each(|c| { 51 | self.buffer[idx] = c as u8; 52 | idx += 1; 53 | }); 54 | self.len = idx; 55 | } 56 | 57 | pub fn append_char(&mut self, c: char) { 58 | let mut idx: usize = self.len; 59 | self.buffer[idx] = c as u8; 60 | idx += 1; 61 | self.len = idx; 62 | } 63 | 64 | pub unsafe fn as_str_ref(&self) -> &str { 65 | core::str::from_utf8_unchecked(&self.buffer[..self.len]) 66 | } 67 | } 68 | 69 | impl Write for StrBuf { 70 | fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { 71 | self.append(s); 72 | Ok(()) 73 | } 74 | } 75 | 76 | #[no_mangle] 77 | pub unsafe extern "C" fn syslog(_priority: u32, mut args: ...) { 78 | log!("syslog called"); 79 | 80 | let mut buf = [0u8; 512]; 81 | vsnprintf( 82 | &mut buf as *mut u8, 83 | 511, 84 | args.arg::() as *const u8, 85 | args, 86 | ); 87 | let res_str = StrBuf::from(&buf as *const u8); 88 | print!("{}", res_str.as_str_ref()); 89 | } 90 | 91 | #[no_mangle] 92 | pub unsafe extern "C" fn pthread_mutex_init(mutex: *mut u8, attr: *mut u8) -> i32 { 93 | log!("pthread_mutex_init called {:p} {:p}", mutex, attr); 94 | 95 | 0 96 | } 97 | 98 | #[no_mangle] 99 | pub unsafe extern "C" fn pthread_mutex_lock(mutex: *mut u8) -> i32 { 100 | log!("pthread_mutex_lock called {:p}", mutex); 101 | 102 | // TODO check if it's the mutex in question 103 | while riscv::interrupt::free(|_| MUTEXES[0].is_some()) { 104 | // wait... 105 | } 106 | riscv::interrupt::free(|_| MUTEXES[0] = Some(mutex)); 107 | 108 | 0 109 | } 110 | 111 | #[no_mangle] 112 | pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut u8) -> i32 { 113 | log!("pthread_mutex_unlock called {:p}", mutex); 114 | 115 | riscv::interrupt::free(|_| MUTEXES[0] = None); 116 | 0 117 | } 118 | 119 | #[no_mangle] 120 | pub unsafe extern "C" fn nanosleep() { 121 | unimplemented!("nanosleep"); 122 | } 123 | 124 | #[no_mangle] 125 | pub unsafe extern "C" fn usleep(usec: u32) -> i32 { 126 | log!("usleep called {}", usec); 127 | 128 | // not nearly accurate 129 | for _ in 0..usec * 10 {} 130 | 131 | 0 132 | } 133 | 134 | #[no_mangle] 135 | pub unsafe extern "C" fn sleep(sec: u32) -> i32 { 136 | log!("sleep called {}", sec); 137 | 138 | usleep(sec * 1000); 139 | 140 | 0 141 | } 142 | 143 | #[repr(C)] 144 | pub union sigval { 145 | sival_int: i32, /* Integer value */ 146 | sival_ptr: *const c_void, /* Pointer value */ 147 | } 148 | 149 | #[repr(C)] 150 | pub struct pthread_attr_s { 151 | priority: u8, /* Priority of the pthread */ 152 | policy: u8, /* Pthread scheduler policy */ 153 | inheritsched: u8, /* Inherit parent priority/policy? */ 154 | detachstate: u8, /* Initialize to the detach state */ 155 | low_priority: u8, /* Low scheduling priority */ 156 | max_repl: u8, /* Maximum pending replenishments */ 157 | 158 | stackaddr: *const c_void, /* Address of memory to be used as stack */ 159 | stacksize: usize, /* Size of the stack allocated for the pthread */ 160 | } 161 | 162 | #[repr(C)] 163 | pub struct sigevent { 164 | sigev_notify: u8, /* Notification method: SIGEV_SIGNAL, SIGEV_NONE, or SIGEV_THREAD */ 165 | sigev_signo: u8, /* Notification signal */ 166 | sigev_value: sigval, /* Data passed with notification */ 167 | 168 | sigev_notify_function: fn(), /* Notification function */ 169 | sigev_notify_attributes: *const pthread_attr_s, /* Notification attributes (not used) */ 170 | } 171 | 172 | #[derive(Debug, Clone, Copy)] 173 | pub struct EmulatedTimer { 174 | pub notify_function: fn(), 175 | pub interval_secs: u32, 176 | pub next_notify: u32, 177 | } 178 | 179 | #[no_mangle] 180 | pub unsafe extern "C" fn printf(s: *const u8, args: ...) { 181 | log!("printf called"); 182 | 183 | syslog(0, s, args); 184 | } 185 | 186 | #[no_mangle] 187 | pub unsafe extern "C" fn strlen(s: *const u8) -> i32 { 188 | log!("strlen called"); 189 | 190 | let mut i = 0; 191 | while *(s.offset(i)) != 0 { 192 | i += 1; 193 | } 194 | 195 | i as i32 196 | } 197 | 198 | #[no_mangle] 199 | pub unsafe extern "C" fn snprintf(dst: *mut u8, n: u32, format: *const u8, args: ...) { 200 | log!("snprintf called n={}", n); 201 | 202 | vsnprintf(dst, n, format, args); 203 | } 204 | 205 | pub(crate) unsafe fn vsnprintf(dst: *mut u8, _n: u32, format: *const u8, mut args: VaListImpl) { 206 | let fmt_str_ptr = format; 207 | 208 | let mut res_str = StrBuf::new(); 209 | 210 | let strbuf = StrBuf::from(fmt_str_ptr); 211 | let s = strbuf.as_str_ref(); 212 | 213 | let mut format_char = ' '; 214 | let mut is_long = false; 215 | let mut found = false; 216 | for c in s.chars().into_iter() { 217 | if found && format_char != ' ' { 218 | // have to format an arg 219 | match format_char { 220 | 'd' => { 221 | if is_long { 222 | let v = args.arg::(); 223 | write!(res_str, "{}", v).ok(); 224 | } else { 225 | let v = args.arg::(); 226 | write!(res_str, "{}", v).ok(); 227 | } 228 | } 229 | 230 | 'u' => { 231 | let v = args.arg::(); 232 | write!(res_str, "{}", v).ok(); 233 | } 234 | 235 | 'p' => { 236 | let v = args.arg::(); 237 | write!(res_str, "0x{:x}", v).ok(); 238 | } 239 | 240 | 'X' => { 241 | let v = args.arg::(); 242 | write!(res_str, "{:2x}", v).ok(); 243 | } 244 | 245 | 'x' => { 246 | let v = args.arg::(); 247 | write!(res_str, "{:2x}", v).ok(); 248 | } 249 | 250 | 's' => { 251 | let v = args.arg::() as *const u8; 252 | let vbuf = StrBuf::from(v); 253 | write!(res_str, "{}", vbuf.as_str_ref()).ok(); 254 | } 255 | 256 | _ => { 257 | write!(res_str, "", format_char).ok(); 258 | } 259 | } 260 | 261 | format_char = ' '; 262 | found = false; 263 | is_long = false; 264 | } 265 | 266 | if !found { 267 | if c == '%' { 268 | found = true; 269 | } 270 | 271 | if !found { 272 | res_str.append_char(c); 273 | } 274 | } else { 275 | if c.is_numeric() || c == '-' || c == 'l' { 276 | if c == 'l' { 277 | is_long = true; 278 | } 279 | // ignore 280 | } else { 281 | // a format char 282 | format_char = c; 283 | } 284 | } 285 | } 286 | 287 | let mut idx = 0; 288 | res_str.as_str_ref().chars().for_each(|c| { 289 | *(dst.offset(idx)) = c as u8; 290 | idx += 1; 291 | }); 292 | *(dst.offset(idx)) = 0; 293 | } 294 | 295 | #[no_mangle] 296 | pub unsafe extern "C" fn puts(s: *const u8) { 297 | log!("puts called"); 298 | 299 | let mut str_buf = StrBuf::new(); 300 | let mut i = 0; 301 | while *(s.offset(i)) != 0 { 302 | str_buf.append_char(*(s.offset(i)) as char); 303 | i += 1; 304 | } 305 | 306 | print!("{}", str_buf.as_str_ref()); 307 | } 308 | 309 | #[no_mangle] 310 | pub unsafe extern "C" fn zalloc( 311 | size: crate::binary::c_types::c_uint, 312 | ) -> *mut crate::binary::c_types::c_void { 313 | crate::os_adapter::bl_os_zalloc(size) 314 | } 315 | 316 | #[no_mangle] 317 | pub unsafe extern "C" fn __errno() -> *mut i32 { 318 | log!("__errno called - not implemented"); 319 | &mut ERRNO 320 | } 321 | 322 | static mut ERRNO: i32 = 0; 323 | 324 | #[no_mangle] 325 | pub unsafe extern "C" fn __truncdfsf2(a: f64) -> f32 { 326 | log!("__truncdfsf2 called {}", a); 327 | 328 | // WORLD'S DUMBEST WAY TO CONVERT A DOUBLE TO FLOAT 329 | let mut str_buf = StrBuf::new(); 330 | write!(str_buf, "{}", a).ok(); 331 | let res = str_buf.as_str_ref().parse::().unwrap(); 332 | res 333 | } 334 | 335 | #[no_mangle] 336 | pub unsafe extern "C" fn strcmp(str1: *const u8, str2: *const u8) -> i32 { 337 | log!("strcmp called"); 338 | 339 | let mut fmt_str_ptr = str1; 340 | while *fmt_str_ptr != 0 { 341 | fmt_str_ptr = fmt_str_ptr.offset(1); 342 | } 343 | 344 | let mut fmt_str_ptr = str2; 345 | while *fmt_str_ptr != 0 { 346 | fmt_str_ptr = fmt_str_ptr.offset(1); 347 | } 348 | 349 | let mut i = 0; 350 | let mut a = 0u8; 351 | let mut b = 0u8; 352 | 353 | while *(str1.offset(i)) == *(str2.offset(i)) { 354 | a = *(str1.offset(i)); 355 | b = *(str2.offset(i)); 356 | 357 | if a == 0 && b == 0 { 358 | return 0; 359 | } 360 | 361 | i += 1; 362 | } 363 | 364 | if a < b { 365 | -1 366 | } else { 367 | 1 368 | } 369 | } 370 | 371 | #[no_mangle] 372 | pub unsafe extern "C" fn strncpy(dest: *mut u8, src: *const u8, n: u32) -> *const u8 { 373 | log!("strncpy called"); 374 | 375 | let mut dstidx = 0; 376 | for i in 0isize..n as isize { 377 | dstidx = i; 378 | *(dest.offset(i)) = *(src.offset(i)); 379 | if *(src.offset(i)) == 0 { 380 | break; 381 | } 382 | } 383 | 384 | if dstidx < n as isize { 385 | *(dest.offset(dstidx)) = 0; 386 | } 387 | 388 | dest 389 | } 390 | -------------------------------------------------------------------------------- /nuttx/wifi_manager/include/bitset.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 | * 4 | * Copyright (c) 2008, Jeffrey Roberson 5 | * All rights reserved. 6 | * 7 | * Copyright (c) 2008 Nokia Corporation 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 1. Redistributions of source code must retain the above copyright 14 | * notice unmodified, this list of conditions, and the following 15 | * disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | * 31 | * $FreeBSD$ 32 | */ 33 | 34 | #ifndef _SYS__BITSET_H_ 35 | #define _SYS__BITSET_H_ 36 | 37 | #if 0 38 | /* 39 | * Find First Set bit 40 | */ 41 | static inline int 42 | ffsl(long mask) { 43 | int bit; 44 | 45 | if (mask == 0) 46 | return (0); 47 | for (bit = 1; !(mask & 1); bit++) 48 | mask = (unsigned long)mask >> 1; 49 | return (bit); 50 | } 51 | 52 | /* 53 | * Find Last Set bit 54 | */ 55 | static inline int 56 | flsl(long mask) { 57 | int bit; 58 | 59 | if (mask == 0) 60 | return (0); 61 | for (bit = 1; mask != 1; bit++) 62 | mask = (unsigned long)mask >> 1; 63 | return (bit); 64 | } 65 | #endif 66 | 67 | #define __size_t _size_t 68 | 69 | /* 70 | * Macros addressing word and bit within it, tuned to make compiler 71 | * optimize cases when SETSIZE fits into single machine word. 72 | */ 73 | #define _BITSET_BITS (sizeof(long) * 8) 74 | 75 | #define __howmany(x, y) (((x) + ((y)-1)) / (y)) 76 | 77 | #define __bitset_words(_s) (__howmany(_s, _BITSET_BITS)) 78 | 79 | #define BITSET_DEFINE(t, _s) \ 80 | struct t { \ 81 | long __bits[__bitset_words((_s))]; \ 82 | } 83 | 84 | #define __bitset_mask(_s, n) \ 85 | (1L << ((__bitset_words((_s)) == 1) ? (__size_t)(n) : ((n) % _BITSET_BITS))) 86 | 87 | #define __bitset_word(_s, n) \ 88 | ((__bitset_words((_s)) == 1) ? 0 : ((n) / _BITSET_BITS)) 89 | 90 | #define BIT_CLR(_s, n, p) \ 91 | ((p)->__bits[__bitset_word(_s, n)] &= ~__bitset_mask((_s), (n))) 92 | 93 | #define BIT_ISSET(_s, n, p) \ 94 | ((((p)->__bits[__bitset_word(_s, n)] & __bitset_mask((_s), (n))) != 0)) 95 | 96 | #define BIT_SET(_s, n, p) \ 97 | ((p)->__bits[__bitset_word(_s, n)] |= __bitset_mask((_s), (n))) 98 | 99 | #define BIT_ZERO(_s, p) \ 100 | do { \ 101 | __size_t __i; \ 102 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 103 | (p)->__bits[__i] = 0L; \ 104 | } while (0) 105 | 106 | #define BIT_FILL(_s, p) \ 107 | do { \ 108 | __size_t __i; \ 109 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 110 | (p)->__bits[__i] = -1L; \ 111 | } while (0) 112 | 113 | #define BIT_SETOF(_s, n, p) \ 114 | do { \ 115 | BIT_ZERO(_s, p); \ 116 | (p)->__bits[__bitset_word(_s, n)] = __bitset_mask((_s), (n)); \ 117 | } while (0) 118 | 119 | /* Is p empty. */ 120 | #define BIT_EMPTY(_s, p) __extension__({ \ 121 | __size_t __i; \ 122 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 123 | if ((p)->__bits[__i]) \ 124 | break; \ 125 | __i == __bitset_words((_s)); \ 126 | }) 127 | 128 | /* Is p full set. */ 129 | #define BIT_ISFULLSET(_s, p) __extension__({ \ 130 | __size_t __i; \ 131 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 132 | if ((p)->__bits[__i] != (long)-1) \ 133 | break; \ 134 | __i == __bitset_words((_s)); \ 135 | }) 136 | 137 | /* Is c a subset of p. */ 138 | #define BIT_SUBSET(_s, p, c) __extension__({ \ 139 | __size_t __i; \ 140 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 141 | if (((c)->__bits[__i] & \ 142 | (p)->__bits[__i]) != \ 143 | (c)->__bits[__i]) \ 144 | break; \ 145 | __i == __bitset_words((_s)); \ 146 | }) 147 | 148 | /* Are there any common bits between b & c? */ 149 | #define BIT_OVERLAP(_s, p, c) __extension__({ \ 150 | __size_t __i; \ 151 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 152 | if (((c)->__bits[__i] & \ 153 | (p)->__bits[__i]) != 0) \ 154 | break; \ 155 | __i != __bitset_words((_s)); \ 156 | }) 157 | 158 | /* Compare two sets, returns 0 if equal 1 otherwise. */ 159 | #define BIT_CMP(_s, p, c) __extension__({ \ 160 | __size_t __i; \ 161 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 162 | if (((c)->__bits[__i] != \ 163 | (p)->__bits[__i])) \ 164 | break; \ 165 | __i != __bitset_words((_s)); \ 166 | }) 167 | 168 | #define BIT_OR(_s, d, s) \ 169 | do { \ 170 | __size_t __i; \ 171 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 172 | (d)->__bits[__i] |= (s)->__bits[__i]; \ 173 | } while (0) 174 | 175 | #define BIT_OR2(_s, d, s1, s2) \ 176 | do { \ 177 | __size_t __i; \ 178 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 179 | (d)->__bits[__i] = (s1)->__bits[__i] | (s2)->__bits[__i]; \ 180 | } while (0) 181 | 182 | #define BIT_AND(_s, d, s) \ 183 | do { \ 184 | __size_t __i; \ 185 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 186 | (d)->__bits[__i] &= (s)->__bits[__i]; \ 187 | } while (0) 188 | 189 | #define BIT_AND2(_s, d, s1, s2) \ 190 | do { \ 191 | __size_t __i; \ 192 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 193 | (d)->__bits[__i] = (s1)->__bits[__i] & (s2)->__bits[__i]; \ 194 | } while (0) 195 | 196 | #define BIT_NAND(_s, d, s) \ 197 | do { \ 198 | __size_t __i; \ 199 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 200 | (d)->__bits[__i] &= ~(s)->__bits[__i]; \ 201 | } while (0) 202 | 203 | #define BIT_NAND2(_s, d, s1, s2) \ 204 | do { \ 205 | __size_t __i; \ 206 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 207 | (d)->__bits[__i] = (s1)->__bits[__i] & ~(s2)->__bits[__i]; \ 208 | } while (0) 209 | 210 | #define BIT_XOR(_s, d, s) \ 211 | do { \ 212 | __size_t __i; \ 213 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 214 | (d)->__bits[__i] ^= (s)->__bits[__i]; \ 215 | } while (0) 216 | 217 | #define BIT_XOR2(_s, d, s1, s2) \ 218 | do { \ 219 | __size_t __i; \ 220 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 221 | (d)->__bits[__i] = (s1)->__bits[__i] ^ (s2)->__bits[__i]; \ 222 | } while (0) 223 | 224 | #define BIT_FFS(_s, p) __extension__({ \ 225 | __size_t __i; \ 226 | int __bit; \ 227 | \ 228 | __bit = 0; \ 229 | for (__i = 0; __i < __bitset_words((_s)); __i++) { \ 230 | if ((p)->__bits[__i] != 0) { \ 231 | __bit = ffsl((p)->__bits[__i]); \ 232 | __bit += __i * _BITSET_BITS; \ 233 | break; \ 234 | } \ 235 | } \ 236 | __bit; \ 237 | }) 238 | 239 | #define BIT_FLS(_s, p) __extension__({ \ 240 | __size_t __i; \ 241 | int __bit; \ 242 | \ 243 | __bit = 0; \ 244 | for (__i = __bitset_words((_s)); __i > 0; __i--) { \ 245 | if ((p)->__bits[__i - 1] != 0) { \ 246 | __bit = flsl((p)->__bits[__i - 1]); \ 247 | __bit += (__i - 1) * _BITSET_BITS; \ 248 | break; \ 249 | } \ 250 | } \ 251 | __bit; \ 252 | }) 253 | 254 | #define BIT_COUNT(_s, p) __extension__({ \ 255 | __size_t __i; \ 256 | int __count; \ 257 | \ 258 | __count = 0; \ 259 | for (__i = 0; __i < __bitset_words((_s)); __i++) \ 260 | __count += __bitcountl((p)->__bits[__i]); \ 261 | __count; \ 262 | }) 263 | 264 | #define BITSET_T_INITIALIZER(x) \ 265 | { \ 266 | .__bits = { x } \ 267 | } 268 | 269 | /* 270 | * Helper to declare a bitset without it's size being a constant. 271 | * 272 | * Sadly we cannot declare a bitset struct with '__bits[]', because it's 273 | * the only member of the struct and the compiler complains. 274 | */ 275 | #define BITSET_DEFINE_VAR(t) BITSET_DEFINE(t, 1) 276 | 277 | /* 278 | * Define a default type that can be used while manually specifying size 279 | * to every call. 280 | */ 281 | BITSET_DEFINE(bitset, 1); 282 | 283 | #endif /* !_SYS__BITSET_H_ */ 284 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "autocfg" 16 | version = "1.0.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 19 | 20 | [[package]] 21 | name = "bare-metal" 22 | version = "0.2.5" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" 25 | dependencies = [ 26 | "rustc_version", 27 | ] 28 | 29 | [[package]] 30 | name = "bare-metal" 31 | version = "1.0.0" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" 34 | 35 | [[package]] 36 | name = "bit_field" 37 | version = "0.10.1" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" 40 | 41 | [[package]] 42 | name = "bitflags" 43 | version = "1.3.2" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 46 | 47 | [[package]] 48 | name = "bl602-hal" 49 | version = "0.1.0" 50 | source = "git+https://github.com/sipeed/bl602-hal?rev=dfc9946e79ea4dac18be11efce11d0592a8517fb#dfc9946e79ea4dac18be11efce11d0592a8517fb" 51 | dependencies = [ 52 | "bl602-pac", 53 | "embedded-hal 0.2.6", 54 | "embedded-hal 1.0.0-alpha.5", 55 | "embedded-time", 56 | "nb 1.0.0", 57 | "paste", 58 | "riscv 0.6.0", 59 | "riscv-target", 60 | ] 61 | 62 | [[package]] 63 | name = "bl602-pac" 64 | version = "0.1.0" 65 | source = "git+https://github.com/sipeed/bl602-pac?branch=main#4c8e69856b39a505714bc4e636705a7be858b50b" 66 | dependencies = [ 67 | "bare-metal 1.0.0", 68 | "riscv 0.6.0", 69 | "vcell", 70 | ] 71 | 72 | [[package]] 73 | name = "bl602wifi" 74 | version = "0.1.0" 75 | dependencies = [ 76 | "bl602-hal", 77 | "ble-hci", 78 | "embedded-time", 79 | "nb 1.0.0", 80 | "riscv 0.7.0", 81 | "riscv-rt", 82 | "smoltcp", 83 | ] 84 | 85 | [[package]] 86 | name = "ble-hci" 87 | version = "0.1.0" 88 | source = "git+https://github.com/bjoernQ/ble-hci#bd07cb74b4ef1aebcd31775185c6f499bb20c869" 89 | 90 | [[package]] 91 | name = "byteorder" 92 | version = "1.4.3" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 95 | 96 | [[package]] 97 | name = "embedded-hal" 98 | version = "0.2.6" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "e36cfb62ff156596c892272f3015ef952fe1525e85261fa3a7f327bd6b384ab9" 101 | dependencies = [ 102 | "nb 0.1.3", 103 | "void", 104 | ] 105 | 106 | [[package]] 107 | name = "embedded-hal" 108 | version = "1.0.0-alpha.5" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "a554c04648665230499563ccdfd1fcd719ef2d5a0af54bdc81c5d877fb556db4" 111 | dependencies = [ 112 | "nb 1.0.0", 113 | ] 114 | 115 | [[package]] 116 | name = "embedded-time" 117 | version = "0.12.0" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "86fbafcea0dea120d8ed8af67ddbf82afc031f1d3b064920645db8d061781e2c" 120 | dependencies = [ 121 | "num", 122 | ] 123 | 124 | [[package]] 125 | name = "lazy_static" 126 | version = "1.4.0" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 129 | 130 | [[package]] 131 | name = "managed" 132 | version = "0.7.2" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577" 135 | 136 | [[package]] 137 | name = "memchr" 138 | version = "2.4.1" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 141 | 142 | [[package]] 143 | name = "nb" 144 | version = "0.1.3" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 147 | dependencies = [ 148 | "nb 1.0.0", 149 | ] 150 | 151 | [[package]] 152 | name = "nb" 153 | version = "1.0.0" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" 156 | 157 | [[package]] 158 | name = "num" 159 | version = "0.3.1" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" 162 | dependencies = [ 163 | "num-complex", 164 | "num-integer", 165 | "num-iter", 166 | "num-rational", 167 | "num-traits", 168 | ] 169 | 170 | [[package]] 171 | name = "num-complex" 172 | version = "0.3.1" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" 175 | dependencies = [ 176 | "num-traits", 177 | ] 178 | 179 | [[package]] 180 | name = "num-integer" 181 | version = "0.1.44" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 184 | dependencies = [ 185 | "autocfg", 186 | "num-traits", 187 | ] 188 | 189 | [[package]] 190 | name = "num-iter" 191 | version = "0.1.42" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" 194 | dependencies = [ 195 | "autocfg", 196 | "num-integer", 197 | "num-traits", 198 | ] 199 | 200 | [[package]] 201 | name = "num-rational" 202 | version = "0.3.2" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" 205 | dependencies = [ 206 | "autocfg", 207 | "num-integer", 208 | "num-traits", 209 | ] 210 | 211 | [[package]] 212 | name = "num-traits" 213 | version = "0.2.14" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 216 | dependencies = [ 217 | "autocfg", 218 | ] 219 | 220 | [[package]] 221 | name = "paste" 222 | version = "1.0.5" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" 225 | 226 | [[package]] 227 | name = "ppv-lite86" 228 | version = "0.2.10" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 231 | 232 | [[package]] 233 | name = "proc-macro2" 234 | version = "1.0.29" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" 237 | dependencies = [ 238 | "unicode-xid", 239 | ] 240 | 241 | [[package]] 242 | name = "quote" 243 | version = "1.0.9" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 246 | dependencies = [ 247 | "proc-macro2", 248 | ] 249 | 250 | [[package]] 251 | name = "r0" 252 | version = "1.0.0" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211" 255 | 256 | [[package]] 257 | name = "rand" 258 | version = "0.7.3" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 261 | dependencies = [ 262 | "rand_chacha", 263 | "rand_core", 264 | "rand_hc", 265 | "rand_pcg", 266 | ] 267 | 268 | [[package]] 269 | name = "rand_chacha" 270 | version = "0.2.2" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 273 | dependencies = [ 274 | "ppv-lite86", 275 | "rand_core", 276 | ] 277 | 278 | [[package]] 279 | name = "rand_core" 280 | version = "0.5.1" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 283 | 284 | [[package]] 285 | name = "rand_hc" 286 | version = "0.2.0" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 289 | dependencies = [ 290 | "rand_core", 291 | ] 292 | 293 | [[package]] 294 | name = "rand_pcg" 295 | version = "0.2.1" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" 298 | dependencies = [ 299 | "rand_core", 300 | ] 301 | 302 | [[package]] 303 | name = "regex" 304 | version = "1.5.4" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 307 | dependencies = [ 308 | "aho-corasick", 309 | "memchr", 310 | "regex-syntax", 311 | ] 312 | 313 | [[package]] 314 | name = "regex-syntax" 315 | version = "0.6.25" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 318 | 319 | [[package]] 320 | name = "riscv" 321 | version = "0.6.0" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "a2f0b705d428e9d0f78e2bb73093887ee58a83c9688de3faedbb4c0631c4618e" 324 | dependencies = [ 325 | "bare-metal 0.2.5", 326 | "bit_field", 327 | "riscv-target", 328 | ] 329 | 330 | [[package]] 331 | name = "riscv" 332 | version = "0.7.0" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "6907ccdd7a31012b70faf2af85cd9e5ba97657cc3987c4f13f8e4d2c2a088aba" 335 | dependencies = [ 336 | "bare-metal 1.0.0", 337 | "bit_field", 338 | "riscv-target", 339 | ] 340 | 341 | [[package]] 342 | name = "riscv-rt" 343 | version = "0.8.0" 344 | source = "git+https://github.com/bjoernQ/riscv-rt?branch=support-ilp32f#ef373496eea7b0de706fc28523dfc8be74cf96a9" 345 | dependencies = [ 346 | "r0", 347 | "riscv 0.6.0", 348 | "riscv-rt-macros", 349 | "riscv-target", 350 | ] 351 | 352 | [[package]] 353 | name = "riscv-rt-macros" 354 | version = "0.1.6" 355 | source = "git+https://github.com/bjoernQ/riscv-rt?branch=support-ilp32f#ef373496eea7b0de706fc28523dfc8be74cf96a9" 356 | dependencies = [ 357 | "proc-macro2", 358 | "quote", 359 | "rand", 360 | "syn", 361 | ] 362 | 363 | [[package]] 364 | name = "riscv-target" 365 | version = "0.1.2" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "88aa938cda42a0cf62a20cfe8d139ff1af20c2e681212b5b34adb5a58333f222" 368 | dependencies = [ 369 | "lazy_static", 370 | "regex", 371 | ] 372 | 373 | [[package]] 374 | name = "rustc_version" 375 | version = "0.2.3" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 378 | dependencies = [ 379 | "semver", 380 | ] 381 | 382 | [[package]] 383 | name = "semver" 384 | version = "0.9.0" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 387 | dependencies = [ 388 | "semver-parser", 389 | ] 390 | 391 | [[package]] 392 | name = "semver-parser" 393 | version = "0.7.0" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 396 | 397 | [[package]] 398 | name = "smoltcp" 399 | version = "0.7.5" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "3e4a069bef843d170df47e7c0a8bf8d037f217d9f5b325865acc3e466ffe40d3" 402 | dependencies = [ 403 | "bitflags", 404 | "byteorder", 405 | "managed", 406 | ] 407 | 408 | [[package]] 409 | name = "syn" 410 | version = "1.0.77" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" 413 | dependencies = [ 414 | "proc-macro2", 415 | "quote", 416 | "unicode-xid", 417 | ] 418 | 419 | [[package]] 420 | name = "unicode-xid" 421 | version = "0.2.2" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 424 | 425 | [[package]] 426 | name = "vcell" 427 | version = "0.1.3" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 430 | 431 | [[package]] 432 | name = "void" 433 | version = "1.0.2" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 436 | -------------------------------------------------------------------------------- /src/wifi/mod.rs: -------------------------------------------------------------------------------- 1 | use embedded_time::duration::Milliseconds; 2 | use smoltcp::phy::{Device, DeviceCapabilities, RxToken, TxToken}; 3 | use smoltcp::wire::EthernetAddress; 4 | 5 | use crate::binary::wifi_mgmr::{self, wifi_mgmr_drv_init, _WIFI_EVENT_CODE_WIFI_ON_GOT_IP}; 6 | use crate::binary::wifi_mgmr_api; 7 | use crate::compat::common::EMULATED_TIMER; 8 | use crate::compat::{common::EmulatedTimer, get_time, work_queue::do_work}; 9 | use crate::{binary::bl_wifi, compat::queue::SimpleQueue}; 10 | use crate::{log, print, println}; 11 | 12 | extern "C" { 13 | static mut __wifi_bss_start: u32; 14 | 15 | static mut __wifi_bss_end: u32; 16 | 17 | pub fn bl_pm_init(); 18 | 19 | pub fn wifi_main_init(); 20 | 21 | pub fn ipc_emb_notify(); 22 | 23 | pub fn wifi_mgmr_tsk_init(); 24 | 25 | pub fn bl_free_rx_buffer(p: *const u8); 26 | 27 | pub fn bl_irq_handler(); 28 | 29 | pub fn bl_output(bl_hw: *const bl_wifi::bl_hw, p: *mut u8, tot_len: usize, is_sta: i32) -> i32; 30 | 31 | pub static wifiMgmr: wifi_mgmr::wifi_mgmr; 32 | 33 | pub static bl606a0_sta: bl_wifi::net_device; 34 | } 35 | 36 | pub static mut WIFI_CONNECTED: bool = false; 37 | struct DataFrame { 38 | len: usize, 39 | data: *mut u8, 40 | } 41 | 42 | static mut DATA_QUEUE_RX: SimpleQueue = SimpleQueue::new(); 43 | 44 | #[link_section = ".wifi_ram.txbuff"] 45 | static mut TX_BUFFER: [u8; 1650] = [0u8; 1650]; // should be a queue 46 | pub static mut TX_QUEUED: bool = false; 47 | 48 | static mut SCAN_IN_PROGRESS: bool = false; 49 | static mut LAST_SCAN_RESULT: [Option; 50] = [None; 50]; 50 | 51 | pub fn wifi_pre_init() { 52 | unsafe { 53 | use core::{mem, ptr}; 54 | 55 | let mut sbss = &mut __wifi_bss_start as *mut u32; 56 | let ebss = &mut __wifi_bss_end as *mut u32; 57 | while sbss < ebss { 58 | ptr::write_volatile(sbss, mem::zeroed()); 59 | sbss = sbss.offset(1); 60 | } 61 | } 62 | 63 | // hbn_config_aon_pad_input_and_smt(); 64 | 65 | // bl602_set_em_sel_bl602_glb_em_8kb(); 66 | } 67 | 68 | pub fn wifi_init() { 69 | let mut mac = get_mac(); 70 | println!("MAC address"); 71 | for x in mac.iter() { 72 | print!("{:2x} ", *x); 73 | } 74 | print!("\r\n"); 75 | 76 | let mut conf = crate::binary::wifi_mgmr::wifi_conf_t { 77 | country_code: [b'C', b'N', 0], 78 | channel_nums: 13, 79 | }; 80 | 81 | unsafe { 82 | crate::binary::bl_wifi::bl_wifi_ap_mac_addr_set(&mut mac as *mut _); 83 | crate::binary::bl_wifi::bl_wifi_sta_mac_addr_set(&mut mac as *mut _); 84 | 85 | let mut my_ssid = [b't', b'e', b's', b't', 0]; 86 | crate::binary::wifi_mgmr_api::wifi_mgmr_sta_ssid_set(&mut my_ssid as *mut _); 87 | crate::binary::wifi_mgmr_api::wifi_mgmr_sta_mac_set(&mut mac as *mut _); 88 | 89 | bl_pm_init(); 90 | wifi_main_init(); 91 | ipc_emb_notify(); 92 | wifi_mgmr_drv_init(&mut conf); 93 | 94 | for _ in 0..250000 {} 95 | 96 | wifi_mgmr_tsk_init(); 97 | 98 | crate::binary::wifi_mgmr_api::wifi_mgmr_sta_autoconnect_disable(); 99 | } 100 | } 101 | 102 | pub fn get_mac() -> [u8; 6] { 103 | unsafe { 104 | let mac_lo = (0x40007014 as *const u32).read_volatile(); 105 | let mac_hi = (0x40007018 as *const u32).read_volatile(); 106 | 107 | let mac = [ 108 | ((mac_hi & 0xff00) >> 8) as u8, 109 | (mac_hi & 0xff) as u8, 110 | ((mac_lo & 0xff000000) >> 24) as u8, 111 | ((mac_lo & 0xff0000) >> 16) as u8, 112 | ((mac_lo & 0xff00) >> 8) as u8, 113 | (mac_lo & 0xff) as u8, 114 | ]; 115 | mac 116 | } 117 | } 118 | 119 | pub fn wifi_scan() -> core::result::Result<[Option; 50], ()> { 120 | unsafe { 121 | if SCAN_IN_PROGRESS { 122 | return Err(()); 123 | } 124 | 125 | SCAN_IN_PROGRESS = true; 126 | wifi_mgmr::wifi_mgmr_scan(core::ptr::null_mut(), Some(scan_cb)); 127 | while SCAN_IN_PROGRESS {} 128 | 129 | Ok(LAST_SCAN_RESULT.clone()) 130 | } 131 | } 132 | 133 | pub fn connect_sta(arg_ssid: &str, arg_psk: &str) { 134 | let mut ssid = [0u8; 33]; 135 | let mut psk = [0u8; 64]; 136 | 137 | ssid[0..(arg_ssid.len())].copy_from_slice(arg_ssid.as_bytes()); 138 | psk[0..(arg_psk.len())].copy_from_slice(arg_psk.as_bytes()); 139 | 140 | unsafe { 141 | wifi_mgmr_api::wifi_mgmr_api_connect( 142 | &mut ssid as *mut _, 143 | &mut psk as *mut _, 144 | core::ptr::null_mut(), // &mut ext_param as *mut _, 145 | ); 146 | 147 | while !WIFI_CONNECTED { 148 | // wait until we are connected 149 | } 150 | } 151 | } 152 | 153 | #[no_mangle] 154 | pub unsafe extern "C" fn bl602_net_notify(event: u32, data: *mut u8, len: usize) -> i32 { 155 | // event: notify type, tx done or received new data 156 | // data: The data of the event, may be NULL 157 | // len: data length 158 | 159 | println!("bl602_net_notify {} {:p} {}", event, data, len); 160 | 161 | let is_rx = (event & 0x2) != 0; 162 | let is_tx_done = (event & 0x1) != 0; 163 | 164 | riscv::interrupt::free(|_| { 165 | if is_rx { 166 | if !DATA_QUEUE_RX.is_full() { 167 | DATA_QUEUE_RX.enqueue(DataFrame { 168 | len: len, 169 | data: data, 170 | }); 171 | } 172 | } else if is_tx_done { 173 | // nothing here 174 | } 175 | }); 176 | 177 | 0 178 | } 179 | 180 | #[no_mangle] 181 | pub unsafe extern "C" fn bl602_netdev_free_txbuf(_buf: *mut u8) { 182 | println!("bl602_netdev_free_txbuf called"); 183 | } 184 | 185 | #[no_mangle] 186 | pub unsafe extern "C" fn bl602_net_event(evt: i32, val: u32) { 187 | // evt e.g. CODE_WIFI_ON_CONNECTED, CODE_WIFI_ON_GOT_IP, ... 188 | 189 | println!("bl602_net_event called {} {}", evt, val); 190 | 191 | if evt == _WIFI_EVENT_CODE_WIFI_ON_GOT_IP { 192 | WIFI_CONNECTED = true; 193 | } 194 | } 195 | 196 | pub unsafe extern "C" fn scan_cb( 197 | _data: *mut crate::binary::c_types::c_void, 198 | _param: *mut crate::binary::c_types::c_void, 199 | ) { 200 | println!("SCAN CALLBACK"); 201 | 202 | for i in 0..50 { 203 | let item = wifiMgmr.scan_items[i]; 204 | if item.is_used != 0 { 205 | LAST_SCAN_RESULT[i] = Some(ScanItem { 206 | ssid: item.ssid.clone(), 207 | channel: item.channel, 208 | rssi: item.rssi, 209 | bssid: item.bssid.clone(), 210 | }); 211 | } else { 212 | LAST_SCAN_RESULT[i] = None; 213 | } 214 | } 215 | 216 | SCAN_IN_PROGRESS = false; 217 | } 218 | 219 | pub fn init_mac(ethernet: &mut smoltcp::iface::EthernetInterface) { 220 | let mac = get_mac(); 221 | let addr = EthernetAddress::from_bytes(&mac); 222 | ethernet.set_ethernet_addr(addr); 223 | } 224 | 225 | pub struct WifiDevice {} 226 | 227 | impl WifiDevice { 228 | pub fn new() -> WifiDevice { 229 | WifiDevice {} 230 | } 231 | } 232 | 233 | // see https://docs.rs/smoltcp/0.7.1/smoltcp/phy/index.html 234 | impl<'a> Device<'a> for WifiDevice { 235 | type RxToken = WifiRxToken; 236 | 237 | type TxToken = WifiTxToken; 238 | 239 | fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { 240 | let available = unsafe { !DATA_QUEUE_RX.is_empty() }; 241 | 242 | if available { 243 | Some((WifiRxToken::default(), WifiTxToken::default())) 244 | } else { 245 | None 246 | } 247 | } 248 | 249 | fn transmit(&'a mut self) -> Option { 250 | Some(WifiTxToken::default()) 251 | } 252 | 253 | fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities { 254 | let mut caps = DeviceCapabilities::default(); 255 | caps.max_transmission_unit = 1514; 256 | caps.max_burst_size = Some(1); 257 | caps 258 | } 259 | } 260 | 261 | #[derive(Debug, Default)] 262 | pub struct WifiRxToken {} 263 | 264 | impl RxToken for WifiRxToken { 265 | fn consume(self, _timestamp: smoltcp::time::Instant, f: F) -> smoltcp::Result 266 | where 267 | F: FnOnce(&mut [u8]) -> smoltcp::Result, 268 | { 269 | unsafe { 270 | while !DATA_QUEUE_RX.is_empty() { 271 | let element = DATA_QUEUE_RX.dequeue(); 272 | 273 | match element { 274 | Some(data) => { 275 | let mut buffer = core::slice::from_raw_parts_mut(data.data, data.len); 276 | 277 | dump_packet_info(&buffer); 278 | 279 | let res = f(&mut buffer); 280 | bl_free_rx_buffer(data.data); 281 | return res; 282 | } 283 | None => {} 284 | } 285 | } 286 | } 287 | 288 | Err(smoltcp::Error::Exhausted) 289 | } 290 | } 291 | 292 | #[derive(Debug, Default)] 293 | pub struct WifiTxToken {} 294 | 295 | impl TxToken for WifiTxToken { 296 | fn consume( 297 | self, 298 | _timestamp: smoltcp::time::Instant, 299 | len: usize, 300 | f: F, 301 | ) -> smoltcp::Result 302 | where 303 | F: FnOnce(&mut [u8]) -> smoltcp::Result, 304 | { 305 | // there are 128 bytes needed in front of the data 306 | let res = unsafe { f(&mut TX_BUFFER[128..(128 + len)]) }; 307 | 308 | unsafe { 309 | dump_packet_info(&TX_BUFFER[128..(128 + len)]); 310 | } 311 | 312 | match res { 313 | Ok(_) => { 314 | let is_sta = 1; // for now we are always STA 315 | unsafe { 316 | if TX_QUEUED { 317 | // for the future we should have more TX buffers 318 | return Err(smoltcp::Error::Exhausted); 319 | } 320 | 321 | bl_output( 322 | bl606a0_sta.bl_hw, 323 | (&mut TX_BUFFER as *mut u8).offset(128), 324 | len, 325 | is_sta, 326 | ); 327 | TX_QUEUED = true; 328 | } 329 | } 330 | Err(_) => {} 331 | } 332 | 333 | res 334 | } 335 | } 336 | 337 | fn dump_packet_info(buffer: &[u8]) { 338 | let ef = smoltcp::wire::EthernetFrame::new_unchecked(buffer); 339 | println!( 340 | "src={:x?} dst={:x?} type={:x?}", 341 | ef.src_addr(), 342 | ef.dst_addr(), 343 | ef.ethertype() 344 | ); 345 | match ef.ethertype() { 346 | smoltcp::wire::EthernetProtocol::Ipv4 => { 347 | let ip = smoltcp::wire::Ipv4Packet::new_unchecked(ef.payload()); 348 | println!( 349 | "src={:?} dst={:?} proto={:x?}", 350 | ip.src_addr(), 351 | ip.dst_addr(), 352 | ip.protocol() 353 | ); 354 | 355 | match ip.protocol() { 356 | smoltcp::wire::IpProtocol::HopByHop => {} 357 | smoltcp::wire::IpProtocol::Icmp => {} 358 | smoltcp::wire::IpProtocol::Igmp => {} 359 | smoltcp::wire::IpProtocol::Tcp => { 360 | let tp = smoltcp::wire::TcpPacket::new_unchecked(ip.payload()); 361 | println!("src={:?} dst={:?}", tp.src_port(), tp.dst_port()); 362 | } 363 | smoltcp::wire::IpProtocol::Udp => { 364 | let up = smoltcp::wire::UdpPacket::new_unchecked(ip.payload()); 365 | println!("src={:?} dst={:?}", up.src_port(), up.dst_port()); 366 | } 367 | smoltcp::wire::IpProtocol::Ipv6Route => {} 368 | smoltcp::wire::IpProtocol::Ipv6Frag => {} 369 | smoltcp::wire::IpProtocol::Icmpv6 => {} 370 | smoltcp::wire::IpProtocol::Ipv6NoNxt => {} 371 | smoltcp::wire::IpProtocol::Ipv6Opts => {} 372 | smoltcp::wire::IpProtocol::Unknown(_) => {} 373 | } 374 | } 375 | smoltcp::wire::EthernetProtocol::Arp => { 376 | let ap = smoltcp::wire::ArpPacket::new_unchecked(ef.payload()); 377 | println!( 378 | "src={:x?} dst={:x?} src proto addr={:x?}", 379 | ap.source_hardware_addr(), 380 | ap.target_hardware_addr(), 381 | ap.source_protocol_addr() 382 | ); 383 | } 384 | smoltcp::wire::EthernetProtocol::Ipv6 => {} 385 | smoltcp::wire::EthernetProtocol::Unknown(_) => {} 386 | } 387 | } 388 | 389 | pub fn trigger_transmit_if_needed() { 390 | unsafe { 391 | let trigger = riscv::interrupt::free(|_| { 392 | if TX_QUEUED { 393 | TX_QUEUED = false; 394 | true 395 | } else { 396 | false 397 | } 398 | }); 399 | 400 | if trigger { 401 | bl_irq_handler(); 402 | } 403 | } 404 | } 405 | 406 | pub extern "C" fn wifi_worker_task1() { 407 | unsafe { 408 | loop { 409 | do_work(1); 410 | 411 | riscv::interrupt::free(|_| { 412 | for i in 0..EMULATED_TIMER.len() { 413 | EMULATED_TIMER[i] = match &EMULATED_TIMER[i] { 414 | Some(old) => { 415 | if old.next_notify != 0 && (get_time().0 >= old.next_notify) { 416 | log!("trigger timer...."); 417 | 418 | (old.notify_function)(); 419 | Some(EmulatedTimer { 420 | notify_function: old.notify_function, 421 | interval_secs: old.interval_secs, 422 | next_notify: (get_time() 423 | + Milliseconds::new(old.interval_secs * 1000)) 424 | .0, 425 | }) 426 | } else { 427 | Some(EmulatedTimer { ..*old }) 428 | } 429 | } 430 | None => None, 431 | }; 432 | } 433 | }); 434 | } 435 | } 436 | } 437 | 438 | pub extern "C" fn wifi_worker_task2() { 439 | loop { 440 | do_work(0); 441 | } 442 | } 443 | 444 | #[derive(Debug, Clone, Copy)] 445 | pub struct ScanItem { 446 | pub ssid: [u8; 32], 447 | pub channel: u8, 448 | pub rssi: i8, 449 | pub bssid: [u8; 6], 450 | } 451 | -------------------------------------------------------------------------------- /nuttx/wifi_manager/stateMachine.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | **************************************************************************************** 4 | * 5 | * @file stateMachine.h 6 | * Copyright (C) Bouffalo Lab 2016-2018 7 | * 8 | **************************************************************************************** 9 | */ 10 | 11 | 12 | 13 | /* 14 | * Copyright (c) 2013 Andreas Misje 15 | * 16 | * Permission is hereby granted, free of charge, to any person obtaining a 17 | * copy of this software and associated documentation files (the "Software"), 18 | * to deal in the Software without restriction, including without limitation 19 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 20 | * and/or sell copies of the Software, and to permit persons to whom the 21 | * Software is furnished to do so, subject to the following conditions: 22 | * 23 | * The above copyright notice and this permission notice shall be included in 24 | * all copies or substantial portions of the Software. 25 | * 26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 31 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 32 | * DEALINGS IN THE SOFTWARE. 33 | */ 34 | 35 | /** 36 | * \mainpage %stateMachine 37 | * 38 | * %stateMachine is a feature-rich, yet simple finite state machine 39 | * implementation. It supports grouped states, guarded transitions, events 40 | * with payload, entry and exit actions, transition actions and access to 41 | * user-defined state data from all actions. 42 | * 43 | * The user must build the state machine by linking together states and 44 | * transitions arrays with pointers. A pointer to an initial state and an 45 | * error state is given to stateM_init() to initialise a state machine object. 46 | * The state machine is run by passing events to it with the function 47 | * stateM_handleEvent(). The return value of stateM_handleEvent() will 48 | * give an indication to what has happened. 49 | * 50 | * \image html stateMachine.svg "Illustrating a stateMachine" 51 | */ 52 | 53 | /** 54 | * \defgroup stateMachine State machine 55 | * 56 | * \author Andreas Misje 57 | * \date 27.03.13 58 | * 59 | * \brief Finite state machine 60 | * 61 | * A finite state machine implementation that supports nested states, guards 62 | * and entry/exit routines. All state machine data is stored in separate 63 | * objects, and the state machine must be built by the user. States are 64 | * connected using pointers, and all data can be stored on either the stack, 65 | * heap or both. 66 | */ 67 | 68 | /** 69 | * \addtogroup stateMachine 70 | * @{ 71 | * 72 | * \file 73 | * \example stateMachineExample.c Simple example of how to create a state 74 | * machine 75 | * \example nestedTest.c Simple example testing the behaviour of nested 76 | * parent states 77 | */ 78 | 79 | #ifndef STATEMACHINE_H 80 | #define STATEMACHINE_H 81 | 82 | #include 83 | #include 84 | 85 | /** 86 | * \brief Event 87 | * 88 | * Events trigger transitions from a state to another. Event types are defined 89 | * by the user. Any event may optionally contain a \ref #event::data 90 | * "payload". 91 | * 92 | * \sa state 93 | * \sa transition 94 | */ 95 | struct event 96 | { 97 | /** \brief Type of event. Defined by user. */ 98 | int type; 99 | /** 100 | * \brief Event payload. 101 | * 102 | * How this is used is entirely up to the user. This data 103 | * is always passed together with #type in order to make it possible to 104 | * always cast the data correctly. 105 | */ 106 | void *data; 107 | }; 108 | 109 | struct state; 110 | 111 | /** 112 | * \brief Transition between a state and another state 113 | * 114 | * All states that are not final must have at least one transition. The 115 | * transition may be guarded or not. Transitions are triggered by events. If 116 | * a state has more than one transition with the same type of event (and the 117 | * same condition), the first transition in the array will be run. An 118 | * unconditional transition placed last in the transition array of a state can 119 | * act as a "catch-all". A transition may optionally run an #action, which 120 | * will have the triggering event passed to it as an argument, along with the 121 | * current and new states' \ref state::data "data". 122 | * 123 | * It is perfectly valid for a transition to return to the state it belongs 124 | * to. Such a transition will not call the state's \ref state::entryAction 125 | * "entry action" or \ref state::exitAction "exit action". If there are no 126 | * transitions for the current event, the state's parent will be handed the 127 | * event. 128 | * 129 | * ### Examples ### 130 | * - An ungarded transition to a state with no action performed: 131 | * ~~~{.c} 132 | * { 133 | * .eventType = Event_timeout, 134 | * .condition = NULL, 135 | * .guard = NULL, 136 | * .action = NULL, 137 | * .nextState = &mainMenuState, 138 | * }, 139 | * ~~~ 140 | * - A guarded transition executing an action 141 | * ~~~{.c} 142 | * { 143 | * .eventType = Event_keyboard, 144 | * .condition = NULL, 145 | * .guard = &ensureNumericInput, 146 | * .action = &addToBuffer, 147 | * .nextState = &awaitingInputState, 148 | * }, 149 | * ~~~ 150 | * - A guarded transition using a condition 151 | * ~~~{.c} 152 | * { 153 | * .eventType = Event_mouse, 154 | * .condition = boxLimits, 155 | * .guard = &coordinatesWithinLimits, 156 | * }, 157 | * ~~~ 158 | * By using \ref #condition "conditions" a more general guard function can be 159 | * used, operating on the supplied argument #condition. In this example, 160 | * `coordinatesWithinLimits` checks whether the coordinates in the mouse event 161 | * are within the limits of the "box". 162 | * 163 | * \sa event 164 | * \sa state 165 | */ 166 | struct transition 167 | { 168 | /** \brief The event that will trigger this transition. */ 169 | int eventType; 170 | /** 171 | * \brief Condition that event must fulfil 172 | * 173 | * This variable will be passed to the #guard (if #guard is non-NULL) and 174 | * may be used as a condition that the incoming event's data must fulfil in 175 | * order for the transition to be performed. By using this variable, the 176 | * number of #guard functions can be minimised by making them more general. 177 | */ 178 | void *condition; 179 | /** 180 | * \brief Check if data passed with event fulfils a condition 181 | * 182 | * A transition may be conditional. If so, this function, if non-NULL, will 183 | * be called. Its first argument will be supplied with #condition, which 184 | * can be compared against the \ref event::data "payload" in the #event. 185 | * The user may choose to use this argument or not. Only if the result is 186 | * true, the transition will take place. 187 | * 188 | * \param condition event (data) to compare the incoming event against. 189 | * \param event the event passed to the state machine. 190 | * 191 | * \returns true if the event's data fulfils the condition, otherwise false. 192 | */ 193 | bool ( *guard )( void *condition, struct event *event ); 194 | /** 195 | * \brief Function containing tasks to be performed during the transition 196 | * 197 | * The transition may optionally do some work in this function before 198 | * entering the next state. May be NULL. 199 | * 200 | * \param currentStateData the leaving state's \ref state::data "data" 201 | * \param event the event passed to the state machine. 202 | * \param newStateData the new state's (the \ref state::entryState 203 | * "entryState" of any (chain of) parent states, not the parent state 204 | * itself) \ref state::data "data" 205 | */ 206 | void ( *action )( void *currentStateData, struct event *event, 207 | void *newStateData ); 208 | /** 209 | * \brief The next state 210 | * 211 | * This must point to the next state that will be entered. It cannot be 212 | * NULL. If it is, the state machine will detect it and enter the \ref 213 | * stateMachine::errorState "error state". 214 | */ 215 | const struct state *nextState; 216 | }; 217 | 218 | /** 219 | * \brief State 220 | * 221 | * The current state in a state machine moves to a new state when one of the 222 | * #transitions in the current state triggers on an event. An optional \ref 223 | * #exitAction "exit action" is called when the state is left, and an \ref 224 | * #entryAction "entry action" is called when the state machine enters a new 225 | * state. If a state returns to itself, neither #exitAction nor #entryAction 226 | * will be called. An optional \ref transition::action "transition action" is 227 | * called in either case. 228 | * 229 | * States may be organised in a hierarchy by setting \ref #parentState 230 | * "parent states". When a group/parent state is entered, the state machine is 231 | * redirected to the group state's \ref #entryState "entry state" (if 232 | * non-NULL). If an event does not trigger a transition in a state and if the 233 | * state has a parent state, the event will be passed to the parent state. 234 | * This behaviour is repeated for all parents. Thus all children of a state 235 | * have a set of common #transitions. A parent state's #entryAction will not 236 | * be called if an event is passed on to a child state. 237 | * 238 | * The following lists the different types of states that may be created, and 239 | * how to create them: 240 | * 241 | * ### Normal state ### 242 | * ~~~{.c} 243 | * struct state normalState = { 244 | * .parentState = &groupState, 245 | * .entryState = NULL, 246 | * .transition = (struct transition[]){ 247 | * { Event_keyboard, (void *)(intptr_t)'\n', &compareKeyboardChar, 248 | * NULL, &msgReceivedState }, 249 | * }, 250 | * .numTransitions = 1, 251 | * .data = normalStateData, 252 | * .entryAction = &doSomething, 253 | * .exitAction = &cleanUp, 254 | * }; 255 | * ~~~ 256 | * In this example, `normalState` is a child of `groupState`, but the 257 | * #parentState value may also be NULL to indicate that it is not a child of 258 | * any group state. 259 | * 260 | * ### Group/parent state ### 261 | * A state becomes a group/parent state when it is linked to by child states 262 | * by using #parentState. No members in the group state need to be set in a 263 | * particular way. A parent state may also have a parent. 264 | * ~~~{.c} 265 | * struct state groupState = { 266 | * .entryState = &normalState, 267 | * .entryAction = NULL, 268 | * ~~~ 269 | * If there are any transitions in the state machine that lead to a group 270 | * state, it makes sense to define an entry state in the group. This can be 271 | * done by using #entryState, but it is not mandatory. If the #entryState 272 | * state has children, the chain of children will be traversed until a child 273 | * with its #entryState set to NULL is found. 274 | * 275 | * \note If #entryState is defined for a group state, the group state's 276 | * #entryAction will not be called (the state pointed to by #entryState (after 277 | * following the chain of children), however, will have its #entryAction 278 | * called). 279 | * 280 | * \warning The state machine cannot detect cycles in parent chains and 281 | * children chains. If such cycles are present, stateM_handleEvent() will 282 | * never finish due to never-ending loops. 283 | * 284 | * ### Final state ### 285 | * A final state is a state that terminates the state machine. A state is 286 | * considered as a final state if its #numTransitions is 0: 287 | * ~~~{.c} 288 | * struct state finalState = { 289 | * .transitions = NULL, 290 | * .numTransitions = 0, 291 | * ~~~ 292 | * The error state used by the state machine to indicate errors should be a 293 | * final state. Any calls to stateM_handleEvent() when the current state is a 294 | * final state will return #stateM_noStateChange. 295 | * 296 | * \sa event 297 | * \sa transition 298 | */ 299 | struct state 300 | { 301 | /** 302 | * \brief If the state has a parent state, this pointer must be non-NULL. 303 | */ 304 | const struct state *parentState; 305 | /** 306 | * \brief If this state is a parent state, this pointer may point to a 307 | * child state that serves as an entry point. 308 | */ 309 | const struct state *entryState; 310 | /** 311 | * \brief An array of transitions for the state. 312 | */ 313 | struct transition *transitions; 314 | /** 315 | * \brief Number of transitions in the #transitions array. 316 | */ 317 | size_t numTransitions; 318 | /** 319 | * \brief Data that will be available for the state in its #entryAction and 320 | * #exitAction, and in any \ref transition::action "transition action" 321 | */ 322 | void *data; 323 | /** 324 | * \brief This function is called whenever the state is being entered. May 325 | * be NULL. 326 | * 327 | * \note If a state returns to itself through a transition (either directly 328 | * or through a parent/group sate), its #entryAction will not be called. 329 | * 330 | * \note A group/parent state with its #entryState defined will not have 331 | * its #entryAction called. 332 | * 333 | * \param stateData the state's #data will be passed. 334 | * \param event the event that triggered the transition will be passed. 335 | */ 336 | void ( *entryAction )( void *stateData, struct event *event ); 337 | /** 338 | * \brief This function is called whenever the state is being left. May be 339 | * NULL. 340 | * 341 | * \note If a state returns to itself through a transition (either directly 342 | * or through a parent/group sate), its #exitAction will not be called. 343 | * 344 | * \param stateData the state's #data will be passed. 345 | * \param event the event that triggered a transition will be passed. 346 | */ 347 | void ( *exitAction )( void *stateData, struct event *event ); 348 | }; 349 | 350 | /** 351 | * \brief State machine 352 | * 353 | * There is no need to manipulate the members directly. 354 | */ 355 | struct stateMachine 356 | { 357 | /** \brief Pointer to the current state */ 358 | const struct state *currentState; 359 | /** 360 | * \brief Pointer to previous state 361 | * 362 | * The previous state is stored for convenience in case the user needs to 363 | * keep track of previous states. 364 | */ 365 | const struct state *previousState; 366 | /** 367 | * \brief Pointer to a state that will be entered whenever an error occurs 368 | * in the state machine. 369 | * 370 | * See #stateM_errorStateReached for when the state machine enters the 371 | * error state. 372 | */ 373 | const struct state *errorState; 374 | }; 375 | 376 | /** 377 | * \brief Initialise the state machine 378 | * 379 | * This function initialises the supplied stateMachine and sets the current 380 | * state to \pn{initialState}. No actions are performed until 381 | * stateM_handleEvent() is called. It is safe to call this function numerous 382 | * times, for instance in order to reset/restart the state machine if a final 383 | * state has been reached. 384 | * 385 | * \note The \ref #state::entryAction "entry action" for \pn{initialState} 386 | * will not be called. 387 | * 388 | * \note If \pn{initialState} is a parent state with its \ref 389 | * state::entryState "entryState" defined, it will not be entered. The user 390 | * must explicitly set the initial state. 391 | * 392 | * \param stateMachine the state machine to initialise. 393 | * \param initialState the initial state of the state machine. 394 | * \param errorState pointer to a state that acts a final state and notifies 395 | * the system/user that an error has occurred. 396 | */ 397 | void stateM_init( struct stateMachine *stateMachine, 398 | const struct state *initialState, const struct state *errorState ); 399 | 400 | /** 401 | * \brief stateM_handleEvent() return values 402 | */ 403 | enum stateM_handleEventRetVals 404 | { 405 | /** \brief Erroneous arguments were passed */ 406 | stateM_errArg = -2, 407 | /** 408 | * \brief The error state was reached 409 | * 410 | * This value is returned either when the state machine enters the error 411 | * state itself as a result of an error, or when the error state is the 412 | * next state as a result of a successful transition. 413 | * 414 | * The state machine enters the state machine if any of the following 415 | * happens: 416 | * - The current state is NULL 417 | * - A transition for the current event did not define the next state 418 | */ 419 | stateM_errorStateReached, 420 | /** \brief The current state changed into a non-final state */ 421 | stateM_stateChanged, 422 | /** 423 | * \brief The state changed back to itself 424 | * 425 | * The state can return to itself either directly or indirectly. An 426 | * indirect path may inlude a transition from a parent state and the use of 427 | * \ref state::entryState "entryStates". 428 | */ 429 | stateM_stateLoopSelf, 430 | /** 431 | * \brief The current state did not change on the given event 432 | * 433 | * If any event passed to the state machine should result in a state 434 | * change, this return value should be considered as an error. 435 | */ 436 | stateM_noStateChange, 437 | /** \brief A final state (any but the error state) was reached */ 438 | stateM_finalStateReached, 439 | }; 440 | 441 | /** 442 | * \brief Pass an event to the state machine 443 | * 444 | * The event will be passed to the current state, and possibly to the current 445 | * state's parent states (if any). If the event triggers a transition, a new 446 | * state will be entered. If the transition has an \ref transition::action 447 | * "action" defined, it will be called. If the transition is to a state other 448 | * than the current state, the current state's \ref state::exitAction 449 | * "exit action" is called (if defined). Likewise, if the state is a new 450 | * state, the new state's \ref state::entryAction "entry action" is called (if 451 | * defined). 452 | * 453 | * The returned value is negative if an error occurs. 454 | * 455 | * \param stateMachine the state machine to pass an event to. 456 | * \param event the event to be handled. 457 | * 458 | * \return #stateM_handleEventRetVals 459 | */ 460 | int stateM_handleEvent( struct stateMachine *stateMachine, 461 | struct event *event ); 462 | 463 | /** 464 | * \brief Get the current state 465 | * 466 | * \param stateMachine the state machine to get the current state from. 467 | * 468 | * \retval a pointer to the current state. 469 | * \retval NULL if \pn{stateMachine} is NULL. 470 | */ 471 | const struct state *stateM_currentState( struct stateMachine *stateMachine ); 472 | 473 | /** 474 | * \brief Get the previous state 475 | * 476 | * \param stateMachine the state machine to get the previous state from. 477 | * 478 | * \retval the previous state. 479 | * \retval NULL if \pn{stateMachine} is NULL. 480 | * \retval NULL if there has not yet been any transitions. 481 | */ 482 | const struct state *stateM_previousState( struct stateMachine *stateMachine ); 483 | 484 | /** 485 | * \brief Check if the state machine has stopped 486 | * 487 | * \param stateMachine the state machine to test. 488 | * 489 | * \retval true if the state machine has reached a final state. 490 | * \retval false if \pn{stateMachine} is NULL or if the current state is not a 491 | * final state. 492 | */ 493 | bool stateM_stopped( struct stateMachine *stateMachine ); 494 | 495 | #endif // STATEMACHINE_H 496 | 497 | /** 498 | * @} 499 | */ 500 | -------------------------------------------------------------------------------- /src/os_adapter.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | binary::wifi_mgmr::bl_ops_funcs_t, 3 | compat::{ 4 | bl602::{irq_attach, up_enable_irq}, 5 | common::{ 6 | pthread_mutex_lock, pthread_mutex_unlock, sleep, usleep, vsnprintf, EmulatedTimer, 7 | StrBuf, EMULATED_TIMER, 8 | }, 9 | get_time, 10 | malloc::{free, malloc}, 11 | queue::SimpleQueue, 12 | work_queue::work_queue, 13 | }, 14 | log, print, println, 15 | wifi::bl602_net_event, 16 | }; 17 | 18 | #[no_mangle] 19 | pub extern "C" fn bl_os_assert_func() {} 20 | 21 | #[no_mangle] 22 | static g_bl_ops_funcs: bl_ops_funcs_t = bl_ops_funcs_t { 23 | _version: 0x0001, 24 | _printf: Some(bl_os_printf), 25 | _init: Some(bl_os_api_init), 26 | _enter_critical: Some(bl_os_enter_critical), 27 | _exit_critical: Some(bl_os_exit_critical), 28 | _msleep: Some(bl_os_msleep), 29 | _sleep: Some(bl_os_sleep), 30 | _event_notify: Some(bl_os_event_notify), 31 | _lock_gaint: Some(bl_os_lock_gaint), 32 | _unlock_gaint: Some(bl_os_unlock_giant), 33 | _irq_attach: Some(bl_os_irq_attach), 34 | _irq_enable: Some(bl_os_irq_enable), 35 | _irq_disable: Some(bl_os_irq_disable), 36 | _workqueue_create: Some(bl_os_workqueue_create), 37 | _workqueue_submit_hp: Some(bl_os_workqueue_submit_hp), 38 | _workqueue_submit_lp: Some(bl_os_workqueue_submit_lp), 39 | _timer_create: Some(bl_os_timer_create), 40 | _timer_delete: Some(bl_os_timer_delete), 41 | _timer_start_once: Some(bl_os_timer_start_once), 42 | _timer_start_periodic: Some(bl_os_timer_start_periodic), 43 | _sem_create: Some(bl_os_sem_create), 44 | _sem_delete: Some(bl_os_sem_delete), 45 | _sem_take: Some(bl_os_sem_take), 46 | _sem_give: Some(bl_os_sem_give), 47 | _mutex_create: Some(bl_os_mutex_create), 48 | _mutex_delete: Some(bl_os_mutex_delete), 49 | _mutex_lock: Some(bl_os_mutex_lock), 50 | _mutex_unlock: Some(bl_os_mutex_unlock), 51 | _queue_create: Some(bl_os_queue_create), 52 | _queue_delete: Some(bl_os_queue_delete), 53 | _queue_send: Some(bl_os_queue_send), 54 | _queue_recv: Some(bl_os_queue_recv), 55 | _malloc: Some(bl_os_malloc), 56 | _free: Some(bl_os_free), 57 | _zalloc: Some(bl_os_zalloc), 58 | _get_time_ms: Some(bl_os_get_time_ms), 59 | _assert: Some(bl_os_assert), 60 | _event_group_create: Some(bl_os_event_group_create), 61 | _event_group_delete: Some(bl_os_event_group_delete), 62 | _event_group_send: Some(bl_os_event_group_send), 63 | _event_group_wait: Some(bl_os_event_group_wait), 64 | _event_register: Some(bl_os_event_register), 65 | _task_create: Some(bl_os_task_create), 66 | _task_delete: Some(bl_os_task_delete), 67 | _task_get_current_task: Some(bl_os_task_get_current_task), 68 | _task_notify_create: Some(bl_os_task_notify_create), 69 | _task_notify: Some(bl_os_task_notify), 70 | _task_wait: Some(bl_os_task_wait), 71 | _queue_send_wait: Some(bl_os_queue_send_wait), 72 | _get_tick: Some(bl_os_get_tick), 73 | _log_write: Some(bl_os_log_write), 74 | }; 75 | 76 | unsafe extern "C" fn bl_os_printf(fmt: *const crate::binary::c_types::c_char, args: ...) { 77 | let mut buf = [0u8; 512]; 78 | crate::compat::common::vsnprintf(&mut buf as *mut u8, 511, fmt as *const u8, args); 79 | let res_str = StrBuf::from(&buf as *const u8); 80 | print!("{}", res_str.as_str_ref()); 81 | } 82 | 83 | /**************************************************************************** 84 | * Name: bl_os_api_init 85 | * 86 | * Description: 87 | * 88 | * Input Parameters: 89 | * 90 | * Returned Value: 91 | * 92 | ****************************************************************************/ 93 | pub extern "C" fn bl_os_api_init() -> i32 { 94 | 0 95 | } 96 | 97 | /**************************************************************************** 98 | * Name: bl_os_enter_critical 99 | * 100 | * Description: 101 | * Enter critical state 102 | * 103 | * Input Parameters: 104 | * None 105 | * 106 | * Returned Value: 107 | * CPU PS value 108 | * 109 | ****************************************************************************/ 110 | pub unsafe extern "C" fn bl_os_enter_critical() -> u32 { 111 | log!("Unimplemented bl_os_enter_critical"); 112 | crate::compat::bl602::up_irq_save(); 113 | //riscv::interrupt::disable(); 114 | 1 115 | } 116 | 117 | /**************************************************************************** 118 | * Name: bl_os_exit_critical 119 | * 120 | * Description: 121 | * Exit from critical state 122 | * 123 | * Input Parameters: 124 | * level - CPU PS value 125 | * 126 | * Returned Value: 127 | * None 128 | * 129 | ****************************************************************************/ 130 | pub unsafe extern "C" fn bl_os_exit_critical(_level: u32) { 131 | log!("Unimplemented bl_os_exit_critical"); 132 | crate::compat::bl602::up_irq_restore(1); 133 | //riscv::interrupt::enable(); 134 | } 135 | 136 | /**************************************************************************** 137 | * Name: bl_os_msleep 138 | * 139 | * Description: 140 | * 141 | * Input Parameters: 142 | * 143 | * Returned Value: 144 | * 145 | ****************************************************************************/ 146 | pub unsafe extern "C" fn bl_os_msleep( 147 | ms: crate::binary::c_types::c_long, 148 | ) -> crate::binary::c_types::c_int { 149 | log!("msleep"); 150 | usleep(ms as u32); 151 | 0 152 | } 153 | 154 | /**************************************************************************** 155 | * Name: bl_os_sleep 156 | * 157 | * Description: 158 | * 159 | * Input Parameters: 160 | * 161 | * Returned Value: 162 | * 163 | ****************************************************************************/ 164 | pub unsafe extern "C" fn bl_os_sleep( 165 | seconds: crate::binary::c_types::c_uint, 166 | ) -> crate::binary::c_types::c_int { 167 | log!("sleep"); 168 | sleep(seconds); 169 | 0 170 | } 171 | 172 | /**************************************************************************** 173 | * Name: bl_os_event_notify 174 | * 175 | * Description: 176 | * 177 | * Input Parameters: 178 | * 179 | * Returned Value: 180 | * 181 | ****************************************************************************/ 182 | unsafe extern "C" fn bl_os_event_notify( 183 | evt: crate::binary::c_types::c_int, 184 | val: crate::binary::c_types::c_int, 185 | ) -> crate::binary::c_types::c_int { 186 | log!("event_notify"); 187 | bl602_net_event(evt, val as u32); 188 | return 0; 189 | } 190 | 191 | /**************************************************************************** 192 | * Name: bl_os_lock_gaint 193 | * 194 | * Description: 195 | * 196 | * Input Parameters: 197 | * 198 | * Returned Value: 199 | * 200 | ****************************************************************************/ 201 | unsafe extern "C" fn bl_os_lock_gaint() {} 202 | 203 | /**************************************************************************** 204 | * Name: bl_os_unlock_giant 205 | * 206 | * Description: 207 | * 208 | * Input Parameters: 209 | * 210 | * Returned Value: 211 | * 212 | ****************************************************************************/ 213 | unsafe extern "C" fn bl_os_unlock_giant() {} 214 | 215 | /**************************************************************************** 216 | * Name: bl_os_irq_attach 217 | * 218 | * Description: 219 | * 220 | * Input Parameters: 221 | * 222 | * Returned Value: 223 | * 224 | ****************************************************************************/ 225 | unsafe extern "C" fn bl_os_irq_attach( 226 | n: i32, 227 | f: *mut crate::binary::c_types::c_void, 228 | arg: *mut crate::binary::c_types::c_void, 229 | ) { 230 | log!("irq attach {} {:p} {:p}", n, f, arg); 231 | let isr = core::mem::transmute(f); 232 | irq_attach(n, isr, arg as *mut _ as *const u8); 233 | } 234 | 235 | /**************************************************************************** 236 | * Name: bl_os_irq_enable 237 | * 238 | * Description: 239 | * 240 | * Input Parameters: 241 | * 242 | * Returned Value: 243 | * 244 | ****************************************************************************/ 245 | unsafe extern "C" fn bl_os_irq_enable(n: i32) { 246 | log!("irq enable {}", n); 247 | up_enable_irq(n); 248 | } 249 | 250 | /**************************************************************************** 251 | * Name: bl_os_irq_disable 252 | * 253 | * Description: 254 | * 255 | * Input Parameters: 256 | * 257 | * Returned Value: 258 | * 259 | ****************************************************************************/ 260 | unsafe extern "C" fn bl_os_irq_disable(_n: i32) { 261 | unimplemented!("irq_disable"); 262 | } 263 | 264 | /**************************************************************************** 265 | * Name: bl_os_workqueue_create 266 | * 267 | * Description: 268 | * 269 | * Input Parameters: 270 | * 271 | * Returned Value: 272 | * 273 | ****************************************************************************/ 274 | 275 | unsafe extern "C" fn bl_os_workqueue_create() -> *mut crate::binary::c_types::c_void { 276 | log!("workqueue_create"); 277 | 1 as *mut crate::binary::c_types::c_void 278 | } 279 | 280 | /**************************************************************************** 281 | * Name: bl_os_workqueue_submit_hpwork 282 | * 283 | * Description: 284 | * 285 | * Input Parameters: 286 | * 287 | * Returned Value: 288 | * 289 | ****************************************************************************/ 290 | unsafe extern "C" fn bl_os_workqueue_submit_hp( 291 | work: *mut crate::binary::c_types::c_void, 292 | worker: *mut crate::binary::c_types::c_void, 293 | argv: *mut crate::binary::c_types::c_void, 294 | tick: crate::binary::c_types::c_long, 295 | ) -> crate::binary::c_types::c_int { 296 | log!( 297 | "workqueue_submit_hp {:p} {:p} {:p} {}", 298 | work, 299 | worker, 300 | argv, 301 | tick 302 | ); 303 | let worker = core::mem::transmute(worker); 304 | work_queue( 305 | 0, 306 | core::ptr::null_mut(), 307 | worker, 308 | core::ptr::null_mut(), 309 | tick, 310 | ) 311 | } 312 | 313 | /**************************************************************************** 314 | * Name: bl_os_workqueue_submit_lpwork 315 | * 316 | * Description: 317 | * 318 | * Input Parameters: 319 | * 320 | * Returned Value: 321 | * 322 | ****************************************************************************/ 323 | unsafe extern "C" fn bl_os_workqueue_submit_lp( 324 | work: *mut crate::binary::c_types::c_void, 325 | worker: *mut crate::binary::c_types::c_void, 326 | argv: *mut crate::binary::c_types::c_void, 327 | tick: crate::binary::c_types::c_long, 328 | ) -> crate::binary::c_types::c_int { 329 | log!( 330 | "workqueue_submit_lp {:p} {:p} {:p} {}", 331 | work, 332 | worker, 333 | argv, 334 | tick 335 | ); 336 | let worker = core::mem::transmute(worker); 337 | work_queue( 338 | 1, 339 | core::ptr::null_mut(), 340 | worker, 341 | core::ptr::null_mut(), 342 | tick, 343 | ) 344 | } 345 | 346 | /**************************************************************************** 347 | * Name: bl_os_timer_create 348 | * 349 | * Description: 350 | * 351 | * Input Parameters: 352 | * 353 | * Returned Value: 354 | * 355 | ****************************************************************************/ 356 | unsafe extern "C" fn bl_os_timer_create( 357 | func: *mut crate::binary::c_types::c_void, 358 | argv: *mut crate::binary::c_types::c_void, 359 | ) -> *mut crate::binary::c_types::c_void { 360 | log!("timer_create {:p} {:p}", func, argv); 361 | 362 | let mut free_idx = 0; 363 | for &et in EMULATED_TIMER.iter() { 364 | if et.is_some() { 365 | free_idx += 1; 366 | } else { 367 | break; 368 | } 369 | } 370 | if free_idx == EMULATED_TIMER.len() { 371 | panic!("No more timers left"); 372 | } 373 | 374 | EMULATED_TIMER[free_idx] = Some(EmulatedTimer { 375 | notify_function: core::mem::transmute(func), 376 | interval_secs: 0, 377 | next_notify: 0, 378 | }); 379 | 380 | (free_idx + 1) as *mut crate::binary::c_types::c_void 381 | } 382 | 383 | /**************************************************************************** 384 | * Name: bl_os_timer_delete 385 | * 386 | * Description: 387 | * 388 | * Input Parameters: 389 | * 390 | * Returned Value: 391 | * 392 | ****************************************************************************/ 393 | unsafe extern "C" fn bl_os_timer_delete( 394 | _timerid: *mut crate::binary::c_types::c_void, 395 | _tick: u32, 396 | ) -> crate::binary::c_types::c_int { 397 | unimplemented!() 398 | } 399 | 400 | /**************************************************************************** 401 | * Name: os_timer_start_once 402 | * 403 | * Description: 404 | * 405 | * Input Parameters: 406 | * 407 | * Returned Value: 408 | * 409 | ****************************************************************************/ 410 | unsafe extern "C" fn bl_os_timer_start_once( 411 | _timerid: *mut crate::binary::c_types::c_void, 412 | _t_sec: crate::binary::c_types::c_long, 413 | _t_nsec: crate::binary::c_types::c_long, 414 | ) -> crate::binary::c_types::c_int { 415 | unimplemented!() 416 | } 417 | 418 | /**************************************************************************** 419 | * Name: os_timer_start_periodic 420 | * 421 | * Description: 422 | * 423 | * Input Parameters: 424 | * 425 | * Returned Value: 426 | * 427 | ****************************************************************************/ 428 | unsafe extern "C" fn bl_os_timer_start_periodic( 429 | timerid: *mut crate::binary::c_types::c_void, 430 | t_sec: crate::binary::c_types::c_long, 431 | t_nsec: crate::binary::c_types::c_long, 432 | ) -> crate::binary::c_types::c_int { 433 | log!("timer_start_periodic {:p} {} {}", timerid, t_sec, t_nsec); 434 | 435 | let mut timer = &mut EMULATED_TIMER[timerid as usize - 1].unwrap(); 436 | timer.interval_secs = t_sec as u32; 437 | timer.next_notify = get_time().0 + t_sec as u32 * 1000; 438 | 439 | log!( 440 | "curr time = {} - next notify {}", 441 | get_time(), 442 | timer.next_notify 443 | ); 444 | 445 | 0 446 | } 447 | 448 | /**************************************************************************** 449 | * Name: bl_os_sem_create 450 | * 451 | * Description: 452 | * Create and initialize semaphore 453 | * 454 | * Input Parameters: 455 | * max - No mean 456 | * init - semaphore initialization value 457 | * 458 | * Returned Value: 459 | * Semaphore data pointer 460 | * 461 | ****************************************************************************/ 462 | unsafe extern "C" fn bl_os_sem_create(init: u32) -> *mut crate::binary::c_types::c_void { 463 | log!("create sem {}", init); 464 | 465 | let mut res = 0xffff; 466 | for (i, sem) in CURR_SEM.iter().enumerate() { 467 | if let None = *sem { 468 | res = i; 469 | break; 470 | } 471 | } 472 | 473 | log!("sem created res = {} (+1)", res); 474 | 475 | if res != 0xffff { 476 | CURR_SEM[res] = Some(init); 477 | (res + 1) as *mut crate::binary::c_types::c_void 478 | } else { 479 | core::ptr::null_mut() 480 | } 481 | } 482 | 483 | static mut CURR_SEM: [Option; 10] = 484 | [None, None, None, None, None, None, None, None, None, None]; 485 | 486 | /**************************************************************************** 487 | * Name: bl_os_sem_delete 488 | * 489 | * Description: 490 | * Delete semaphore 491 | * 492 | * Input Parameters: 493 | * semphr - Semaphore data pointer 494 | * 495 | * Returned Value: 496 | * None 497 | * 498 | ****************************************************************************/ 499 | unsafe extern "C" fn bl_os_sem_delete(semphr: *mut crate::binary::c_types::c_void) { 500 | log!("sem delete {:p}", semphr); 501 | CURR_SEM[semphr as usize - 1] = None; 502 | } 503 | 504 | /**************************************************************************** 505 | * Name: bl_os_sem_take 506 | * 507 | * Description: 508 | * Wait semaphore within a certain period of time 509 | * 510 | * Input Parameters: 511 | * semphr - Semaphore data pointer 512 | * ticks - Wait system ticks 513 | * 514 | * Returned Value: 515 | * True if success or false if fail 516 | * 517 | ****************************************************************************/ 518 | unsafe extern "C" fn bl_os_sem_take(semphr: *mut crate::binary::c_types::c_void, tick: u32) -> i32 { 519 | log!("sem_take {:p} {}", semphr, tick); 520 | 521 | let forever = if tick == 0 { true } else { false }; 522 | let tick = if tick == 0 { 1 } else { tick }; 523 | 524 | loop { 525 | for _ in 0..tick as usize { 526 | let res = riscv::interrupt::free(|_| { 527 | if let Some(cnt) = CURR_SEM[semphr as usize - 1] { 528 | if cnt > 0 { 529 | CURR_SEM[semphr as usize - 1] = Some(cnt - 1); 530 | 1 531 | } else { 532 | 0 533 | } 534 | } else { 535 | 0 536 | } 537 | }); 538 | 539 | if res == 1 { 540 | return 1; 541 | } 542 | } 543 | 544 | if !forever { 545 | break; 546 | } 547 | } 548 | 549 | 0 550 | } 551 | 552 | /**************************************************************************** 553 | * Name: bl_os_sem_give 554 | * 555 | * Description: 556 | * Post semaphore 557 | * 558 | * Input Parameters: 559 | * semphr - Semaphore data pointer 560 | * 561 | * Returned Value: 562 | * True if success or false if fail 563 | * 564 | ****************************************************************************/ 565 | unsafe extern "C" fn bl_os_sem_give(semphr: *mut crate::binary::c_types::c_void) -> i32 { 566 | log!("sem_give {:p}", semphr); 567 | 568 | let res = riscv::interrupt::free(|_| { 569 | if let Some(cnt) = CURR_SEM[semphr as usize - 1] { 570 | CURR_SEM[semphr as usize - 1] = Some(cnt + 1); 571 | 1 572 | } else { 573 | 0 574 | } 575 | }); 576 | 577 | res 578 | } 579 | 580 | /**************************************************************************** 581 | * Name: bl_os_mutex_create 582 | * 583 | * Description: 584 | * Create mutex 585 | * 586 | * Input Parameters: 587 | * None 588 | * 589 | * Returned Value: 590 | * Mutex data pointer 591 | * 592 | ****************************************************************************/ 593 | unsafe extern "C" fn bl_os_mutex_create() -> *mut crate::binary::c_types::c_void { 594 | log!("mutex create"); 595 | 1 as *mut crate::binary::c_types::c_void 596 | } 597 | 598 | /**************************************************************************** 599 | * Name: bl_os_mutex_delete 600 | * 601 | * Description: 602 | * Delete mutex 603 | * 604 | * Input Parameters: 605 | * mutex_data - mutex data pointer 606 | * 607 | * Returned Value: 608 | * None 609 | * 610 | ****************************************************************************/ 611 | unsafe extern "C" fn bl_os_mutex_delete(_mutex: *mut crate::binary::c_types::c_void) { 612 | unimplemented!("mutex delete") 613 | } 614 | 615 | /**************************************************************************** 616 | * Name: bl_os_mutex_lock 617 | * 618 | * Description: 619 | * Lock mutex 620 | * 621 | * Input Parameters: 622 | * mutex_data - mutex data pointer 623 | * 624 | * Returned Value: 625 | * True if success or false if fail 626 | * 627 | ****************************************************************************/ 628 | unsafe extern "C" fn bl_os_mutex_lock(mutex: *mut crate::binary::c_types::c_void) -> i32 { 629 | log!("mutex lock"); 630 | pthread_mutex_lock(mutex as *mut u8); 631 | 1 632 | } 633 | 634 | /**************************************************************************** 635 | * Name: bl_os_mutex_unlock 636 | * 637 | * Description: 638 | * Lock mutex 639 | * 640 | * Input Parameters: 641 | * mutex_data - mutex data pointer 642 | * 643 | * Returned Value: 644 | * True if success or false if fail 645 | * 646 | ****************************************************************************/ 647 | unsafe extern "C" fn bl_os_mutex_unlock(mutex: *mut crate::binary::c_types::c_void) -> i32 { 648 | log!("mutex unlock"); 649 | pthread_mutex_unlock(mutex as *mut u8); 650 | 1 651 | } 652 | 653 | /**************************************************************************** 654 | * Name: bl_os_workqueue_create 655 | * 656 | * Description: 657 | * 658 | * Input Parameters: 659 | * 660 | * Returned Value: 661 | * 662 | ****************************************************************************/ 663 | unsafe extern "C" fn bl_os_queue_create( 664 | queue_len: u32, 665 | item_size: u32, 666 | ) -> *mut crate::binary::c_types::c_void { 667 | log!("queue_create len={} item_size={}", queue_len, item_size); 668 | 669 | let res = riscv::interrupt::free(|_| { 670 | let mut res = 0xffff; 671 | for (i, sem) in MESSAGE_QUEUES.iter().enumerate() { 672 | if let None = *sem { 673 | res = i; 674 | break; 675 | } 676 | } 677 | 678 | if res == 0xffff { 679 | panic!("No more messafe queues available"); 680 | } 681 | 682 | MESSAGE_QUEUES[res] = Some(SimpleQueue::new()); 683 | 684 | res 685 | }); 686 | 687 | res as *mut crate::binary::c_types::c_void 688 | } 689 | 690 | struct MqMessage { 691 | data: [u8; 256], 692 | len: usize, 693 | } 694 | 695 | static mut MESSAGE_QUEUES: [Option>; 2] = [None, None]; 696 | 697 | /**************************************************************************** 698 | * Name: bl_os_mq_delete 699 | * 700 | * Description: 701 | * 702 | * Input Parameters: 703 | * 704 | * Returned Value: 705 | * 706 | ****************************************************************************/ 707 | unsafe extern "C" fn bl_os_queue_delete(_queue: *mut crate::binary::c_types::c_void) { 708 | unimplemented!("queue_delete") 709 | } 710 | 711 | /**************************************************************************** 712 | * Name: bl_os_mq_send_generic 713 | * 714 | * Description: 715 | * Generic send message to queue within a certain period of time 716 | * 717 | * Input Parameters: 718 | * queue - Message queue data pointer 719 | * item - Message data pointer 720 | * ticks - Wait ticks 721 | * prio - Message priority 722 | * 723 | * Returned Value: 724 | * True if success or false if fail 725 | * 726 | ****************************************************************************/ 727 | unsafe extern "C" fn bl_os_queue_send( 728 | queue: *mut crate::binary::c_types::c_void, 729 | item: *mut crate::binary::c_types::c_void, 730 | len: u32, 731 | ) -> crate::binary::c_types::c_int { 732 | log!("queue_send {:p} {:p} {} {}", queue, item, len, 0,); 733 | 734 | let message = item as *const u8; 735 | let queue = queue as usize; 736 | let success = riscv::interrupt::free(|_| { 737 | if let Some(ref mut queue) = MESSAGE_QUEUES[queue] { 738 | let mut data = [0u8; 256]; 739 | for i in 0..len as usize { 740 | data[i] = *(message.offset(i as isize)); 741 | } 742 | 743 | let msg = MqMessage { 744 | data, 745 | len: len as usize, 746 | }; 747 | 748 | queue.enqueue(msg) 749 | } else { 750 | false 751 | } 752 | }); 753 | 754 | if success { 755 | 1 756 | } else { 757 | 0 758 | } 759 | } 760 | 761 | /**************************************************************************** 762 | * Name: bl_os_mq_recv 763 | * 764 | * Description: 765 | * Receive message from queue within a certain period of time 766 | * 767 | * Input Parameters: 768 | * queue - Message queue data pointer 769 | * item - Message data pointer 770 | * ticks - Wait ticks 771 | * 772 | * Returned Value: 773 | * True if success or false if fail 774 | * 775 | ****************************************************************************/ 776 | unsafe extern "C" fn bl_os_queue_recv( 777 | queue: *mut crate::binary::c_types::c_void, 778 | item: *mut crate::binary::c_types::c_void, 779 | len: u32, 780 | tick: u32, 781 | ) -> crate::binary::c_types::c_int { 782 | log!("queue recv {:p} {:p} {} {}", queue, item, len, tick); 783 | 784 | // TODO implement waiting 785 | let queue = queue as usize; 786 | let res = riscv::interrupt::free(|_| { 787 | if let Some(ref mut queue) = MESSAGE_QUEUES[queue] { 788 | queue.dequeue() 789 | } else { 790 | None 791 | } 792 | }); 793 | 794 | let mut received_bytes: i32 = 0; 795 | let msg = item as *mut u8; 796 | 797 | match res { 798 | core::option::Option::Some(message) => { 799 | for i in 0..message.len { 800 | *(msg.offset(i as isize)) = message.data[i]; 801 | } 802 | 803 | log!("copied message with len {}", message.len); 804 | 805 | received_bytes = message.len as i32; 806 | } 807 | core::option::Option::None => {} 808 | }; 809 | 810 | log!("queue recv - received bytes: {}", received_bytes); 811 | 812 | if received_bytes > 0 { 813 | 1 814 | } else { 815 | 0 816 | } 817 | } 818 | 819 | /**************************************************************************** 820 | * Name: bl_os_malloc 821 | * 822 | * Description: 823 | * Allocate a block of memory 824 | * 825 | * Input Parameters: 826 | * size - memory size 827 | * 828 | * Returned Value: 829 | * Memory pointer 830 | * 831 | ****************************************************************************/ 832 | unsafe extern "C" fn bl_os_malloc( 833 | size: crate::binary::c_types::c_uint, 834 | ) -> *mut crate::binary::c_types::c_void { 835 | log!("malloc {}", size); 836 | malloc(size) as *mut crate::binary::c_types::c_void 837 | } 838 | 839 | /**************************************************************************** 840 | * Name: bl_os_free 841 | * 842 | * Description: 843 | * Free a block of memory 844 | * 845 | * Input Parameters: 846 | * ptr - memory block 847 | * 848 | * Returned Value: 849 | * No 850 | * 851 | ****************************************************************************/ 852 | unsafe extern "C" fn bl_os_free(p: *mut crate::binary::c_types::c_void) { 853 | log!("free {:p}", p); 854 | free(p as *const u8); 855 | } 856 | 857 | /**************************************************************************** 858 | * Name: bl_os_zalloc 859 | * 860 | * Description: 861 | * Allocate a block of memory 862 | * 863 | * Input Parameters: 864 | * size - memory size 865 | * 866 | * Returned Value: 867 | * Memory pointer 868 | * 869 | ****************************************************************************/ 870 | pub unsafe extern "C" fn bl_os_zalloc( 871 | size: crate::binary::c_types::c_uint, 872 | ) -> *mut crate::binary::c_types::c_void { 873 | log!("zalloc {}", size); 874 | let res = malloc(size) as *mut crate::binary::c_types::c_void; 875 | for i in 0..size { 876 | (res as *mut u8).offset(i as isize).write_volatile(0); 877 | } 878 | 879 | res 880 | } 881 | 882 | /**************************************************************************** 883 | * Name: bl_os_clock_gettime_ms 884 | * 885 | * Description: 886 | * 887 | * Input Parameters: 888 | * 889 | * Returned Value: 890 | * 891 | ****************************************************************************/ 892 | unsafe extern "C" fn bl_os_get_time_ms() -> u64 { 893 | get_time().0 as u64 894 | } 895 | 896 | unsafe extern "C" fn bl_os_assert( 897 | _file: *const crate::binary::c_types::c_char, 898 | _line: crate::binary::c_types::c_int, 899 | _func: *const crate::binary::c_types::c_char, 900 | _expr: *const crate::binary::c_types::c_char, 901 | ) { 902 | unimplemented!() 903 | } 904 | 905 | unsafe extern "C" fn bl_os_event_group_create() -> *mut crate::binary::c_types::c_void { 906 | unimplemented!() 907 | } 908 | 909 | unsafe extern "C" fn bl_os_event_group_delete(_event: *mut crate::binary::c_types::c_void) { 910 | unimplemented!() 911 | } 912 | 913 | unsafe extern "C" fn bl_os_event_group_send( 914 | _event: *mut crate::binary::c_types::c_void, 915 | _bits: u32, 916 | ) -> u32 { 917 | unimplemented!() 918 | } 919 | 920 | unsafe extern "C" fn bl_os_event_group_wait( 921 | _event: *mut crate::binary::c_types::c_void, 922 | _bits_to_wait_for: u32, 923 | _clear_on_exit: crate::binary::c_types::c_int, 924 | _wait_for_all_bits: crate::binary::c_types::c_int, 925 | _block_time_tick: u32, 926 | ) -> u32 { 927 | unimplemented!() 928 | } 929 | 930 | unsafe extern "C" fn bl_os_event_register( 931 | _type_: crate::binary::c_types::c_int, 932 | _cb: *mut crate::binary::c_types::c_void, 933 | _arg: *mut crate::binary::c_types::c_void, 934 | ) -> crate::binary::c_types::c_int { 935 | unimplemented!() 936 | } 937 | 938 | unsafe extern "C" fn bl_os_task_create( 939 | _name: *const crate::binary::c_types::c_char, 940 | _entry: *mut crate::binary::c_types::c_void, 941 | _stack_depth: u32, 942 | _param: *mut crate::binary::c_types::c_void, 943 | _prio: u32, 944 | _task_handle: *mut crate::binary::c_types::c_void, 945 | ) -> crate::binary::c_types::c_int { 946 | unimplemented!() 947 | } 948 | 949 | unsafe extern "C" fn bl_os_task_delete(_task_handle: *mut crate::binary::c_types::c_void) { 950 | unimplemented!() 951 | } 952 | 953 | unsafe extern "C" fn bl_os_task_get_current_task() -> *mut crate::binary::c_types::c_void { 954 | unimplemented!() 955 | } 956 | 957 | unsafe extern "C" fn bl_os_task_notify_create() -> *mut crate::binary::c_types::c_void { 958 | unimplemented!() 959 | } 960 | 961 | unsafe extern "C" fn bl_os_task_notify(_task_handle: *mut crate::binary::c_types::c_void) { 962 | unimplemented!() 963 | } 964 | 965 | unsafe extern "C" fn bl_os_task_wait( 966 | _task_handle: *mut crate::binary::c_types::c_void, 967 | _tick: u32, 968 | ) { 969 | unimplemented!() 970 | } 971 | 972 | unsafe extern "C" fn bl_os_queue_send_wait( 973 | _queue: *mut crate::binary::c_types::c_void, 974 | _item: *mut crate::binary::c_types::c_void, 975 | _len: u32, 976 | _ticks: u32, 977 | _prio: crate::binary::c_types::c_int, 978 | ) -> crate::binary::c_types::c_int { 979 | unimplemented!() 980 | } 981 | 982 | unsafe extern "C" fn bl_os_get_tick() -> u32 { 983 | get_time().0 984 | } 985 | 986 | unsafe extern "C" fn bl_os_log_write( 987 | level: u32, 988 | tag: *const crate::binary::c_types::c_char, 989 | file: *const crate::binary::c_types::c_char, 990 | line: crate::binary::c_types::c_int, 991 | format: *const crate::binary::c_types::c_char, 992 | args: ... 993 | ) { 994 | let tag = if tag.is_null() { 995 | StrBuf::new() 996 | } else { 997 | StrBuf::from(tag) 998 | }; 999 | let file = StrBuf::from(file); 1000 | 1001 | let mut buf = [0u8; 512]; 1002 | vsnprintf(&mut buf as *mut u8, 511, format, args); 1003 | let res_str = StrBuf::from(&buf as *const u8); 1004 | print!("{}", res_str.as_str_ref()); 1005 | 1006 | println!( 1007 | "{} {} {}:{} {}", 1008 | level, 1009 | tag.as_str_ref(), 1010 | file.as_str_ref(), 1011 | line, 1012 | res_str.as_str_ref(), 1013 | ); 1014 | } 1015 | --------------------------------------------------------------------------------