Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions glue/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ keywords = ["warduino", "wasm"]
license = "MPL-2.0"

[dependencies]
num = "0.4"
num-traits = "0.2"
num-derive = "0.3"
num = { version = "0.4.3", default-features = false }
num-derive = { version = "0.4.2", default-features = false }
num-traits = { version = "0.2.19", default-features = false }


[[example]]
name = "blink"
Expand Down
15 changes: 11 additions & 4 deletions glue/rust/examples/button.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
// config::BUTTON demo app
use warduino::{delay, digital_read, digital_write, InterruptMode, pin_mode, PinMode, PinVoltage, sub_interrupt};
use warduino::{
delay, digital_read, digital_write, pin_mode, sub_interrupt, InterruptMode, PinMode, PinVoltage,
};

mod config;

fn callback(_topic: &str, _payload: &str, _length: u32) {
fn callback(
_topic: *const u8,
_topic_length: usize,
_payload: *const u8,
_payload_length: usize,
_length: u32,
) {
let voltage = digital_read(config::LED);
match voltage {
PinVoltage::HIGH => digital_write(config::LED, PinVoltage::LOW),
PinVoltage::LOW => digital_write(config::LED, PinVoltage::HIGH)
PinVoltage::LOW => digital_write(config::LED, PinVoltage::HIGH),
}
}

Expand All @@ -22,4 +30,3 @@ pub fn main() {
delay(1000);
}
}

4 changes: 3 additions & 1 deletion glue/rust/examples/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ pub static SSID: &str = "local-network";
pub static PASSWORD: &str = "network-password";
pub static BROKER_URL: &str = "192.168.0.24";
pub static BROKER_PORT: u32 = 1883;
pub static CLIENT_ID: &str = "random-mqtt-client-id";
pub static CLIENT_ID: &str = "random-mqtt-client-id";

fn main() {}
37 changes: 29 additions & 8 deletions glue/rust/examples/smartlamp.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Simple smart lamp app demo
use warduino::{delay, digital_read, digital_write, InterruptMode, mqtt_connect, mqtt_connected,
mqtt_init, mqtt_loop, mqtt_publish, mqtt_subscribe, pin_mode, PinMode, PinVoltage,
print, sleep, sub_interrupt, wifi_connect, wifi_connected, wifi_localip};
use warduino::{
delay, digital_read, digital_write, mqtt_connect, mqtt_connected, mqtt_init, mqtt_loop,
mqtt_publish, mqtt_subscribe, pin_mode, print, sleep, sub_interrupt, wifi_connect,
wifi_connected, wifi_localip, InterruptMode, PinMode, PinVoltage,
};

mod config;

Expand All @@ -12,13 +14,24 @@ fn until(done: fn() -> bool, attempt: fn()) {
}
}

fn callback(topic: &str, payload: &str, size: u32) {
fn callback(
topic: *const u8,
topic_len: usize,
payload: *const u8,
payload_length: usize,
size: u32,
) {
let topic =
unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(topic, topic_len)) };
let payload = unsafe {
std::str::from_utf8_unchecked(std::slice::from_raw_parts(payload, payload_length))
};
print(&format!("Message [{}] {}\n", topic, payload));

if payload.contains("on") {
digital_write(config::LED, PinVoltage::HIGH); // Turn the LED on
digital_write(config::LED, PinVoltage::HIGH); // Turn the LED on
} else {
digital_write(config::LED, PinVoltage::LOW); // Turn the LED off
digital_write(config::LED, PinVoltage::LOW); // Turn the LED off
}
}

Expand All @@ -29,7 +42,13 @@ fn invert(voltage: PinVoltage) -> PinVoltage {
}
}

fn toggle_led(_topic: &str, _payload: &str, _size: u32) {
fn toggle_led(
_topic: *const u8,
_topic_length: usize,
_payload: *const u8,
_payload_length: usize,
_size: u32,
) {
// Get current status of LED
let status = digital_read(config::LED);
// Toggle LED
Expand All @@ -43,7 +62,9 @@ pub fn main() {
pin_mode(config::BUTTON, PinMode::INPUT);

// Connect to Wi-Fi
until(wifi_connected, || wifi_connect(config::SSID, config::PASSWORD));
until(wifi_connected, || {
wifi_connect(config::SSID, config::PASSWORD)
});
let message: String = "Connected to wifi network with ip: ".to_owned() + &wifi_localip();
print(&message);

Expand Down
152 changes: 110 additions & 42 deletions glue/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,16 @@
//! ```

#![crate_name = "warduino"]
#![no_std]
extern crate alloc;

extern crate num;
#[macro_use]
extern crate num_derive;

use alloc::{borrow::ToOwned, string::String};
use core::mem;
use linking::*;
use std::mem;

mod linking;

Expand Down Expand Up @@ -91,28 +94,46 @@ pub enum PinMode {
}

/// Returns the number of milliseconds passed since the current program started to run.
pub fn millis() -> u32 { unsafe { _millis() } }
pub fn millis() -> u32 {
unsafe { _millis() }
}

/// Pauses the program for the amount of time (in milliseconds).
pub fn delay(ms: u32) { unsafe { _delay(ms); } }
pub fn delay(ms: u32) {
unsafe {
_delay(ms);
}
}

/// Pauses the program for the amount of time (in seconds)
pub fn sleep(s: u32) { delay(s * 1000); }
pub fn sleep(s: u32) {
delay(s * 1000);
}

/// Configures the [PinMode] of the specified pin.
pub fn pin_mode(pin: u32, mode: PinMode) { unsafe { _pinMode(pin, mode as u32) } }
pub fn pin_mode(pin: u32, mode: PinMode) {
unsafe { _pinMode(pin, mode as u32) }
}

/// Write the voltage to a specified digital pin, either [HIGH](PinVoltage) or [LOW](PinVoltage).
pub fn digital_write(pin: u32, value: PinVoltage) { unsafe { _digitalWrite(pin, value as u32) } }
pub fn digital_write(pin: u32, value: PinVoltage) {
unsafe { _digitalWrite(pin, value as u32) }
}

/// Reads the value from a specified digital pin, either [HIGH](PinVoltage) or [LOW](PinVoltage).
pub fn digital_read(pin: u32) -> PinVoltage { unsafe { num::FromPrimitive::from_u32(_digitalRead(pin)).unwrap() } }
pub fn digital_read(pin: u32) -> PinVoltage {
unsafe { num::FromPrimitive::from_u32(_digitalRead(pin)).unwrap() }
}

/// Reads the value from the specified analog pin.
pub fn analog_read(pin: u32) -> i32 { unsafe { _analogRead(pin) } }
pub fn analog_read(pin: u32) -> i32 {
unsafe { _analogRead(pin) }
}

/// Writes the value to the specified analog pin.
pub fn analog_write(pin: u32, signal: u32) -> i32 { unsafe { _analogWrite(pin, signal) } }
pub fn analog_write(pin: u32, signal: u32) -> i32 {
unsafe { _analogWrite(pin, signal) }
}

/// The status of the Wi-Fi connection
#[derive(FromPrimitive, PartialEq)]
Expand All @@ -136,59 +157,91 @@ pub enum WiFiStatus {
}

/// Connect to Wi-Fi network with SSID and password
pub fn wifi_connect(ssid: &str, password: &str) { unsafe { _connect(ssid, password) } }
pub fn wifi_connect(ssid: &str, password: &str) {
unsafe { _connect(ssid.as_ptr(), ssid.len(), password.as_ptr(), password.len()) }
}

/// Returns the status of the Wi-Fi connection of the board
pub fn wifi_status() -> WiFiStatus { unsafe { num::FromPrimitive::from_i32(_status()).unwrap() } }
pub fn wifi_status() -> WiFiStatus {
unsafe { num::FromPrimitive::from_i32(_status()).unwrap() }
}

/// Returns whether the board si still connected to Wi-Fi
pub fn wifi_connected() -> bool { wifi_status() == WiFiStatus::Connected }
pub fn wifi_connected() -> bool {
wifi_status() == WiFiStatus::Connected
}

/// Returns the local IP address of the board
pub fn wifi_localip() -> String {
pub fn with_wifi_localip<T>(then: impl FnOnce(&str) -> T) -> T {
unsafe {
let buffer: [u8; 100] = [0; 100];
_localip(buffer.as_ptr(), mem::size_of_val(&buffer) / mem::size_of::<u8>());
std::str::from_utf8(&buffer).unwrap().to_owned()
_localip(
buffer.as_ptr(),
mem::size_of_val(&buffer) / mem::size_of::<u8>(),
);
then(core::str::from_utf8(&buffer).unwrap())
}
}

const BUFFER_SIZE: usize = 250;

/// Send an HTTP GET request.
pub fn get(url: &str) -> &str {
const BUFFER: &[u8; BUFFER_SIZE] = &[0; BUFFER_SIZE];
unsafe {
_get(url.as_ptr(), url.len(), BUFFER.as_ptr(), mem::size_of_val(BUFFER) / mem::size_of::<u8>());
std::str::from_utf8_unchecked(BUFFER)
pub fn with_get<T>(url: &str, then: impl FnOnce(&str) -> T) -> T {
let BUFFER: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
unsafe {
_get(
url.as_ptr(),
url.len(),
BUFFER.as_ptr(),
mem::size_of_val(&BUFFER) / mem::size_of::<u8>(),
);
then(core::str::from_utf8_unchecked(&BUFFER))
}
}

/// Send an HTTP POST request.
pub fn post(options: &PostOptions) -> &str {
const BUFFER: &[u8; BUFFER_SIZE] = &[0; BUFFER_SIZE];
pub fn with_post<T>(options: &PostOptions, then: impl FnOnce(&str) -> T) -> T {
let BUFFER: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
unsafe {
_post(options.uri.as_ptr(), options.uri.len(),
options.body.as_ptr(), options.body.len(),
options.headers.content_type.as_ptr(), options.headers.content_type.len(),
options.headers.authorization.as_ptr(), options.headers.authorization.len(),
BUFFER.as_ptr(), mem::size_of_val(BUFFER) / mem::size_of::<u8>());
std::str::from_utf8_unchecked(BUFFER)
_post(
options.uri.as_ptr(),
options.uri.len(),
options.body.as_ptr(),
options.body.len(),
options.headers.content_type.as_ptr(),
options.headers.content_type.len(),
options.headers.authorization.as_ptr(),
options.headers.authorization.len(),
BUFFER.as_ptr(),
mem::size_of_val(&BUFFER) / mem::size_of::<u8>(),
);
then(core::str::from_utf8_unchecked(&BUFFER))
}

}

/// Print a string to the serial port.
pub fn print(text: &str) { unsafe { _print_buffer(text.as_ptr(), text.len()) } }
pub fn print(text: &str) {
unsafe { _print_buffer(text.as_ptr(), text.len()) }
}

/// Print an integer to the serial port.
pub fn print_int(integer: i32) { unsafe { _print_int(integer) } }
pub fn print_int(integer: i32) {
unsafe { _print_int(integer) }
}

/// subscribe a callback function to an interrupt on the given pin
pub fn sub_interrupt(pin: u32, mode: InterruptMode, f: fn(&str, &str, u32)) { unsafe { _sub_interrupt(pin, f, mode as u32) } }
pub fn sub_interrupt(
pin: u32,
mode: InterruptMode,
f: fn(*const u8, usize, *const u8, usize, u32),
) {
unsafe { _sub_interrupt(pin, f, mode as u32) }
}

/// Unsubscribe all callback functions for a given pin
pub fn unsub_interrupt(pin: u32) { unsafe { _unsub_interrupt(pin) } }
pub fn unsub_interrupt(pin: u32) {
unsafe { _unsub_interrupt(pin) }
}

/// The status of the MQTT connection
#[derive(FromPrimitive, PartialEq)]
Expand Down Expand Up @@ -216,26 +269,41 @@ pub enum MQTTStatus {
}

/// Configure a MQTT broker
pub fn mqtt_init(server: &str, port: u32) { unsafe { _mqtt_init(server.as_ptr(), server.len(), port) } }
pub fn mqtt_init(server: &str, port: u32) {
unsafe { _mqtt_init(server.as_ptr(), server.len(), port) }
}

/// Connect to the Configured MQTT broker with client_id
pub fn mqtt_connect(client_id: &str) -> bool { unsafe { _mqtt_connect(client_id.as_ptr(), client_id.len()) != 0 } }
pub fn mqtt_connect(client_id: &str) -> bool {
unsafe { _mqtt_connect(client_id.as_ptr(), client_id.len()) != 0 }
}

/// Returns whether the board is still connected to the MQTT broker
pub fn mqtt_connected() -> bool { mqtt_state() == MQTTStatus::Connected }
pub fn mqtt_connected() -> bool {
mqtt_state() == MQTTStatus::Connected
}

/// Returns the status of the connection to the MQTT broker
pub fn mqtt_state() -> MQTTStatus { unsafe { num::FromPrimitive::from_i32(_mqtt_state()).unwrap() } }
pub fn mqtt_state() -> MQTTStatus {
unsafe { num::FromPrimitive::from_i32(_mqtt_state()).unwrap() }
}

/// Publish a message on an MQTT topic
pub fn mqtt_publish(topic: &str, payload: &str) -> i32 { unsafe { _mqtt_publish(topic.as_ptr(), topic.len(), payload.as_ptr(), payload.len()) } }
pub fn mqtt_publish(topic: &str, payload: &str) -> i32 {
unsafe { _mqtt_publish(topic.as_ptr(), topic.len(), payload.as_ptr(), payload.len()) }
}

/// Subscribe a callback function to an MQTT topic
pub fn mqtt_subscribe(topic: &str, f: fn(&str, &str, u32)) -> i32 { unsafe { _mqtt_subscribe(topic.as_ptr(), topic.len(), f) } }
pub fn mqtt_subscribe(topic: &str, f: fn(*const u8, usize, *const u8, usize, u32)) -> i32 {
unsafe { _mqtt_subscribe(topic.as_ptr(), topic.len(), f) }
}

/// Unsubscribe a callback function from an MQTT topic
pub fn mqtt_unsubscribe(topic: &str, f: fn(&str, &str, u32)) -> i32 { unsafe { _mqtt_unsubscribe(topic.as_ptr(), topic.len(), f) } }
pub fn mqtt_unsubscribe(topic: &str, f: fn(*const u8, usize, *const u8, usize, u32)) -> i32 {
unsafe { _mqtt_unsubscribe(topic.as_ptr(), topic.len(), f) }
}

/// Check for messages from the MQTT broker
pub fn mqtt_poll() -> i32 { unsafe { _mqtt_loop() } }

pub fn mqtt_poll() -> i32 {
unsafe { _mqtt_loop() }
}
Loading