diff --git a/.vscode/launch.json b/.vscode/launch.json index 2b76fa0e1cf361a7bbfb2eee245abd53f26d41cc..130ad1f0c000ab9d02cc1deeb69508ef50d8cc66 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,10 +9,8 @@ "request": "attach", "name": "Debug hello", "gdbpath": "/usr/bin/arm-none-eabi-gdb", - //"executable": ".target/thumbv7em-none-eabihf/debug/examples/hello", "target": ":3333", "remote": true, - //"debugger_args": [], "autorun": [ "monitor reset halt", "monitor arm semihosting enable", @@ -26,10 +24,8 @@ "request": "attach", "name": "Debug gpio", "gdbpath": "/usr/bin/arm-none-eabi-gdb", - //"executable": ".target/thumbv7em-none-eabihf/debug/examples/hello", "target": ":3333", "remote": true, - //"debugger_args": [], "autorun": [ "monitor reset halt", "monitor arm semihosting enable", @@ -41,19 +37,51 @@ { "type": "gdb", "request": "attach", - "name": "Debug usart1", + "name": "Debug itm", "gdbpath": "/usr/bin/arm-none-eabi-gdb", - //"executable": ".target/thumbv7em-none-eabihf/debug/examples/hello", "target": ":3333", "remote": true, - //"debugger_args": [], "autorun": [ "monitor reset halt", "monitor arm semihosting enable", - "file ./target/thumbv7em-none-eabihf/debug/examples/usart1", + "monitor tpiu config external uart off 8000000 2000000", + "monitor itm port 0 on", + "file ./target/thumbv7em-none-eabihf/debug/examples/itm", + "load" + ], + "cwd": "${workspaceRoot}" + }, + { + "type": "gdb", + "request": "attach", + "name": "Debug ble_hid", + "gdbpath": "/usr/bin/arm-none-eabi-gdb", + "target": ":3333", + "remote": true, + "autorun": [ + "monitor reset init", + "monitor arm semihosting enable", + "file ./target/thumbv7em-none-eabihf/debug/examples/ble_hid", "load" ], "cwd": "${workspaceRoot}" + }, + { + "type": "gdb", + "request": "attach", + "name": "Debug usart1", + "gdbpath": "/usr/bin/arm-none-eabi-gdb", + "target": ":3333", + "remote": true, + "autorun": [ + "monitor reset-init", + "monitor arm semihosting enable", + "file ./target/thumbv7em-none-eabihf/debug/examples/usart1", + "load", + "monitor reset-init", + "info target" + ], + "cwd": "${workspaceRoot}" } ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a490cda5dae2e78433f2b335578169fc2e3be2a7..5b92a69c579dceef58622eaa08c90cc7b0fadb73 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -31,6 +31,22 @@ "taskName": "xargo build --example usart1", "type": "shell", "command": "xargo build --example usart1", + "problemMatcher": [ + "$rustc" + ] + }, + { + "taskName": "xargo build --example itm", + "type": "shell", + "command": "xargo build --example itm", + "problemMatcher": [ + "$rustc" + ] + }, + { + "taskName": "xargo build --example ble_hid", + "type": "shell", + "command": "xargo build --example ble_hid", "problemMatcher": [ "$rustc" ], diff --git a/Cargo.toml b/Cargo.toml index 3f06ac7dfbd53ada79d30055cabd4d911799763c..797c6a6afd3fdebee1fa703f62eb024e447a7751 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,9 @@ cortex-m-semihosting = "0.2.0" features = ["abort-on-panic"] version = "0.3.5" +[dev-dependencies.hal] +path = "hal" + [profile.release] debug = true lto = true diff --git a/examples/ble_hid.rs b/examples/ble_hid.rs new file mode 100644 index 0000000000000000000000000000000000000000..dad30a573d2da5851fabed138a9dc8fb8f6e757f --- /dev/null +++ b/examples/ble_hid.rs @@ -0,0 +1,374 @@ +//! Example application +//#![deny(unsafe_code)] +//#![deny(warnings)] +#![feature(proc_macro)] +#![no_std] + +extern crate cortex_m_rtfm as rtfm; +extern crate hal; +#[macro_use] +extern crate nucleo_64; + +use hal::usart::USART; + +use rtfm::app; + +app! { + device: nucleo_64::stm32f40x, +} + +fn init(p: init::Peripherals) { + p.DWT.enable_cycle_counter(); + unsafe { + p.DWT.cyccnt.write(0); + } + + p.FLASH.acr.reset(); //////////latency().write().bits(2); + p.FLASH.acr.modify(|_, w| unsafe {w.latency().bits(2)} ); //////////latency().write().bits(2); + + //modify(|_, w | w.latency().set_bits(2)); + println!("Init! {:x}", p.FLASH.acr.read().latency().bits()); + + + //////////////////////////////////////////////////////////////////////////////////////////////// + // Clock stuff! + //////////////////////////////////////////////////////////////////////////////////////////////// + // PP PLLN PLLM + //rcc().pllcfgr.write(|w| w.bits(0b0000 0000 0000 00 01 0 101010000 010000)); + + + + rtfm::bkpt(); + p.RCC.cfgr.modify(|_, w| w.sw0().clear_bit()); //Switch to HSI + p.RCC.cfgr.modify(|_, w| w.sw1().clear_bit()); //Switch to HSI + rtfm::bkpt(); + p.RCC.cfgr.modify(|_, w| unsafe { w.ppre1().bits(4) }); //Configure apb1 prescaler = 2 + p.RCC.apb1enr.modify(|_, w| w.pwren().set_bit()); + p.RCC.cr.write(|w| w.pllon().clear_bit()); //Enable PLL + p.RCC + .pllcfgr + .write(|w| unsafe { w.bits(0b00000000000000010101010000010000) }); //Configure PLL + + p.RCC.cr.modify(|_, w| w.pllon().set_bit()); //Enable PLL + + while p.RCC.cr.read().pllrdy().bit_is_clear() {} + + p.RCC.cfgr.modify(|_, w| w.sw0().clear_bit()); //Switch to PLL + rtfm::bkpt(); + p.RCC.cfgr.modify(|_, w| w.sw1().set_bit()); //Switch to PLL + rtfm::bkpt(); + p.RCC.apb2enr.modify(|_, w| w.syscfgen().set_bit()); + rtfm::bkpt(); + + p.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); //Enable GPIOA clock + p.RCC.ahb1enr.modify(|_, w| w.gpioben().set_bit()); //Enable GPIOB clock + + //////////////////////////////////////////////////////////////////////////////////////////////// + // USART2 stuff + //////////////////////////////////////////////////////////////////////////////////////////////// + + rtfm::bkpt(); + USART::initialize(p.GPIOA, p.RCC, p.USART2); + USART::send(p.USART2, "\n\n\nUSART initialized\n\r"); + //////////////////////////////////////////////////////////////////////////////////////////////// + + //spi.initialize(); + //i2c.initialize(); + +} + +fn idle() -> ! { + rtfm::bkpt(); + + rtfm::bkpt(); + + println!("Hello, world!"); + + rtfm::bkpt(); + loop { + rtfm::wfi(); + } +} + +/* +//#[macro_use] +extern crate hal_core; +use hal_core::*; + +extern crate hal; +use hal::spi::*; +use hal::bt::*; +use hal::usart::*; +use hal::i2c::*; + +extern crate stm32f401; +use stm32f401::base::*; +use stm32f401::gpioa::*; +use stm32f401::gpiob::*; +use stm32f401::rcc::*; +use stm32f401::usart2::*; +use stm32f401::spi1::*; +use stm32f401::exti::*; +use stm32f401::i2c1::*; + +extern crate cortex_m; +//use cortex_m::peripheral::*; +use cortex_m::interrupt; + +use jap::{exceptions, interrupts}; + +pub fn usart2() -> &'static mut Usart2 { + unsafe { &mut *(USART2_BASE as *mut Usart2) } +} + +pub fn i2c1() -> &'static mut I2c1 { + unsafe { &mut *(I2C1_BASE as *mut I2c1) } +} + +pub fn spi1() -> &'static mut Spi1 { + unsafe { &mut *(SPI1_BASE as *mut Spi1) } +} + +pub fn gpioa() -> &'static mut Gpioa { + unsafe { &mut *(GPIOA_BASE as *mut Gpioa) } +} + +pub fn gpiob() -> &'static mut Gpiob { + unsafe { &mut *(GPIOB_BASE as *mut Gpiob) } +} + +pub fn p.RCC -> &'static mut Rcc { + unsafe { &mut *(RCC_BASE as *mut Rcc) } +} + +pub fn exti() -> &'static mut Exti { + unsafe { &mut *(EXTI_BASE as *mut Exti) } +} + +pub extern "C" fn exti0_handler() { + unsafe { usart.send("Received data: \n\r") }; + + exti().pr.modify(|_, w| unsafe { w.pr0().bits(1) }); // clr interrupt +} + +// We need a `main` function, just like every other Rust program +fn main() { + let mut hid_service_handle: [u8; 2] = [0; 2]; + let mut hid_report_char_handle: [u8; 2] = [0; 2]; + let mut mode: bool = true; + + interrupt::free(|_| { + //nvic().set_priority(interrupts::Interrupt::Exti0, 0); // highest + //nvic().enable(interrupts::Interrupt::Exti0); + }); + + dwt_driver::set_cyccntena(); + + //////////////////////////////////////////////////////////////////////////////////////////////// + // Clock stuff! + //////////////////////////////////////////////////////////////////////////////////////////////// + // PP PLLN PLLM + //p.RCC.pllcfgr.write(|w| w.bits(0b0000 0000 0000 00 01 0 101010000 010000)); + p.RCC.cfgr.modify(|_, w| unsafe { w.sw0().bits(0) }); //Switch to HSI + p.RCC.cfgr.modify(|_, w| unsafe { w.sw1().bits(0) }); //Switch to HSI + p.RCC.cfgr.modify(|_, w| unsafe { w.ppre1().bits(4) }); //Configure apb1 prescaler = 2 + p.RCC.apb1enr.modify(|_, w| unsafe { w.pwren().bits(1) }); + p.RCC.cr.write(|w| unsafe { w.pllon().bits(0) }); //Enable PLL + p.RCC + .pllcfgr + .write(|w| unsafe { w.bits(0b00000000000000010101010000010000) }); //Configure PLL + p.RCC.cr.modify(|_, w| unsafe { w.pllon().bits(1) }); //Enable PLL + p.RCC.cfgr.modify(|_, w| unsafe { w.sw0().bits(0) }); //Switch to PLL + p.RCC.cfgr.modify(|_, w| unsafe { w.sw1().bits(1) }); + + p.RCC.apb2enr.modify(|_, w| unsafe { w.syscfgen().bits(1) }); + + p.RCC.ahb1enr.modify(|_, w| unsafe { w.gpioaen().bits(1) }); //Enable GPIOA clock + p.RCC.ahb1enr.modify(|_, w| unsafe { w.gpioben().bits(1) }); //Enable GPIOB clock + + //////////////////////////////////////////////////////////////////////////////////////////////// + // USART2 stuff + //////////////////////////////////////////////////////////////////////////////////////////////// + + unsafe { usart.initialize() }; + unsafe { usart.send("\n\n\nUSART initialized\n\r") }; + + //////////////////////////////////////////////////////////////////////////////////////////////// + + spi.initialize(); + i2c.initialize(); + + //exti().imr.modify(|_, w| unsafe { w.mr0().bits(1) }); // interrupt mask + //exti().rtsr.modify(|_, w| unsafe { w.tr0().bits(1) }); // rising edge + + loop { + if mode == true { + bt.restart_bt(); + + bt.configure_bt_address(); + dwt_driver::wait_cycles(30_000); + + bt.gatt_service_init(); + dwt_driver::wait_cycles(30_000); + + bt.gap_service_init(); + dwt_driver::wait_cycles(30_000); + + bt.gap_set_io_capability(); + dwt_driver::wait_cycles(30_000); + + bt.gap_set_auth_requirments(); + dwt_driver::wait_cycles(30_000); + + hid_service_handle = bt.start_hid_service(); + dwt_driver::wait_cycles(30_000); + + let hid_protocol_mode_char_handle = + bt.hid_add_protocol_mode_characteristic(hid_service_handle); + dwt_driver::wait_cycles(30_000); + + bt.hid_set_protocol_mode_characteristic( + hid_service_handle, + hid_protocol_mode_char_handle, + ); + dwt_driver::wait_cycles(30_000); + + /*let hid_boot_mouse_report_char_handle = */ + bt.hid_add_boot_mouse_input_report_characteristic( + hid_service_handle, + ); + dwt_driver::wait_cycles(30_000); + + let hid_information_char_handle = + bt.hid_add_information_characteristic(hid_service_handle); + dwt_driver::wait_cycles(30_000); + + bt.hid_set_information_characteristic( + hid_service_handle, + hid_information_char_handle, + ); + dwt_driver::wait_cycles(30_000); + + /*let HIDControlPointCharactersiticHandle = */ + bt.hid_add_control_point_characteristic(hid_service_handle); + dwt_driver::wait_cycles(30_000); + + let hid_report_map_char_handle = + bt.hid_add_report_map_characteristic(hid_service_handle); + dwt_driver::wait_cycles(30_000); + + bt.hid_set_report_map_characteristic( + hid_service_handle, + hid_report_map_char_handle, + ); + dwt_driver::wait_cycles(30_000); + + hid_report_char_handle = + bt.hid_add_report_characteristic(hid_service_handle); + dwt_driver::wait_cycles(30_000); + + bt.hid_add_report_description( + hid_service_handle, + hid_report_char_handle, + ); + dwt_driver::wait_cycles(30_000); + + let battery_level_service_handle = bt.start_battery_level_service(); + dwt_driver::wait_cycles(30_000); + + let battery_level_char_handle = + bt.add_battery_level_characteristic( + battery_level_service_handle, + ); + dwt_driver::wait_cycles(30_000); + + bt.add_presentation_format_description( + battery_level_service_handle, + battery_level_char_handle, + ); + dwt_driver::wait_cycles(30_000); + + let device_information_service_handle = + bt.start_device_information_service(); + dwt_driver::wait_cycles(30_000); + + bt.add_pnp_id_characteristic(device_information_service_handle); + dwt_driver::wait_cycles(30_000); + + bt.gap_set_discoverable(); + dwt_driver::wait_cycles(30_000); + + mode = false; + } else { + let mut data: [u8; 128] = [0; 128]; + + data[0] = 0x60; + + i2c.write_memory(data, 1); + + let ident = i2c.read_memory(0x0f); + if ident != 104 { + loop {} + } + let xindata = i2c.read_memory(0x28); + let xindata2 = i2c.read_memory(0x29); + let yindata = i2c.read_memory(0x2A); + let yindata2 = i2c.read_memory(0x2B); + + let xvalue: i16 = + (((xindata2 as i16) << 8) + (xindata as i16)) / 500; // 100; + let yvalue: i16 = + (((yindata2 as i16) << 8) + (yindata as i16)) / 500; // 100; + + bt.set_report_characteristic( + hid_service_handle, + hid_report_char_handle, + xvalue, + yvalue, + ); + dwt_driver::wait_cycles(84_000_000); + } + + let response = bt.spi_read(); + + if response[0] == 4 && response[1] == 5 && response[2] == 4 + /*&& response[3] == 0 && response[4] == 1 && response[5] == 8 && response[6] == 19*/ + { + unsafe { usart.send("Disconnected\n\r") }; + mode = true; + } else if response[0] == 4 && response[1] == 255 && response[2] == 3 + && response[3] == 1 && response[4] == 0 + && response[5] == 1 + { + unsafe { usart.send("Restarted BT\n\r") }; + } else if response[0] == 4 && response[1] == 62 && response[2] == 19 + && response[3] == 1 + { + unsafe { usart.send("Connected complete event!\n\r") }; + } else if response[0] == 4 && response[1] == 62 && response[2] == 10 + && response[3] == 3 + { + unsafe { usart.send("Connection update complete\n\r") }; + } else if response[0] == 4 && response[1] == 8 && response[2] == 4 { + unsafe { usart.send("Encryption change\n\r") }; + } else { + //Nothing we bother with + //unsafe { usart.send("Received data: unknown\n\r") }; + } + } +} + +// The program must specify how exceptions will be handled +// Here we just use the default handler to handle all the exceptions +#[no_mangle] +pub static _EXCEPTIONS: exceptions::Handlers = exceptions::Handlers { + ..exceptions::DEFAULT_HANDLERS +}; + +// Likewise with interrupts +#[no_mangle] +pub static _INTERRUPTS: interrupts::Handlers = interrupts::Handlers { + exti0: exti0_handler, + ..interrupts::DEFAULT_HANDLERS +}; +*/ diff --git a/examples/itm.1.rs b/examples/itm.1.rs new file mode 100644 index 0000000000000000000000000000000000000000..ab913ecf9c0650108474963bd9cfb71ddeaf59a3 --- /dev/null +++ b/examples/itm.1.rs @@ -0,0 +1,52 @@ +//! Sends "Hello" and then "World" through the ITM port 0 +//! +//! You'll need to run these lines in your GDB session +//! +//! ``` text +//! > monitor tpiu config external uart off 8000000 2000000 +//! > monitor itm port 0 on +//! ``` +//! +//! And connect the SWO (PB3) pin to an UART adapter, or read it by some other +//! means. +//! +//! Finally you should see the output if you monitor the UART adapter device +//! file. +//! +//! ``` console +//! $ cat /dev/ttyUSB0 +//! Hello +//! World +//! ``` +#![deny(unsafe_code)] +#![deny(warnings)] +#![feature(proc_macro)] +#![no_std] + +extern crate blue_pill; +#[macro_use(iprint, iprintln)] +extern crate cortex_m; +extern crate cortex_m_rtfm as rtfm; + +use rtfm::{app, Threshold}; + +app! { + device: blue_pill::stm32f103xx, + + idle: { + resources: [ITM], + }, +} + +fn init(p: init::Peripherals) { + iprintln!(&p.ITM.stim[0], "Hello"); +} + +fn idle(_t: &mut Threshold, r: idle::Resources) -> ! { + iprintln!(&r.ITM.stim[0], "World"); + + // Sleep + loop { + rtfm::wfi(); + } +} diff --git a/examples/itm.rs b/examples/itm.rs index ab913ecf9c0650108474963bd9cfb71ddeaf59a3..503ed097f04f411ac55eb590e5bb245bd29394d0 100644 --- a/examples/itm.rs +++ b/examples/itm.rs @@ -23,15 +23,15 @@ #![feature(proc_macro)] #![no_std] -extern crate blue_pill; #[macro_use(iprint, iprintln)] extern crate cortex_m; extern crate cortex_m_rtfm as rtfm; +extern crate nucleo_64; use rtfm::{app, Threshold}; app! { - device: blue_pill::stm32f103xx, + device: nucleo_64::stm32f40x, idle: { resources: [ITM], @@ -46,6 +46,7 @@ fn idle(_t: &mut Threshold, r: idle::Resources) -> ! { iprintln!(&r.ITM.stim[0], "World"); // Sleep + rtfm::bkpt(); loop { rtfm::wfi(); } diff --git a/hal/Cargo.toml b/hal/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..797e5a4075aeb85feef4ae781954841dc42f84dd --- /dev/null +++ b/hal/Cargo.toml @@ -0,0 +1,13 @@ +[package] +authors = [ + "Bjorn Paulstrom <bjornpaulstrom@hotmail.se>", +] +description = "hal" + +license = "MIT OR Apache-2.0" +name = "hal" +version = "0.1.0" + +[dependencies.stm32f40x] +git = "https://gitlab.henriktjader.com/pln/STM32F40x" +features = ["rt"] diff --git a/hal/src/bt.rs b/hal/src/bt.rs new file mode 100644 index 0000000000000000000000000000000000000000..7c6da7c0b1bb7fa3b5061e5bcfc0798f2861e902 --- /dev/null +++ b/hal/src/bt.rs @@ -0,0 +1,964 @@ +extern crate hal_core; +use self::hal_core::*; + +extern crate stm32f401; +use self::stm32f401::base::*; +use self::stm32f401::gpioa::*; +use self::stm32f401::exti::*; + +use spi::*; +use usart::*; + +pub static bt: BT = BT +{ +}; + +pub struct BT {} + +pub struct BluetoothWriteStatus +{ + pub status: bool, + pub bytes: u8, +} + +pub struct BluetoothReadStatus +{ + pub status: bool, + pub bytes: u8, +} + +pub struct HCICommand +{ + pub ogf: u8, + pub ocf: u16, + pub length: u8, + pub command: [u8; 128], +} + +pub struct HCIResponse +{ + //eventcode: u8, + //length: u8, + pub params: [u8; 128], +} + +pub fn gpioa() -> &'static mut Gpioa +{ + unsafe { &mut *(GPIOA_BASE as *mut Gpioa) } +} + +pub fn exti() -> &'static mut Exti { + unsafe { &mut *(EXTI_BASE as *mut Exti) } +} + + +impl BT +{ + pub fn restart_bt(&self) + { + unsafe { usart.send("Restarting Bluetooth...\n\r") }; + + gpioa().bsrr.write(|w| w.br8().bits(1)); // turn off bt + dwt_driver::wait_cycles(84_000 * 5); //5 msec + gpioa().bsrr.write(|w| w.bs8().bits(1)); // turn on bt + dwt_driver::wait_cycles(84_000 * 5); // 5msec + + let data = self.spi_read(); + } + + pub fn send_hci_command(&self, hci: HCICommand) -> [u8; 128] + { + + let mut hc: [u8; 128] = [0; 128]; + let mut response: [u8; 128] = [0; 128]; + let mut bws = BluetoothWriteStatus { status: false, bytes: 0 }; + + hc[0] = 0x01; + hc[1] = hci.ocf as u8; + hc[2] = hci.ogf << 2; + hc[3] = hci.length; + + if hci.ocf > 255 { + if hci.ocf & 0b1000000000 != 0 { + hc[2] = hc[2] + 2; + } + if hci.ocf & 0b0100000000 != 0 { + hc[2] = hc[2] + 1; + } + } + + let mut i = 0; + while i < hci.length + { + hc[4 + i as usize] = hci.command[i as usize]; + i = i + 1; + } + + //exti().imr.modify(|_, w| unsafe { w.mr0().bits(0) }); // interrupt mask + loop + { + self.spi_select_bt(); + self.bluetooth_write_status(&mut bws); + if bws.status == true + { + if bws.bytes > hci.length + { + spi.spi1sendreceive(hc, &mut response, hci.length+4); + self.spi_deselect_bt(); + response = self.spi_read(); + //exti().imr.modify(|_, w| unsafe { w.mr0().bits(1) }); // interrupt mask + return response; + } + + } + self.spi_deselect_bt(); + } + } + + pub fn spi_read(&self) -> [u8; 128] + { + let mut response: [u8; 128] = [0; 128]; + let mut brs = BluetoothReadStatus { status: false, bytes: 0 }; + dwt_driver::wait_cycles(10 * 84_000); //1msec + while gpioa().idr.read().idr0().bits() == 1 + { + self.spi_select_bt(); + dwt_driver::wait_cycles(500 * 84); //500 usec + self.bluetooth_read_status(&mut brs); + if brs.status == true && brs.bytes > 0 + { + response = spi.spi1receive(brs.bytes); + self.spi_deselect_bt(); + //dwt_driver::wait_cycles(50 * 84_000); //50msec + break; + } + self.spi_deselect_bt(); + dwt_driver::wait_cycles(10 * 84_000); //1msec + } + response + } + + pub fn configure_bt_address(&self) + { + unsafe { usart.send("Setting config data, bdaddress: ") }; + + let mut hcicommand: HCICommand = HCICommand { ogf: 0x3f, ocf: 0x000C, length: 8, command: [0; 128] }; + hcicommand.command[0] = 0x00; + hcicommand.command[1] = 0x06; + hcicommand.command[2] = 0xaa; + hcicommand.command[3] = 0x00; + hcicommand.command[4] = 0x00; + hcicommand.command[5] = 0xe1; + hcicommand.command[6] = 0x80; + hcicommand.command[7] = 0x02; + + //self.bt_send_hci_command(hc); + let hciresponse = self.send_hci_command(hcicommand); + + //The controller will generate a command complete event. BT Core specification Vol 2, Part E, 7.7.14 - Command Complete Event + if hciresponse[6] == 0x00 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn gatt_service_init(&self) + { + unsafe { usart.send("Initializing GATT service: ") }; + + let hcicommand: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000001, length: 0, command: [0; 128] }; + + //self.bt_send_hci_command(hc); + let hciresponse = self.send_hci_command(hcicommand); + + //The controller will generate a command complete event. BT Core specification Vol 2, Part E, 7.7.14 - Command Complete Event + if hciresponse[6] == 0x00 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn gap_service_init(&self) + { + unsafe { usart.send("Initializing GAP service: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0x008A, length: 3, command: [0; 128] }; + hc.command[0] = 0x01; + hc.command[1] = 0x00; + hc.command[2] = 0x07; + + let hciresponse = self.send_hci_command(hc); + + //The controller will generate a command complete event. BT Core specification Vol 2, Part E, 7.7.14 - Command Complete Event + if hciresponse[6] == 0x00 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn gap_set_io_capability(&self) + { + unsafe { usart.send("Setting GAP IO capability: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0x85, length: 1, command: [0; 128] }; + hc.command[0] = 0x03; + + let hciresponse = self.send_hci_command(hc); + + //The controller will generate a command complete event. BT Core specification Vol 2, Part E, 7.7.14 - Command Complete Event + if hciresponse[6] == 0x00 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn gap_set_auth_requirments(&self) + { + unsafe { usart.send("Setting GAP auth requirments: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0x86, length: 26, command: [0; 128] }; + hc.command[0] = 0x00; + hc.command[1] = 0x00; + hc.command[2] = 0x00; + hc.command[3] = 0x00; + hc.command[4] = 0x00; + hc.command[5] = 0x00; + hc.command[6] = 0x00; + hc.command[7] = 0x00; + hc.command[8] = 0x00; + hc.command[9] = 0x00; + hc.command[10] = 0x00; + hc.command[11] = 0x00; + hc.command[12] = 0x00; + hc.command[13] = 0x00; + hc.command[14] = 0x00; + hc.command[15] = 0x00; + hc.command[16] = 0x00; + hc.command[17] = 0x00; + hc.command[18] = 0x07; + hc.command[19] = 0x10; + hc.command[20] = 0x00; + hc.command[21] = 0x01; + hc.command[22] = 0x00; + hc.command[23] = 0x00; + hc.command[24] = 0x00; + hc.command[25] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + //The controller will generate a command complete event. BT Core specification Vol 2, Part E, 7.7.14 - Command Complete Event + if hciresponse[6] == 0x00 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn start_hid_service(&self) -> [u8;2] + { + unsafe { usart.send("Starting HID service: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000010, length: 5, command: [0; 128] }; + hc.command[0] = 0x01; + hc.command[1] = 0x12; + hc.command[2] = 0x18; + hc.command[3] = 0x01; + hc.command[4] = 0x10; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn hid_add_protocol_mode_characteristic(&self, HIDServiceHandle: [u8;2]) -> [u8;2] + { + unsafe { usart.send("Adding HID protocol mode characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000100, length: 12, command: [0; 128] }; + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = 0x01; + hc.command[3] = 0x4e; + hc.command[4] = 0x2a; + hc.command[5] = 0x01; + hc.command[6] = 0x00; + hc.command[7] = 0x06; + hc.command[8] = 0x00; + hc.command[9] = 0x00; + hc.command[10] = 0x10; + hc.command[11] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn hid_set_protocol_mode_characteristic(&self, HIDServiceHandle: [u8;2], HIDProtocolModeCharactersiticHandle: [u8;2]) + { + + unsafe { usart.send("Setting HID protocol mode characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000110, length: 7, command: [0; 128] }; + + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = HIDProtocolModeCharactersiticHandle[0]; + hc.command[3] = HIDProtocolModeCharactersiticHandle[1]; + hc.command[4] = 0x00; + hc.command[5] = 0x01; + hc.command[6] = 0x01; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn hid_add_boot_mouse_input_report_characteristic(&self, HIDServiceHandle: [u8;2]) -> [u8;2] + { + unsafe { usart.send("Adding boot mouse input report characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000100, length: 12, command: [0; 128] }; + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = 0x01; + hc.command[3] = 0x33; + hc.command[4] = 0x2a; + hc.command[5] = 0x03; + hc.command[6] = 0x00; + hc.command[7] = 0x1a; + hc.command[8] = 0x00; + hc.command[9] = 0x01; + hc.command[10] = 0x10; + hc.command[11] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn hid_add_information_characteristic(&self, HIDServiceHandle: [u8;2]) -> [u8;2] + { + unsafe { usart.send("Adding HID information characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000100, length: 12, command: [0; 128] }; + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = 0x01; + hc.command[3] = 0x4a; + hc.command[4] = 0x2a; + hc.command[5] = 0x04; + hc.command[6] = 0x00; + hc.command[7] = 0x02; + hc.command[8] = 0x00; + hc.command[9] = 0x01; + hc.command[10] = 0x10; + hc.command[11] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn hid_set_information_characteristic(&self, HIDServiceHandle: [u8;2], HIDInformationCharactersiticHandle: [u8;2]) + { + unsafe { usart.send("Setting HID information characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000110, length: 10, command: [0; 128] }; + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = HIDInformationCharactersiticHandle[0]; + hc.command[3] = HIDInformationCharactersiticHandle[1]; + hc.command[4] = 0x00; + hc.command[5] = 0x04; + hc.command[6] = 0x01; + hc.command[7] = 0x12; + hc.command[8] = 0x00; + hc.command[9] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn hid_add_control_point_characteristic(&self, HIDServiceHandle: [u8;2]) -> [u8;2] + { + unsafe { usart.send("Adding HID control point characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000100, length: 12, command: [0; 128] }; + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = 0x01; + hc.command[3] = 0x4c; + hc.command[4] = 0x2a; + hc.command[5] = 0x01; + hc.command[6] = 0x00; + hc.command[7] = 0x04; + hc.command[8] = 0x00; + hc.command[9] = 0x01; + hc.command[10] = 0x10; + hc.command[11] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn hid_add_report_map_characteristic(&self, HIDServiceHandle: [u8;2]) -> [u8;2] + { + unsafe { usart.send("Adding HID report map characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000100, length: 12, command: [0; 128] }; + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = 0x01; + hc.command[3] = 0x4b; + hc.command[4] = 0x2a; + hc.command[5] = 0x34; + hc.command[6] = 0x00; + hc.command[7] = 0x02; + hc.command[8] = 0x00; + hc.command[9] = 0x00; + hc.command[10] = 0x10; + hc.command[11] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn hid_set_report_map_characteristic(&self, HIDServiceHandle: [u8;2], HIDReportMapCharactersiticHandle: [u8;2]) + { + unsafe { usart.send("Setting report map characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000110, length: 58, command: [0; 128] }; + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = HIDReportMapCharactersiticHandle[0]; + hc.command[3] = HIDReportMapCharactersiticHandle[1]; + hc.command[4] = 0x00; + hc.command[5] = 0x34; + hc.command[6] = 0x05; // + hc.command[7] = 0x01; // + hc.command[8] = 0x09; // + hc.command[9] = 0x02; // + hc.command[10] = 0xA1;// + hc.command[11] = 0x01;// + hc.command[12] = 0x09;// + hc.command[13] = 0x01;// + hc.command[14] = 0xA1;// + hc.command[15] = 0x00;// + hc.command[16] = 0x85;// + hc.command[17] = 0x01;// + hc.command[18] = 0x05;// + hc.command[19] = 0x09;// + hc.command[20] = 0x19;// + hc.command[21] = 0x01;// + hc.command[22] = 0x29;// + hc.command[23] = 0x03;// + hc.command[24] = 0x15;// + hc.command[25] = 0x00;// + hc.command[26] = 0x25;// + hc.command[27] = 0x01;// + hc.command[28] = 0x95;// + hc.command[29] = 0x03;// + hc.command[30] = 0x75;// + hc.command[31] = 0x01;// + hc.command[32] = 0x81;// + hc.command[33] = 0x02;// + hc.command[34] = 0x95;// + hc.command[35] = 0x01;// + hc.command[36] = 0x75;// + hc.command[37] = 0x05;// + hc.command[38] = 0x81;// + hc.command[39] = 0x03;// + hc.command[40] = 0x05;// + hc.command[41] = 0x01;// + hc.command[42] = 0x09;// + hc.command[43] = 0x30;// + hc.command[44] = 0x09;// + hc.command[45] = 0x31;// + hc.command[46] = 0x15;// + hc.command[47] = 0x81;// + hc.command[48] = 0x25;// + hc.command[49] = 0x7F;// + hc.command[50] = 0x75;// + hc.command[51] = 0x08;// + hc.command[52] = 0x95;// + hc.command[53] = 0x02;// + hc.command[54] = 0x81;// + hc.command[55] = 0x06;// + hc.command[56] = 0xC0;// + hc.command[57] = 0xC0;// + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn hid_add_report_characteristic(&self, HIDServiceHandle: [u8;2]) -> [u8;2] + { + unsafe { usart.send("Adding HID report characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000100, length: 12, command: [0; 128] }; + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = 0x01; + hc.command[3] = 0x4d; + hc.command[4] = 0x2a; + hc.command[5] = 0x03; + hc.command[6] = 0x00; + hc.command[7] = 0x12; + hc.command[8] = 0x00; + hc.command[9] = 0x01; + hc.command[10] = 0x10; + hc.command[11] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn hid_add_report_description(&self, HIDServiceHandle: [u8;2], HIDReportCharactersiticHandle: [u8;2]) -> [u8;2] + { + unsafe { usart.send("Adding HID report description: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000101, length: 16, command: [0; 128] }; + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = HIDReportCharactersiticHandle[0]; + hc.command[3] = HIDReportCharactersiticHandle[1]; + hc.command[4] = 0x01; + hc.command[5] = 0x08; + hc.command[6] = 0x29; + hc.command[7] = 0x02; + hc.command[8] = 0x02; + hc.command[9] = 0x01; + hc.command[10] = 0x01; + hc.command[11] = 0x00; + hc.command[12] = 0x01; + hc.command[13] = 0x01; + hc.command[14] = 0x10; + hc.command[15] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn start_battery_level_service(&self) -> [u8;2] + { + unsafe { usart.send("Starting battery level service: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000010, length: 5, command: [0; 128] }; + hc.command[0] = 0x01; + hc.command[1] = 0x0F; + hc.command[2] = 0x18; + hc.command[3] = 0x01; + hc.command[4] = 0x04; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn add_battery_level_characteristic(&self, BatteryLevelServiceHandle: [u8;2]) -> [u8;2] + { + unsafe { usart.send("Adding battery level characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000100, length: 12, command: [0; 128] }; + hc.command[0] = BatteryLevelServiceHandle[0]; + hc.command[1] = BatteryLevelServiceHandle[1]; + hc.command[2] = 0x01; + hc.command[3] = 0x19; + hc.command[4] = 0x2a; + hc.command[5] = 0x01; + hc.command[6] = 0x00; + hc.command[7] = 0x02; + hc.command[8] = 0x00; + hc.command[9] = 0x01; + hc.command[10] = 0x10; + hc.command[11] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn add_presentation_format_description(&self, BatteryLevelServiceHandle: [u8;2], BatteryLevelCharactersiticHandle: [u8;2]) -> [u8;2] + { + unsafe { usart.send("Adding battery level format description: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000101, length: 21, command: [0; 128] }; + hc.command[0] = BatteryLevelServiceHandle[0]; + hc.command[1] = BatteryLevelServiceHandle[1]; + hc.command[2] = BatteryLevelCharactersiticHandle[0]; + hc.command[3] = BatteryLevelCharactersiticHandle[1]; + hc.command[4] = 0x01; + hc.command[5] = 0x04; + hc.command[6] = 0x29; + hc.command[7] = 0x07; + hc.command[8] = 0x07; + hc.command[9] = 0x04; + hc.command[10] = 0x00; + hc.command[11] = 0xad; + hc.command[12] = 0x27; + hc.command[13] = 0x01; + hc.command[14] = 0x00; + hc.command[15] = 0x01; + hc.command[16] = 0x00; + hc.command[17] = 0x01; + hc.command[18] = 0x01; + hc.command[19] = 0x10; + hc.command[20] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + + pub fn start_device_information_service(&self) -> [u8;2] + { + unsafe { usart.send("Starting device information service: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000010, length: 5, command: [0; 128] }; + hc.command[0] = 0x01; + hc.command[1] = 0x0A; + hc.command[2] = 0x18; + hc.command[3] = 0x01; + hc.command[4] = 0x15; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + let mut ret: [u8;2] = [0;2]; + ret[0] = hciresponse[7]; + ret[1] = hciresponse[8]; + return ret; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn add_pnp_id_characteristic(&self, DeviceInformationServiceHandle: [u8;2]) + { + unsafe { usart.send("Adding device info PNP ID characteristic: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000100, length: 12, command: [0; 128] }; + hc.command[0] = DeviceInformationServiceHandle[0]; + hc.command[1] = DeviceInformationServiceHandle[1]; + hc.command[2] = 0x01; + hc.command[3] = 0x50; + hc.command[4] = 0x2a; + hc.command[5] = 0x07; + hc.command[6] = 0x00; + hc.command[7] = 0x02; + hc.command[8] = 0x00; + hc.command[9] = 0x01; + hc.command[10] = 0x10; + hc.command[11] = 0x00; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn gap_set_discoverable(&self) + { + unsafe { usart.send("GAP set discoverable: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0x83, length: 16, command: [0; 128] }; + hc.command[0] = 0x00; + hc.command[1] = 0x00; + hc.command[2] = 0x00; + hc.command[3] = 0x00; + hc.command[4] = 0x00; + hc.command[5] = 0x00; + hc.command[6] = 0x00; + hc.command[7] = 0x03; + hc.command[8] = 0x09; + hc.command[9] = 0x42; + hc.command[10] = 0x50; + hc.command[11] = 0x00; + hc.command[12] = 0x06; + hc.command[13] = 0x00; + hc.command[14] = 0x00; + hc.command[15] = 0x0c; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + loop {} + } + } + + pub fn set_report_characteristic(&self, HIDServiceHandle: [u8;2], HIDReportCharactersiticHandle: [u8;2], x: i16, y: i16) + { + unsafe { usart.send("Sending data: ") }; + + let mut hc: HCICommand = HCICommand { ogf: 0x3f, ocf: 0b0100000110, length: 9, command: [0; 128] }; + hc.command[0] = HIDServiceHandle[0]; + hc.command[1] = HIDServiceHandle[1]; + hc.command[2] = HIDReportCharactersiticHandle[0]; + hc.command[3] = HIDReportCharactersiticHandle[1]; + hc.command[4] = 0x00; + hc.command[5] = 0x03; + hc.command[6] = 0x00; + hc.command[7] = -x as u8; + hc.command[8] = y as u8; + + let hciresponse = self.send_hci_command(hc); + + if hciresponse[6] == 0 + { + unsafe { usart.send("Success\n\r") }; + } + else + { + unsafe { usart.send("Failure\n\r") }; + //loop {} + } + } + + //Brief: Selects the BT device for SPI transfer + pub fn spi_select_bt(&self) { + gpioa().bsrr.write(|w| w.br1().bits(1)); // clear ODR1 (BT select) + //gpioa().odr.write(unsafe { |w| w.odr1().bits(0) } ); + } + + //Brief: Deselects the BT device for SPI transfer + pub fn spi_deselect_bt(&self) { + gpioa().bsrr.write(|w| w.bs1().bits(1)); + //gpioa().odr.write(unsafe { |w| w.odr1().bits(1) } ); + } + + //Brief: Writes to BT device expecting response on how many bytes can be written as a command + //return: struct containing info on bt device, if it is ready for receiving command and how many bytes can be written + pub fn bluetooth_write_status(&self, bws: &mut BluetoothWriteStatus) + { + let mut response: [u8; 128] = [0; 128]; + let mut data = [0; 128]; + data[0] = 0x0a; + + unsafe { spi.spi1sendreceive(data, &mut response, 5) }; + if response[0] == 0x02 + { + bws.status = true; + bws.bytes = response[1]; + } + } + + pub fn bluetooth_read_status(&self, brs: &mut BluetoothReadStatus) + { + let mut data: [u8; 128] = [0; 128]; + let mut response: [u8; 128] = [0; 128]; + data[0] = 0x0b; + + spi.spi1sendreceive(data, &mut response, 5); + + if response[0] == 0x02 + { + brs.status = true; + brs.bytes = response[3]; + } + } +} diff --git a/hal/src/i2c.rs b/hal/src/i2c.rs new file mode 100644 index 0000000000000000000000000000000000000000..052f721fb91489f1442ac854c1842b835b80044f --- /dev/null +++ b/hal/src/i2c.rs @@ -0,0 +1,183 @@ +extern crate stm32f401; +use self::stm32f401::gpioa::*; +use self::stm32f401::gpiob::*; +use self::stm32f401::base::*; +use self::stm32f401::rcc::*; +use self::stm32f401::i2c1::*; + +extern crate hal_core; +use self::hal_core::*; + +pub struct I2C {} + +pub fn gpioa() -> &'static mut Gpioa { + unsafe { &mut *(GPIOA_BASE as *mut Gpioa) } +} + +pub fn gpiob() -> &'static mut Gpiob { + unsafe { &mut *(GPIOB_BASE as *mut Gpiob) } +} + +pub fn rcc() -> &'static mut Rcc { + unsafe { &mut *(RCC_BASE as *mut Rcc) } +} + +pub fn i2c1() -> &'static mut I2c1 { + unsafe { &mut *(I2C1_BASE as *mut I2c1) } +} + +pub static i2c: I2C = I2C {}; + +impl I2C +{ + pub fn initialize(&self) + { + rcc().apb1enr.modify(|_, w| unsafe { w.i2c1en().bits(1) }); + + i2c1().cr2.modify(|_, w| unsafe { w.freq().bits(0x2a) }); + i2c1().trise.modify(|_, w| unsafe { w.trise().bits(0x0d) }); + i2c1().ccr.modify(|_, w| unsafe { w.f_s().bits(1) }); + i2c1().ccr.modify(|_, w| unsafe { w.ccr().bits(0x23) }); + i2c1().oar1.modify(|_, w| unsafe { w.bits(0x4033) }); + i2c1().cr1.modify(|_, w| unsafe { w.pe().bits(1) }); + + gpiob().moder.modify(|_, w| unsafe { w.moder8().bits(2) }); + gpiob().otyper.modify(|_, w| unsafe { w.ot8().bits(1) }); + gpiob().ospeedr.modify(|_, w| unsafe { w.ospeedr8().bits(3) }); + gpiob().afrh.modify(|_, w| unsafe { w.afrh8().bits(4) }); + gpiob().pupdr.modify(|_, w| unsafe { w.pupdr8().bits(1) }); + + gpiob().moder.modify(|_, w| unsafe { w.moder9().bits(2) }); + gpiob().otyper.modify(|_, w| unsafe { w.ot9().bits(1) }); + gpiob().ospeedr.modify(|_, w| unsafe { w.ospeedr9().bits(3) }); + gpiob().afrh.modify(|_, w| unsafe { w.afrh9().bits(4) }); + gpiob().pupdr.modify(|_, w| unsafe { w.pupdr9().bits(1) }); + + //rcc().apb1rstr.modify(|_, w| unsafe { w.i2c1rst().bits(1) }); + //rcc().apb1rstr.modify(|_, w| unsafe { w.i2c1rst().bits(0) }); + + i2c1().cr1.modify(|_, w| unsafe { w.pe().bits(1) }); + } + + pub fn read_memory(&self, memory_address: u32) -> u32 + { + /* Disable Pos */ + i2c1().cr1.modify(|_, w| unsafe { w.pos().bits(0) }); + + /* Send Slave Address and Memory Address */ + self.request_memory_read(memory_address); + + //Disable Acknowledge + i2c1().cr1.modify(|_, w| unsafe { w.ack().bits(0) }); + + //Clear ADDR flag; This bit is cleared by software reading SR1 register followed reading SR2, or by hardware when PE=0. + i2c1().sr1.read(); + i2c1().sr2.read(); + + //Generate stop + i2c1().cr1.modify(|_, w| unsafe { w.stop().bits(1) }); + + /* Wait until RXNE flag is set */ + while i2c1().sr1.read().rx_ne().bits() == 0 {} + + let value :u32 = i2c1().dr.read().bits(); + + value + + } + + pub fn request_memory_read(&self, memory_address: u32) + { + //Enable Acknowledge + i2c1().cr1.modify(|_, w| unsafe { w.ack().bits(1) }); + + //Generate Start + i2c1().cr1.modify(|_, w| unsafe { w.start().bits(1) }); + + /* Wait until SB flag is set */ + while i2c1().sr1.read().sb().bits() == 0 {} + + /* Send slave address */ + i2c1().dr.write(|w| unsafe { w.bits(214) }); + + // Wait until ADDR flag is set + while i2c1().sr1.read().addr().bits() == 0 {} + + //Clear ADDR flag; This bit is cleared by software reading SR1 register followed reading SR2, or by hardware when PE=0. + i2c1().sr1.read(); + i2c1().sr2.read(); + + //Wait until TXE flag is set + while i2c1().sr1.read().tx_e().bits() == 0 {} + + //Send Memory Address + i2c1().dr.write(|w| unsafe { w.bits(memory_address as u32) }); + + //Wait until TXE flag is set + while i2c1().sr1.read().tx_e().bits() == 0 {} + + /* Generate Restart */ + i2c1().cr1.modify(|_, w| unsafe { w.start().bits(1) }); + + //Loop until start condition is set + while i2c1().sr1.read().sb().bits() == 0 {} + + /* Send slave address */ + i2c1().dr.write(|w| unsafe { w.bits(215) }); + + // Wait until ADDR flag is set + while i2c1().sr1.read().addr().bits() == 0 {} + } + + pub fn write_memory(&self, data: [u8; 128], len: u8) + { + /* Disable Pos */ + i2c1().cr1.modify(|_, w| unsafe { w.pos().bits(0) }); + + self.request_memory_write(); + + //Send data + let mut x: u8 = 0; + while x < len + { + //Wait until TXE flag is set + while i2c1().sr1.read().tx_e().bits() == 0 {} + i2c1().dr.write(|w| unsafe { w.bits(data[x as usize] as u32) }); + x = x + 1; + } + + //Wait until BTF flag is set + while i2c1().sr1.read().btf().bits() == 0 {} + + i2c1().cr1.modify(|_, w| unsafe { w.stop().bits(1) }); + + dwt_driver::wait_cycles(30_000); + } + + pub fn request_memory_write(&self) -> bool + { + /* Generate Start */ + i2c1().cr1.modify(|_, w| unsafe { w.start().bits(1) }); + + //Loop until start condition is set + while i2c1().sr1.read().sb().bits() == 0 {} + + //Send slave address + i2c1().dr.write(|w| unsafe { w.bits(214) }); + + // Wait until ADDR flag is set + while i2c1().sr1.read().addr().bits() == 0 {} + + //Clear ADDR flag; This bit is cleared by software reading SR1 register followed reading SR2, or by hardware when PE=0. + i2c1().sr1.read(); + i2c1().sr2.read(); + + //Wait until TXE flag is set + while i2c1().sr1.read().tx_e().bits() == 0 {} + + //Send Memory Address + i2c1().dr.write(|w| unsafe { w.bits(32) }); + + true + } +} \ No newline at end of file diff --git a/hal/src/lib.rs b/hal/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..7e016144531cc2ce99674d165d706f2509320590 --- /dev/null +++ b/hal/src/lib.rs @@ -0,0 +1,9 @@ +#![no_std] +//#![feature(asm)] +//#![feature(plugin)] + +extern crate stm32f40x; +//pub mod spi; +// pub mod bt; +pub mod usart; +// pub mod i2c; diff --git a/hal/src/spi.rs b/hal/src/spi.rs new file mode 100644 index 0000000000000000000000000000000000000000..3c5ccd2013a0309d5ff90876e5f02fa60151c83e --- /dev/null +++ b/hal/src/spi.rs @@ -0,0 +1,128 @@ +extern crate stm32f401; +use self::stm32f401::spi1::*; +use self::stm32f401::gpioa::*; +use self::stm32f401::gpiob::*; +use self::stm32f401::base::*; +use self::stm32f401::rcc::*; + +pub struct SPI { + pub receivebuffer: [u8; 128], + pub sendbuffer: [u8; 128], + pub receiveindex: u8, + pub sendindex: u8, + pub sendlength: u8, + pub receivelength: u8, +} + +pub fn spi1() -> &'static mut Spi1 { + unsafe { &mut *(SPI1_BASE as *mut Spi1) } +} + +pub fn gpioa() -> &'static mut Gpioa { + unsafe { &mut *(GPIOA_BASE as *mut Gpioa) } +} + +pub fn gpiob() -> &'static mut Gpiob { + unsafe { &mut *(GPIOB_BASE as *mut Gpiob) } +} + +pub fn rcc() -> &'static mut Rcc { + unsafe { &mut *(RCC_BASE as *mut Rcc) } +} + +pub static spi: SPI = SPI { + receivebuffer: [0; 128], + sendbuffer: [0; 128], + receiveindex: 0, + sendindex: 0, + sendlength: 0, + receivelength: 0, +}; + +impl SPI { + pub fn initialize(&self) { + rcc().apb2enr.modify(|_, w| unsafe { w.spi1en().bits(1) }); + spi1().cr1.modify(|_, w| unsafe { w.spe().bits(0) }); //enable SPI + + gpioa().moder.modify(|_, w| w.moder6().bits(2)); //TX,RX + gpioa().moder.modify(|_, w| w.moder7().bits(2)); + gpioa().otyper.modify(|_, w| w.ot6().bits(0)); + gpioa().otyper.modify(|_, w| w.ot7().bits(0)); + gpioa().ospeedr.modify(|_, w| w.ospeedr6().bits(3)); + gpioa().ospeedr.modify(|_, w| w.ospeedr7().bits(3)); + gpioa().afrl.modify(|_, w| w.afrl6().bits(5)); + gpioa().afrl.modify(|_, w| w.afrl7().bits(5)); + + gpioa().moder.modify(|_, w| w.moder1().bits(1)); //CS + gpioa().otyper.modify(|_, w| w.ot1().bits(0)); + gpioa().ospeedr.modify(|_, w| w.ospeedr1().bits(3)); + gpioa().pupdr.modify(|_, w| w.pupdr1().bits(1)); + + gpioa().moder.modify(|_, w| w.moder8().bits(1)); //restart pin + gpioa().otyper.modify(|_, w| w.ot8().bits(0)); + gpioa().pupdr.modify(|_, w| w.pupdr8().bits(1)); + + gpioa().moder.modify(|_, w| w.moder0().bits(0)); //BT chip got data pin + gpioa().otyper.modify(|_, w| w.ot0().bits(0)); + gpioa().pupdr.modify(|_, w| w.pupdr0().bits(0)); + + gpiob().moder.modify(|_, w| unsafe { w.moder3().bits(2) }); //SPI clock + gpiob().otyper.modify(|_, w| unsafe { w.ot3().bits(0) }); + gpiob().ospeedr.modify(|_, w| unsafe { w.ospeedr3().bits(3) }); + gpiob().afrl.modify(|_, w| unsafe { w.afrl3().bits(5) }); + gpiob().pupdr.modify(|_, w| unsafe { w.pupdr3().bits(2) }); + + spi1().cr1.modify(|_, w| unsafe { w.br().bits(0b100) }); // CLK / 32 prescaler + spi1().cr1.modify(|_, w| unsafe { w.ssi().bits(1) }); // NSS + spi1().cr1.modify(|_, w| unsafe { w.ssm().bits(1) }); // Software chip select + spi1().cr1.modify(|_, w| unsafe { w.mstr().bits(1) }); //Master + spi1().cr1.modify(|_, w| unsafe { w.spe().bits(1) }); //enable SPI + } + + //Brief: Send a series of uint8 through spi1 + //data: u8 to send + //len: length of data + pub fn spi1send(&self, data: [u8; 128], len: u8) { + let mut x: u8 = 0; + while x < len { + while spi1().sr.read().txe().bits() == 0 {} + spi1().dr.write(|w| unsafe { w.bits(data[x as usize] as u32) }); + while spi1().sr.read().rxne().bits() == 0 {} + let _ = spi1().dr.read().dr().bits() as u8; + x = x + 1; + } + } + + pub fn spi1receive(&self, length: u8) -> [u8; 128] + { + let mut response: [u8; 128] = [0; 128]; + let mut x: u8 = 0; + + while x < length + { + while spi1().sr.read().txe().bits() == 0 {} + spi1().dr.write(|w| unsafe { w.bits(0 as u32) }); + while spi1().sr.read().rxne().bits() == 0 {} + response[x as usize] = spi1().dr.read().dr().bits() as u8; + x = x + 1; + } + response + } + + //Brief: Send a series of uint8 through spi1 returning answer + //data: u8 to send + //len: length of data + //return: return bytes from spi + pub fn spi1sendreceive(&self, data: [u8; 128], response: &mut [u8; 128], len: u8) + { + let mut x: u8 = 0; + while x < len + { + while spi1().sr.read().txe().bits() == 0 {} + spi1().dr.write(|w| unsafe { w.bits(data[x as usize] as u32) }); + while spi1().sr.read().rxne().bits() == 0 {} + response[x as usize] = spi1().dr.read().dr().bits() as u8; + x = x + 1; + } + } +} diff --git a/hal/src/usart.rs b/hal/src/usart.rs new file mode 100644 index 0000000000000000000000000000000000000000..dfcf7e4a4432b5d00849d60a9623bddca0f2d17a --- /dev/null +++ b/hal/src/usart.rs @@ -0,0 +1,40 @@ + + +use stm32f40x::{USART2, GPIOA, RCC}; +pub static mut usart: USART = USART {}; + +pub struct USART {} + +impl USART { + pub fn initialize(gpioa: &GPIOA, rcc: &RCC, usart2: &USART2) { + gpioa.moder.modify(|_, w| w.moder2().bits(2)); + gpioa.moder.modify(|_, w| w.moder3().bits(2)); + gpioa.otyper.modify(|_, w| w.ot2().clear_bit()); + gpioa.otyper.modify(|_, w| w.ot3().clear_bit()); + gpioa.afrl.modify(|_, w| w.afrl2().bits(7)); + gpioa.afrl.modify(|_, w| w.afrl3().bits(7)); + + rcc.apb1enr.modify(|_, w| w.usart2en().set_bit()); //enable usart2 + usart2.cr1.modify(|_, w| w.over8().clear_bit()); //16bitoversampling + usart2 + .brr + .modify(|_, w| unsafe { w.div_fraction().bits(0x7) }); //Baudrate fraction + usart2 + .brr + .modify(|_, w| unsafe { w.div_mantissa().bits(0x111) }); //Baudrate Mantissa + usart2.cr1.modify(|_, w| w.ue().set_bit()); //USART enable + usart2.cr1.modify(|_, w| w.te().set_bit()); //Transmit enable + usart2.cr1.modify(|_, w| w.re().set_bit()); //Receieve enable + } + + //Brief: Send a series of chars through usart2 + //data: chars to send + //return: none + + pub fn send(usart2: &USART2, data: &str) { + for c in data.chars() { + while usart2.sr.read().txe().bit_is_clear() {} + usart2.dr.write(|w| unsafe { w.bits(c as u32) }); + } + } +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000000000000000000000000000000000000..1f26f3f49ea15543fd1d23cf361768b57d5128dd --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +line_width = 100 \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index eaf53f27f210c718b23339bef5c582479dc855db..1e492244655cfe7f072deb0b0b26fcade2704c09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,9 +144,9 @@ pub mod apb2 { #[macro_export] macro_rules! println { ($($e:tt)*) => { - { + { extern crate cortex_m_semihosting; - use core::fmt::Write; + use core::fmt::Write; writeln!(cortex_m_semihosting::hio::hstdout().unwrap(), $($e)*).unwrap(); } }