tessel/
protocol.rs

1use std::io;
2use std::io::prelude::*;
3use unix_socket::UnixStream;
4
5use self::Command::*;
6
7mod raw_cmd {
8    pub const NOP: u8 = 0x00;
9    pub const FLUSH: u8 = 0x01;
10    pub const ECHO: u8 = 0x02;
11    pub const GPIO_IN: u8 = 0x03;
12    pub const GPIO_HIGH: u8 = 0x04;
13    pub const GPIO_LOW: u8 = 0x05;
14    pub const GPIO_CFG: u8 = 0x06;
15    pub const GPIO_WAIT: u8 = 0x07;
16    pub const GPIO_INT: u8 = 0x08;
17    pub const ENABLE_SPI: u8 = 0x0A;
18    pub const DISABLE_SPI: u8 = 0x0B;
19    pub const ENABLE_I2C: u8 = 0x0C;
20    pub const DISABLE_I2C: u8 = 0x0D;
21    pub const ENABLE_UART: u8 = 0x0E;
22    pub const DISABLE_UART: u8 = 0x0F;
23    pub const TX: u8 = 0x10;
24    pub const RX: u8 = 0x11;
25    pub const TXRX: u8 = 0x12;
26    pub const START: u8 = 0x13;
27    pub const STOP: u8 = 0x14;
28    pub const GPIO_TOGGLE: u8 = 0x15;
29    pub const GPIO_INPUT: u8 = 0x16;
30    pub const GPIO_RAW_READ: u8 = 0x17;
31    pub const ANALOG_READ: u8 = 0x18;
32    pub const ANALOG_WRITE: u8 = 0x19;
33    pub const GPIO_PULL: u8 = 0x1A;
34    pub const PWM_DUTY_CYCLE: u8 = 0x1B;
35    pub const PWM_PERIOD: u8 = 0x1C;
36}
37
38#[derive(Debug, Copy, Clone, PartialEq, Eq)]
39pub enum Command<'a> {
40    Nop,
41    Flush,
42
43    GpioIn(u8),
44    GpioHigh(u8),
45    GpioLow(u8),
46    GpioToggle(u8),
47    GpioWait(u8),
48    GpioInt(u8),
49    GpioCfg(u8),
50    GpioInput(u8),
51    GpioRawRead(u8),
52    GpioPull(u8),
53    AnalogRead(u8),
54
55    AnalogWrite{ pin: u8, value: u8 },
56
57    EnableSpi{ mode: u8, freq: u8, div: u8 },
58    DisableSpi,
59    EnableI2c{ baud: u8 },
60    DisableI2c,
61    EnableUart{ baud: u8, mode: u8 },
62    DisableUart,
63
64    Start(u8),
65    Stop,
66
67    PwmDutyCycle{ pin: u8, duty_cycle: u16 },
68    PwmPeriod{ prescalar: u8, tcc_id: u8, period: u16 },
69
70    Rx(u8),
71    Echo(&'a [u8]),
72    Tx(&'a [u8]),
73    TxRx(&'a [u8]),
74}
75
76/// Starting byte of reply packets. Because this is extensible, we use
77/// a list of constants instead of an enum.
78pub mod reply {
79    pub struct Reply(pub u8);
80
81    pub const ACK: Reply = Reply(0x80);
82    pub const NACK: Reply = Reply(0x81);
83    pub const HIGH: Reply = Reply(0x82);
84    pub const LOW: Reply = Reply(0x83);
85    pub const DATA: Reply = Reply(0x84);
86
87    pub const MIN_ASYNC: Reply = Reply(0xA0);
88    /// c0 to c8 is all async pin assignments.
89    pub const ASYNC_PIN_CHANGE_N: Reply = Reply(0xC0);
90    pub const ASYNC_UART_RX: Reply = Reply(0xD0);
91}
92
93/// Socket that communicates with the SAMD21.
94pub struct PortSocket {
95    _socket_path: String,
96    socket: UnixStream,
97}
98
99impl PortSocket {
100    pub fn new(path: &str) -> PortSocket {
101        // Connect to the unix domain socket for this port
102        let socket = UnixStream::connect(path).unwrap();
103
104        PortSocket {
105            _socket_path: path.to_string(),
106            socket: socket
107        }
108    }
109
110    pub fn raw_write(&mut self, buffer: &[u8]) -> io::Result<()> {
111        self.socket.write_all(buffer)
112    }
113
114    pub fn write_command(&mut self, cmd: Command) -> io::Result<()> {
115        let socket = &mut self.socket;
116        match cmd {
117            Nop => socket.write_all(&[raw_cmd::NOP]),
118            Flush => socket.write_all(&[raw_cmd::FLUSH]),
119            Rx(len) => socket.write_all(&[raw_cmd::RX, len]),
120            Echo(data) => {
121                assert!(data.len() <= u8::max_value() as usize);
122                try!(socket.write_all(&[raw_cmd::ECHO, data.len() as u8]));
123                socket.write_all(data)
124            },
125            Tx(data) => {
126                for slice in data.chunks(u8::max_value() as usize) {
127                    try!(socket.write_all(&[raw_cmd::TX, slice.len() as u8]));
128                    try!(socket.write_all(slice));
129                }
130                Ok(())
131            }
132            TxRx(data) => {
133                assert!(data.len() <= u8::max_value() as usize);
134                try!(socket.write_all(&[raw_cmd::TXRX, data.len() as u8]));
135                socket.write_all(data)
136            }
137            GpioIn(pin) => socket.write_all(&[raw_cmd::GPIO_IN, pin]),
138            GpioHigh(pin) => socket.write_all(&[raw_cmd::GPIO_HIGH, pin]),
139            GpioLow(pin) => socket.write_all(&[raw_cmd::GPIO_LOW, pin]),
140            GpioToggle(pin) => socket.write_all(&[raw_cmd::GPIO_TOGGLE, pin]),
141            GpioWait(pin) => socket.write_all(&[raw_cmd::GPIO_WAIT, pin]),
142            GpioInt(pin) => socket.write_all(&[raw_cmd::GPIO_INT, pin]),
143            GpioCfg(pin) => socket.write_all(&[raw_cmd::GPIO_CFG, pin]),
144            GpioInput(pin) => socket.write_all(&[raw_cmd::GPIO_INPUT, pin]),
145            GpioRawRead(pin) => socket.write_all(&[raw_cmd::GPIO_RAW_READ, pin]),
146            GpioPull(pin) => socket.write_all(&[raw_cmd::GPIO_PULL, pin]),
147            AnalogRead(pin) => socket.write_all(&[raw_cmd::ANALOG_READ, pin]),
148
149            AnalogWrite{ pin, value } => socket.write_all(&[raw_cmd::ANALOG_WRITE, pin, value]),
150
151            EnableSpi{ mode, freq, div } => socket.write_all(&[raw_cmd::ENABLE_SPI, mode, freq, div]),
152            DisableSpi => socket.write_all(&[raw_cmd::DISABLE_SPI]),
153            EnableI2c{ baud } => socket.write_all(&[raw_cmd::ENABLE_I2C, baud]),
154            DisableI2c => socket.write_all(&[raw_cmd::DISABLE_I2C]),
155            EnableUart{ baud, mode } => socket.write_all(&[raw_cmd::ENABLE_UART, baud, mode]),
156            DisableUart => socket.write_all(&[raw_cmd::DISABLE_UART]),
157
158            Start(addr) => socket.write_all(&[raw_cmd::START, addr]),
159            Stop => socket.write_all(&[raw_cmd::STOP]),
160
161            PwmDutyCycle{ pin, duty_cycle } => socket.write_all(&[raw_cmd::PWM_DUTY_CYCLE, pin, (duty_cycle >> 8) as u8, (duty_cycle & 0xFF) as u8]),
162            PwmPeriod{ prescalar, tcc_id, period } => socket.write_all(&[raw_cmd::PWM_PERIOD, prescalar << 4 | tcc_id & 0x7, (period >> 8) as u8, (period & 0xf) as u8]),
163        }
164    }
165
166    pub fn read_exact(&mut self, buffer: &mut [u8]) -> io::Result<()> {
167        self.socket.read_exact(buffer)
168    }
169}