Initial commit

This commit is contained in:
Victor Timofei 2022-04-23 23:48:42 +03:00
commit 82d4a184a2
Signed by: vtimofei
GPG Key ID: B790DCEBE281403A
9 changed files with 279 additions and 0 deletions

4
.cargo/config Normal file
View File

@ -0,0 +1,4 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
rustflags = [
"-C", "link-arg=-Tlink.x",
]

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.gdb_history
/template
Cargo.lock
target/

30
Cargo.toml Normal file
View File

@ -0,0 +1,30 @@
[package]
authors = ["Henrik Böving <hargonix@gmail.com>"]
edition = "2018"
name = "i2c"
version = "0.1.0"
[dependencies.microbit-v2]
version = "0.12.0"
git = "https://github.com/nrf-rs/microbit/"
optional = true
[dependencies.microbit]
version = "0.12.0"
git = "https://github.com/nrf-rs/microbit/"
optional = true
[dependencies]
cortex-m = "0.7.3"
cortex-m-rt = "0.7.0"
rtt-target = { version = "0.3.1", features = ["cortex-m"] }
panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] }
nb = "1.0.0"
heapless = "0.7.10"
lsm303agr = "0.2.2"
embedded-hal = "0.2.6"
[features]
v2 = ["microbit-v2"]
v1 = ["microbit"]

12
Embed.toml Normal file
View File

@ -0,0 +1,12 @@
[default.general]
# chip = "nrf52833_xxAA" # uncomment this line for micro:bit V2
# chip = "nrf51822_xxAA" # uncomment this line for micro:bit V1
[default.reset]
halt_afterwards = false
[default.rtt]
enabled = true
[default.gdb]
enabled = false

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# mbsh - micro:bit shell
A UART interactive shell for the BBC micro:bit.
## Supported commands
- `clear`: Clears the terminal
- `accelerometer`: Returns the accelerometer data
- `magnetometer`: Returns the magnetometer data
## Demo
[![asciicast](https://asciinema.org/a/EYeh6pOV8neKA5e4HE2SYI5OQ.svg)](https://asciinema.org/a/EYeh6pOV8neKA5e4HE2SYI5OQ)

30
build.rs Normal file
View File

@ -0,0 +1,30 @@
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory (wherever `Cargo.toml` is). However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! a rebuild of the application with new memory settings is ensured after updating `memory.x`.
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
fn main() {
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=memory.x");
}

6
memory.x Normal file
View File

@ -0,0 +1,6 @@
MEMORY
{
/* NOTE K = KiBi = 1024 bytes */
FLASH : ORIGIN = 0x00000000, LENGTH = 256K
RAM : ORIGIN = 0x20000000, LENGTH = 16K
}

134
src/main.rs Normal file
View File

@ -0,0 +1,134 @@
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use heapless::Vec;
use rtt_target::{rtt_init_print, rprintln};
use panic_rtt_target as _;
use core::fmt::Write;
use microbit::hal::prelude::*;
#[cfg(feature = "v1")]
use microbit::{
hal::twi,
pac::twi0::frequency::FREQUENCY_A,
};
#[cfg(feature = "v2")]
use microbit::{
hal::twim,
pac::twim0::frequency::FREQUENCY_A,
};
use lsm303agr::{
AccelOutputDataRate, Lsm303agr,
};
#[cfg(feature = "v1")]
use microbit::{
hal::prelude::*,
hal::uart,
hal::uart::{Baudrate, Parity},
};
#[cfg(feature = "v2")]
use microbit::{
hal::prelude::*,
hal::uarte,
hal::uarte::{Baudrate, Parity},
};
#[cfg(feature = "v2")]
mod serial_setup;
#[cfg(feature = "v2")]
use serial_setup::UartePort;
#[entry]
fn main() -> ! {
rtt_init_print!();
let board = microbit::Board::take().unwrap();
#[cfg(feature = "v1")]
let mut i2c = { twi::Twi::new(board.TWI0, board.i2c.into(), FREQUENCY_A::K100) };
#[cfg(feature = "v2")]
let mut i2c = { twim::Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::K100) };
#[cfg(feature = "v1")]
let mut serial = {
uart::Uart::new(
board.UART0,
board.uart.into(),
Parity::EXCLUDED,
Baudrate::BAUD115200,
)
};
#[cfg(feature = "v2")]
let mut serial = {
let serial = uarte::Uarte::new(
board.UARTE0,
board.uart.into(),
Parity::EXCLUDED,
Baudrate::BAUD115200,
);
UartePort::new(serial)
};
let mut sensor = Lsm303agr::new_with_i2c(i2c);
sensor.init().unwrap();
sensor.set_accel_odr(AccelOutputDataRate::Hz50);
let mut buffer: Vec<u8, 1024> = Vec::new();
write!(serial, "{}[2J$ ", 27 as char).unwrap();
loop {
let byte = nb::block!(serial.read()).unwrap();
nb::block!(serial.write(byte)).unwrap();
if byte == b'\r' {
nb::block!(serial.write(b'\n')).unwrap();
while let Some(b' ') = buffer.last() {
buffer.pop();
}
let cmd = core::str::from_utf8(buffer.as_slice());
match cmd {
core::result::Result::Ok("accelerometer") => {
rprintln!("INFO: Calculating accelerometer");
let data = sensor.accel_data();
match data {
Result::Ok(data) => write!(serial, "x: {}, y: {}, z: {}\r\n", data.x, data.y, data.z).unwrap(),
Result::Err(e) => {
rprintln!("ERR: {:?}", e);
write!(serial, "ERR: {:?}", e).unwrap();
},
}
},
core::result::Result::Ok("magnetometer") => {
rprintln!("INFO: Calculating magnetometer");
let data = nb::block!(sensor.mag_data()).unwrap();
write!(serial, "x: {}, y: {}, z: {}\r\n", data.x, data.y, data.z).unwrap();
},
core::result::Result::Ok("clear") => {
write!(serial, "{}[2J", 27 as char).unwrap();
},
core::result::Result::Ok("") => {},
core::result::Result::Ok(cmd) => write!(serial, "Unknown command: `{}`\r\n", cmd).unwrap(),
core::result::Result::Err(e) => rprintln!("ERR: couldn't unwrap cmd: {}\r\n", e),
}
buffer.clear();
write!(serial, "$ ").unwrap();
} else if byte == 8 {
buffer.pop();
} else if !(buffer.len() == 0 && byte == b' ') {
buffer.push(byte);
}
nb::block!(serial.flush()).unwrap();
}
}

46
src/serial_setup.rs Normal file
View File

@ -0,0 +1,46 @@
use core::fmt;
use embedded_hal::blocking::serial as bserial;
use embedded_hal::serial;
use microbit::hal::uarte::{Error, Instance, Uarte, UarteRx, UarteTx};
static mut TX_BUF: [u8; 1] = [0; 1];
static mut RX_BUF: [u8; 1] = [0; 1];
pub struct UartePort<T: Instance>(UarteTx<T>, UarteRx<T>);
impl<T: Instance> UartePort<T> {
pub fn new(serial: Uarte<T>) -> UartePort<T> {
let (tx, rx) = serial
.split(unsafe { &mut TX_BUF }, unsafe { &mut RX_BUF })
.unwrap();
UartePort(tx, rx)
}
}
impl<T: Instance> fmt::Write for UartePort<T> {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.0.write_str(s)
}
}
impl<T: Instance> serial::Write<u8> for UartePort<T> {
type Error = Error;
fn write(&mut self, b: u8) -> nb::Result<(), Self::Error> {
self.0.write(b)
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
self.0.flush()
}
}
impl<T: Instance> bserial::write::Default<u8> for UartePort<T> {}
impl<T: Instance> serial::Read<u8> for UartePort<T> {
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.1.read()
}
}