diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4ae822d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/target
+**/*.rs.bk
+.idea
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..26bb8dd
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,48 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "cc2500"
+version = "0.1.0"
+dependencies = [
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rppal 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cfg-if"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "lazy_static"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.2.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "log"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rppal"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[metadata]
+"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
+"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
+"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
+"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
+"checksum rppal 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "137dbba1fb867daa27cda4c3cd6a11bca5bb5a1551f034cf9319b994846ddbe1"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..e4a1ff7
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,35 @@
+[package]
+name = "cc2500"
+version = "0.1.0"
+authors = ["tschl"]
+edition = "2018"
+target = "armv7-unknown-linux-gnueabihf"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+rppal = "0.11.3"
+log = "0.4.8"
+
+[target.armv7-unknown-linux-gnueabihf]
+linker = "arm-linux-gnueabihf-gcc-8"
+ar = "arm-linux-gnueabihf-ar"
+
+[tasks.compile]
+command = "cargo"
+args = ["build", "--target", "armv7-unknown-linux-gnueabihf"]
+
+[tasks.upload]
+command = "scp"
+args = ["./target/armv7-unknown-linux-gnueabihf/debug/cc2500", "pi@xxx.xxx.xxx.xxx:"]
+
+[tasks.gdb]
+command = "ssh"
+args = ["pi@xxx.xxx.xxx.xxx", "gdbserver 0.0.0.0:2345 ./cc2500"]
+
+[tasks.debug-raspberry]
+dependencies = [
+ "compile",
+ "upload",
+# "gdb"
+]
\ No newline at end of file
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..4cd4bdf
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,66 @@
+# Ansluta Rust controller
+
+This project is a rust application compiled for an raspberry pi to control IKEA lamps by faking an Ansluta remote.
+Thanks to [NDBCK](https://github.com/NDBCK/Ansluta-Remote-Controller) for his great research and example code in C++.
+In this project I used the first time ever rust language so please don't judge about code style :D.
+
+
+### Requirements
+
+* [Raspberry PI 3 (€33,99 at Amazon)](https://amzn.to/2oiGepb)
+* [CC2500 2.4 GHz chip (€3 at Amazon)](https://amzn.to/2mbaRwk)
+* [Breadboard & Jumper cables (€8.99 at Amazon)](https://amzn.to/2mRyfiG)
+* [Rust](https://www.rust-lang.org/tools/install)
+* [Cargo make](https://github.com/sagiegurari/cargo-make#installation)
+* [Cargo watch](https://github.com/passcod/cargo-watch#install)
+* Linux Subsystem if you are on windows
+* GCC for Raspberry ARM processor
+
+### Setup
+
+**1)** Open linux shell (`bash.exe` for linux subsystem on windows)
+
+**2)** Install rustup, rust and cargo
+```bash
+$ curl https://sh.rustup.rs -sSf | sh
+```
+
+**3)** Install cargo-make
+```
+$ cargo install --force cargo-make
+```
+
+**4)** Install cargo-make
+```
+$ cargo install --force cargo-watch
+```
+
+**5)** Install ARM gcc to cross compile for raspberry pi.
+*Note: If you choose another gcc version you have to update the linker used in the Cargo.toml file.*
+```
+$ apt-get install gcc-8-multilib-arm-linux-gnueabihf
+```
+
+**6)** Add target in rustup
+```
+$ rustup target add armv7-unknown-linux-gnueabihf
+```
+
+**7)** Update ip in Cargo.toml to directly upload to raspberry pi on build
+```
+$ sed -i 's/xxx.xxx.xxx.xxx/your-ip/g' ./Cargo.toml
+```
+
+### Run
+
+**Build**: Compile and upload to raspberry pi
+```bash
+$ cargo make --makefile Cargo.toml debug-raspberry
+```
+
+**Watch**: Compile and upload on every file change
+```bash
+cargo watch -x "make --makefile Cargo.toml debug-raspberry"
+```
+
+**NOTE**: Seems like there is no remote debug functionality at all. I didn't managed it to have breakpoints working. Neither CLion with GDBRemote nor CLI worked and I just found bugs / issues raised by other users complaining about the same.
\ No newline at end of file
diff --git a/src/cc2500.rs b/src/cc2500.rs
new file mode 100644
index 0000000..d325eaf
--- /dev/null
+++ b/src/cc2500.rs
@@ -0,0 +1,28 @@
+use crate::cc2500::chip::CC2500;
+use rppal::spi::Spi;
+
+mod chip;
+mod constants;
+
+#[derive(Debug, Copy, Clone)]
+pub struct Address(pub u8, pub u8);
+
+pub enum STATE {
+ SIDLE = 0x36, // Exit RX / TX
+ STX = 0x35, // Enable TX. If in RX state, only enable TX if CCA passes
+ SFTX = 0x3B, // Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states
+ SRES = 0x30, // Reset chip
+ SRX = 0x34, // Enable RX. Perform calibration if enabled
+ SFRX = 0x3A, // Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states
+}
+
+pub enum COMMAND {
+ LightOff = 0x01, // Command to turn the light off
+ LightOn50 = 0x02, // Command to turn the light on 50%
+ LightOn100 = 0x03, // Command to turn the light on 100%
+ PAIR = 0xFF, // Command to pair a remote to the light
+}
+
+pub fn new(spi: Spi) -> CC2500 {
+ CC2500 { spi, address: None }
+}
diff --git a/src/cc2500/chip.rs b/src/cc2500/chip.rs
new file mode 100644
index 0000000..6284fcb
--- /dev/null
+++ b/src/cc2500/chip.rs
@@ -0,0 +1,243 @@
+use super::constants::*;
+use super::COMMAND;
+use super::STATE;
+use super::Address;
+use rppal::gpio::Gpio;
+use rppal::spi::{Polarity};
+use rppal::spi::{Segment, Spi};
+use std::thread;
+
+pub struct CC2500 {
+ pub spi: Spi,
+ pub address: Option
,
+}
+
+/**
+ * Block execution until MISO is set to high and chip is ready for receiving data
+ */
+fn wait_for_miso() {
+ let gpio = Gpio::new().expect("Couldn't iunit GPIO");
+ let miso = gpio
+ .get(9)
+ .expect("Could not attach to MISO pin")
+ .into_output();
+
+ while miso.is_set_high() {}
+}
+
+/**
+ * Create list of segments for the list of bytes
+ */
+fn bytes_to_segments(bytes: &[u8], delay: u16) -> Vec {
+ let segments = bytes.iter().map(|byte| {
+ let mut segment = Segment::with_write(std::slice::from_ref(byte));
+ segment.set_delay(delay);
+ segment
+ });
+ return segments.collect();
+}
+
+impl CC2500 {
+
+ /**
+ * Write spi register on CC2500 chip
+ */
+ fn write_reg(&mut self, reg: u8, value: u8) {
+ self.spi.set_ss_polarity(Polarity::ActiveLow).expect("Couldn't set polarity");
+ wait_for_miso();
+
+ let bytes = [reg, value];
+ let segments = bytes_to_segments(&bytes, 200);
+ self.spi
+ .transfer_segments(&segments)
+ .expect("Could not write");
+
+ self.spi.set_ss_polarity(Polarity::ActiveHigh).expect("Couldn't set polarity");
+
+ thread::sleep(DELAY_200);
+ }
+
+ /**
+ * Read spi register from CC2500 chip
+ */
+ fn read_reg(&mut self, addr: u8) -> u8 {
+ self.spi.set_ss_polarity(Polarity::ActiveLow).expect("Couldn't set polarity");
+ wait_for_miso();
+
+ let buffer = [addr + 0x80];
+ let mut write = Segment::with_write(&buffer);
+ write.set_delay(200);
+
+ let mut buffer: [u8; 1] = [1];
+ let mut read = Segment::with_read(&mut buffer);
+ read.set_delay(200);
+
+ self.spi
+ .transfer_segments(&[write, read])
+ .expect("Could not write");
+
+ self.spi.set_ss_polarity(Polarity::ActiveHigh).expect("Couldn't set polarity");
+
+ return buffer[0];
+ }
+
+ /**
+ * Send a strobe of 1 byte to the CC2500
+ */
+ pub fn strobe(&mut self, state: STATE) {
+ self.spi.set_ss_polarity(Polarity::ActiveLow).expect("Couldn't set polarity");
+ wait_for_miso();
+
+ self.spi
+ .write(&[state as u8])
+ .expect("Could not transfer to SPI");
+
+ self.spi.set_ss_polarity(Polarity::ActiveHigh).expect("Couldn't set polarity");
+
+ thread::sleep(DELAY_20000);
+ }
+
+ /**
+ * Initialize the registers of CC2500 chip
+ */
+ pub fn init(&mut self) {
+ self.strobe(STATE::SRES);
+
+ self.write_reg(REG_IOCFG2, VAL_IOCFG2);
+ self.write_reg(REG_IOCFG0, VAL_IOCFG0);
+ self.write_reg(REG_PKTLEN, VAL_PKTLEN);
+ self.write_reg(REG_PKTCTRL1, VAL_PKTCTRL1);
+ self.write_reg(REG_PKTCTRL0, VAL_PKTCTRL0);
+ self.write_reg(REG_ADDR, VAL_ADDR);
+ self.write_reg(REG_CHANNR, VAL_CHANNR);
+ self.write_reg(REG_FSCTRL1, VAL_FSCTRL1);
+ self.write_reg(REG_FSCTRL0, VAL_FSCTRL0);
+ self.write_reg(REG_FREQ2, VAL_FREQ2);
+ self.write_reg(REG_FREQ1, VAL_FREQ1);
+ self.write_reg(REG_FREQ0, VAL_FREQ0);
+ self.write_reg(REG_MDMCFG4, VAL_MDMCFG4);
+ self.write_reg(REG_MDMCFG3, VAL_MDMCFG3);
+ self.write_reg(REG_MDMCFG2, VAL_MDMCFG2);
+ self.write_reg(REG_MDMCFG1, VAL_MDMCFG1);
+ self.write_reg(REG_MDMCFG0, VAL_MDMCFG0);
+ self.write_reg(REG_DEVIATN, VAL_DEVIATN);
+ self.write_reg(REG_MCSM2, VAL_MCSM2);
+ self.write_reg(REG_MCSM1, VAL_MCSM1);
+ self.write_reg(REG_MCSM0, VAL_MCSM0);
+ self.write_reg(REG_FOCCFG, VAL_FOCCFG);
+ self.write_reg(REG_BSCFG, VAL_BSCFG);
+ self.write_reg(REG_AGCCTRL2, VAL_AGCCTRL2);
+ self.write_reg(REG_AGCCTRL1, VAL_AGCCTRL1);
+ self.write_reg(REG_AGCCTRL0, VAL_AGCCTRL0);
+ self.write_reg(REG_WOREVT1, VAL_WOREVT1);
+ self.write_reg(REG_WOREVT0, VAL_WOREVT0);
+ self.write_reg(REG_WORCTRL, VAL_WORCTRL);
+ self.write_reg(REG_FREND1, VAL_FREND1);
+ self.write_reg(REG_FREND0, VAL_FREND0);
+ self.write_reg(REG_FSCAL3, VAL_FSCAL3);
+ self.write_reg(REG_FSCAL2, VAL_FSCAL2);
+ self.write_reg(REG_FSCAL1, VAL_FSCAL1);
+ self.write_reg(REG_FSCAL0, VAL_FSCAL0);
+ self.write_reg(REG_RCCTRL1, VAL_RCCTRL1);
+ self.write_reg(REG_RCCTRL0, VAL_RCCTRL0);
+ self.write_reg(REG_FSTEST, VAL_FSTEST);
+ self.write_reg(REG_TEST2, VAL_TEST2);
+ self.write_reg(REG_TEST1, VAL_TEST1);
+ self.write_reg(REG_TEST0, VAL_TEST0);
+ self.write_reg(REG_DAFUQ, VAL_DAFUQ);
+ // Set power level to max
+ self.write_reg(0x3E, 0xFF);
+ }
+
+ /**
+ * Send command with CC2500 to Ansluta. Repeating the message 50 times to ensure it was consumed
+ */
+ pub fn command(&mut self, cmd: COMMAND) {
+ let cmd_address = cmd as u8;
+ match self.address {
+ None => panic!("Can not send command to unknown address!"),
+ Some(address) => {
+ for _i in 0..50 {
+ self.strobe(STATE::SIDLE);
+ self.strobe(STATE::SFTX);
+
+ self.spi.set_ss_polarity(Polarity::ActiveLow).expect("Couldn't set polarity");
+ wait_for_miso();
+
+ let bytes = vec![
+ 0x7F,
+ 0x06,
+ 0x55,
+ 0x01,
+ address.0,
+ address.1,
+ cmd_address,
+ 0xAA,
+ 0xFF,
+ ];
+
+ let segments: Vec<_> = bytes_to_segments(&bytes, 0);
+ self.spi
+ .transfer_segments(&segments)
+ .expect("Could not write");
+
+ self.spi.set_ss_polarity(Polarity::ActiveHigh).expect("Couldn't set polarity");
+
+ self.strobe(STATE::STX);
+ thread::sleep(DELAY_10);
+ }
+ }
+ }
+ }
+
+ /**
+ * Debugger function to read the address of the original ansulta remote.
+ * Once it's read it will print it. In future this should be persisted for other calls
+ */
+ pub fn read_address(&mut self) -> Option {
+ loop {
+ self.strobe(STATE::SRX);
+ self.write_reg(REG_IOCFG1, 0x01); // Switch MISO to output if packet has been received
+ thread::sleep(DELAY_200);
+
+ let packet_length = self.read_reg(REG_FIFO) as usize;
+ let mut packet = vec![0; packet_length as usize];
+
+ if packet_length > 8 {
+ println!("Received packet is to big {}", packet_length);
+ }
+ // Read packet from FIFO buffer
+ if packet_length > 0 && packet_length <= 8 {
+ println!("Received packet");
+
+ for i in 0..packet_length {
+ packet[i] = self.read_reg(REG_FIFO);
+ }
+ println!("Packet {:x?}", packet);
+
+ let start = packet.iter().position(|&byte| byte != 0x55).unwrap();
+
+ // Check if the packet is from IKEA remote
+ if packet[start] == 0x01 && packet[start + 4] == 0xAA {
+ println!("Address found: {} {}", packet[start + 1], packet[start + 2]);
+ self.address = Some(Address(packet[start + 1], packet[start + 2]));
+
+ self.strobe(STATE::SIDLE);
+ self.strobe(STATE::SFRX);
+
+ return self.address.clone();
+ }
+ }
+
+ self.strobe(STATE::SIDLE);
+ self.strobe(STATE::SFRX);
+ }
+ }
+
+ /**
+ * Set address of original ansluta
+ */
+ pub fn set_address(&mut self, address: Address) {
+ self.address = Some(address.clone());
+ }
+}
diff --git a/src/cc2500/constants.rs b/src/cc2500/constants.rs
new file mode 100644
index 0000000..069d2ca
--- /dev/null
+++ b/src/cc2500/constants.rs
@@ -0,0 +1,116 @@
+#![allow(dead_code)]
+
+use std::time::Duration;
+
+pub const DELAY_1: Duration = Duration::from_micros(1);
+pub const DELAY_20000: Duration = Duration::from_micros(20000);
+pub const DELAY_10: Duration = Duration::from_micros(10);
+pub const DELAY_0: Duration = Duration::from_micros(0);
+pub const DELAY_200: Duration = Duration::from_micros(200);
+
+pub const REG_IOCFG2: u8 = 0x00;
+pub const REG_IOCFG1: u8 = 0x01;
+pub const REG_IOCFG0: u8 = 0x02;
+pub const REG_FIFOTHR: u8 = 0x03;
+pub const REG_SYNC1: u8 = 0x04;
+pub const REG_SYNC0: u8 = 0x05;
+pub const REG_PKTLEN: u8 = 0x06;
+pub const REG_PKTCTRL1: u8 = 0x07;
+pub const REG_PKTCTRL0: u8 = 0x08;
+pub const REG_ADDR: u8 = 0x09;
+pub const REG_CHANNR: u8 = 0x0A;
+pub const REG_FSCTRL1: u8 = 0x0B;
+pub const REG_FSCTRL0: u8 = 0x0C;
+pub const REG_FREQ2: u8 = 0x0D;
+pub const REG_FREQ1: u8 = 0x0E;
+pub const REG_FREQ0: u8 = 0x0F;
+pub const REG_MDMCFG4: u8 = 0x10;
+pub const REG_MDMCFG3: u8 = 0x11;
+pub const REG_MDMCFG2: u8 = 0x12;
+pub const REG_MDMCFG1: u8 = 0x13;
+pub const REG_MDMCFG0: u8 = 0x14;
+pub const REG_DEVIATN: u8 = 0x15;
+pub const REG_MCSM2: u8 = 0x16;
+pub const REG_MCSM1: u8 = 0x17;
+pub const REG_MCSM0: u8 = 0x18;
+pub const REG_FOCCFG: u8 = 0x19;
+pub const REG_BSCFG: u8 = 0x1A;
+pub const REG_AGCCTRL2: u8 = 0x1B;
+pub const REG_AGCCTRL1: u8 = 0x1C;
+pub const REG_AGCCTRL0: u8 = 0x1D;
+pub const REG_WOREVT1: u8 = 0x1E;
+pub const REG_WOREVT0: u8 = 0x1F;
+pub const REG_WORCTRL: u8 = 0x20;
+pub const REG_FREND1: u8 = 0x21;
+pub const REG_FREND0: u8 = 0x22;
+pub const REG_FSCAL3: u8 = 0x23;
+pub const REG_FSCAL2: u8 = 0x24;
+pub const REG_FSCAL1: u8 = 0x25;
+pub const REG_FSCAL0: u8 = 0x26;
+pub const REG_RCCTRL1: u8 = 0x27;
+pub const REG_RCCTRL0: u8 = 0x28;
+pub const REG_FSTEST: u8 = 0x29;
+pub const REG_PTEST: u8 = 0x2A;
+pub const REG_AGCTEST: u8 = 0x2B;
+pub const REG_TEST2: u8 = 0x2C;
+pub const REG_TEST1: u8 = 0x2D;
+pub const REG_TEST0: u8 = 0x2E;
+pub const REG_PARTNUM: u8 = 0x30;
+pub const REG_VERSION: u8 = 0x31;
+pub const REG_FREQEST: u8 = 0x32;
+pub const REG_LQI: u8 = 0x33;
+pub const REG_RSSI: u8 = 0x34;
+pub const REG_MARCSTATE: u8 = 0x35;
+pub const REG_WORTIME1: u8 = 0x36;
+pub const REG_WORTIME0: u8 = 0x37;
+pub const REG_PKTSTATUS: u8 = 0x38;
+pub const REG_VCO_VC_DAC: u8 = 0x39;
+pub const REG_TXBYTES: u8 = 0x3A;
+pub const REG_RXBYTES: u8 = 0x3B;
+pub const REG_RCCTRL1_STATUS: u8 = 0x3C;
+pub const REG_RCCTRL0_STATUS: u8 = 0x3D;
+pub const REG_FIFO: u8 = 0x3F; // TX and RX FIFO
+pub const REG_DAFUQ: u8 = 0x7E;
+
+pub const VAL_IOCFG2: u8 = 0x29;
+pub const VAL_IOCFG0: u8 = 0x06;
+pub const VAL_PKTLEN: u8 = 0xFF;
+pub const VAL_PKTCTRL1: u8 = 0x04;
+pub const VAL_PKTCTRL0: u8 = 0x05;
+pub const VAL_ADDR: u8 = 0x01;
+pub const VAL_CHANNR: u8 = 0x10;
+pub const VAL_FSCTRL1: u8 = 0x09;
+pub const VAL_FSCTRL0: u8 = 0x00;
+pub const VAL_FREQ2: u8 = 0x5D;
+pub const VAL_FREQ1: u8 = 0x93;
+pub const VAL_FREQ0: u8 = 0xB1;
+pub const VAL_MDMCFG4: u8 = 0x2D;
+pub const VAL_MDMCFG3: u8 = 0x3B;
+pub const VAL_MDMCFG2: u8 = 0x73; //MSK, No Manchester
+pub const VAL_MDMCFG1: u8 = 0xA2;
+pub const VAL_MDMCFG0: u8 = 0xF8;
+pub const VAL_DEVIATN: u8 = 0x01;
+pub const VAL_MCSM2: u8 = 0x07;
+pub const VAL_MCSM1: u8 = 0x30;
+pub const VAL_MCSM0: u8 = 0x18;
+pub const VAL_FOCCFG: u8 = 0x1D;
+pub const VAL_BSCFG: u8 = 0x1C;
+pub const VAL_AGCCTRL2: u8 = 0xC7;
+pub const VAL_AGCCTRL1: u8 = 0x00;
+pub const VAL_AGCCTRL0: u8 = 0xB2;
+pub const VAL_WOREVT1: u8 = 0x87;
+pub const VAL_WOREVT0: u8 = 0x6B;
+pub const VAL_WORCTRL: u8 = 0xF8;
+pub const VAL_FREND1: u8 = 0xB6;
+pub const VAL_FREND0: u8 = 0x10;
+pub const VAL_FSCAL3: u8 = 0xEA;
+pub const VAL_FSCAL2: u8 = 0x0A;
+pub const VAL_FSCAL1: u8 = 0x00;
+pub const VAL_FSCAL0: u8 = 0x11;
+pub const VAL_RCCTRL1: u8 = 0x41;
+pub const VAL_RCCTRL0: u8 = 0x00;
+pub const VAL_FSTEST: u8 = 0x59;
+pub const VAL_TEST2: u8 = 0x88;
+pub const VAL_TEST1: u8 = 0x31;
+pub const VAL_TEST0: u8 = 0x0B;
+pub const VAL_DAFUQ: u8 = 0xFF;
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..73cde32
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,64 @@
+use crate::cc2500::{COMMAND, Address};
+use rppal::spi::{BitOrder, Bus, Mode, SlaveSelect, Spi};
+use std::env;
+use std::fs;
+
+mod cc2500;
+
+const ADDRESS_FILE: &str = "./.ansluta-address";
+
+/**
+ * Load 2 byte address of original ansluta
+ */
+fn load_address() -> Option {
+ match fs::read(ADDRESS_FILE) {
+ Ok(address) => Some(Address(address[0], address[1])),
+ Err(_) => None
+ }
+}
+
+/**
+ * Save 2 byte address of original ansluta for later use
+ */
+fn save_address(address: Address) {
+ if let Err(error) = fs::write(ADDRESS_FILE, [address.0, address.1]) {
+ panic!("Couldn't save ansluta address to {} because {}", ADDRESS_FILE, error);
+ }
+}
+
+/**
+ * Initialize CC2500 chip registers, ensure we have a ansulta address and execute one of the commands off, 50 or 100
+ */
+fn main() {
+ let spi = Spi::new(Bus::Spi0, SlaveSelect::Ss0, 6_000_000, Mode::Mode0)
+ .expect("Couldn't start SPI connection");
+ spi.set_bit_order(BitOrder::MsbFirst)
+ .expect("Could not set bit order on SPI");
+
+ let mut cc2500 = cc2500::new(spi);
+ cc2500.init();
+ // Read address from original ansluta if none is known yet
+ match load_address() {
+ Some(address) => cc2500.set_address(address),
+ None => {
+ match cc2500.read_address() {
+ Some(address) => save_address(address),
+ None => panic!("Could not find address!")
+ }
+ }
+ }
+
+ let args: Vec = env::args().collect();
+ let level = &args[1];
+ let command = {
+ match level.as_str() {
+ "off" => COMMAND::LightOff,
+ "50" => COMMAND::LightOn50,
+ "100" => COMMAND::LightOn100,
+ _ => panic!("Unknown level. Use off, 50 or 100")
+ }
+ };
+
+ println!("Light {}", level);
+ cc2500.command(command);
+}