qik/
lib.rs

1use std::convert::From;
2use std::io;
3use std::time::Duration;
4
5extern crate sysfs_gpio;
6
7use sysfs_gpio::{Direction, Pin};
8
9extern crate serial;
10
11use std::io::prelude::*;
12use self::serial::prelude::*;
13use self::serial::posix::TTYPort;
14
15use std::thread;
16
17#[derive(Debug)]
18pub enum QikError {
19    SerialErr(serial::Error),
20    GpioErr(sysfs_gpio::Error),
21    IoErr(io::Error),
22}
23
24impl From<serial::Error> for QikError {
25    fn from(e: serial::Error) -> Self {
26        QikError::SerialErr(e)
27    }
28}
29
30impl From<sysfs_gpio::Error> for QikError {
31    fn from(e: sysfs_gpio::Error) -> Self {
32        QikError::GpioErr(e)
33    }
34}
35
36impl From<io::Error> for QikError {
37    fn from(e: io::Error) -> Self {
38        QikError::IoErr(e)
39    }
40}
41
42#[allow(non_camel_case_types)]
43pub enum Motor {
44    M0,
45    M1
46}
47
48#[allow(non_camel_case_types)]
49pub enum ConfigParam {
50    DEVICE_ID, //0,
51    PWM_PARAMETER, //1,
52    SHUT_DOWN_MOTORS_ON_ERROR, //2,
53    SERIAL_TIMEOUT, //3,
54    MOTOR_M0_ACCELERATION, //4,
55    MOTOR_M1_ACCELERATION, //5,
56    MOTOR_M0_BRAKE_DURATION, //6,
57    MOTOR_M1_BRAKE_DURATION, //7,
58    MOTOR_M0_CURRENT_LIMIT_DIV_2, //8,
59    MOTOR_M1_CURRENT_LIMIT_DIV_2, //9,
60    MOTOR_M0_CURRENT_LIMIT_RESPONSE, //10,
61    MOTOR_M1_CURRENT_LIMIT_RESPONSE, //11,
62}
63
64#[allow(non_camel_case_types, dead_code)]
65enum Command {
66    GET_FIRMWARE_VERSION,
67    GET_ERROR_BYTE,
68    GET_CONFIGURATION_PARAMETER,
69    SET_CONFIGURATION_PARAMETER,
70
71    MOTOR_M0_FORWARD,
72    MOTOR_M0_FORWARD_8_BIT,
73    MOTOR_M0_REVERSE,
74    MOTOR_M0_REVERSE_8_BIT,
75    MOTOR_M1_FORWARD,
76    MOTOR_M1_FORWARD_8_BIT,
77    MOTOR_M1_REVERSE,
78    MOTOR_M1_REVERSE_8_BIT,
79
80    // 2s9v1 only
81    MOTOR_M0_COAST,
82    MOTOR_M1_COAST,
83
84    // 2s12v10 only
85    MOTOR_M0_BRAKE,
86    MOTOR_M1_BRAKE,
87    GET_MOTOR_M0_CURRENT,
88    GET_MOTOR_M1_CURRENT,
89    GET_MOTOR_M0_SPEED,
90    GET_MOTOR_M1_SPEED,
91}
92
93fn get_cmd_byte(cmd: Command) -> u8 {
94    use self::Command::*;
95    match cmd {
96        // commons
97        GET_FIRMWARE_VERSION => 0x81,
98        GET_ERROR_BYTE => 0x82,
99        GET_CONFIGURATION_PARAMETER => 0x83,
100        SET_CONFIGURATION_PARAMETER  => 0x84,
101        MOTOR_M0_FORWARD => 0x88,
102        MOTOR_M0_FORWARD_8_BIT => 0x89,
103        MOTOR_M0_REVERSE => 0x8A,
104        MOTOR_M0_REVERSE_8_BIT => 0x8B,
105        MOTOR_M1_FORWARD => 0x8C,
106        MOTOR_M1_FORWARD_8_BIT => 0x8D,
107        MOTOR_M1_REVERSE => 0x8E,
108        MOTOR_M1_REVERSE_8_BIT => 0x8F,
109        // 2s9v1 only
110        MOTOR_M0_COAST => 0x86,
111        MOTOR_M1_COAST => 0x87,
112        // 2s12v10 only
113        MOTOR_M0_BRAKE => 0x86,
114        MOTOR_M1_BRAKE => 0x87,
115        GET_MOTOR_M0_CURRENT => 0x90,
116        GET_MOTOR_M1_CURRENT => 0x91,
117        GET_MOTOR_M0_SPEED => 0x92,
118        GET_MOTOR_M1_SPEED => 0x93,
119    }
120}
121
122
123fn get_config_param_byte(p: ConfigParam) -> u8 {
124    use self::ConfigParam::*;
125    match p {
126        DEVICE_ID => 0,
127        PWM_PARAMETER => 1,
128        SHUT_DOWN_MOTORS_ON_ERROR => 2,
129        SERIAL_TIMEOUT => 3,
130        MOTOR_M0_ACCELERATION => 4,
131        MOTOR_M1_ACCELERATION => 5,
132        MOTOR_M0_BRAKE_DURATION => 6,
133        MOTOR_M1_BRAKE_DURATION => 7,
134        MOTOR_M0_CURRENT_LIMIT_DIV_2 => 8,
135        MOTOR_M1_CURRENT_LIMIT_DIV_2 => 9,
136        MOTOR_M0_CURRENT_LIMIT_RESPONSE => 10,
137        MOTOR_M1_CURRENT_LIMIT_RESPONSE => 11,
138    }
139}
140
141
142pub struct Qik {
143    reset_pin: Pin,
144    port: TTYPort,
145}
146
147impl Qik {
148
149    pub fn new(device: String, reset_pin: u64) -> Result<Self, QikError> {
150
151        let mut port = try!(serial::open(&device).map_err(QikError::SerialErr));
152
153        try!(port.reconfigure(&|settings| {
154            try!(settings.set_baud_rate(serial::Baud9600));
155            settings.set_char_size(serial::Bits8);
156            settings.set_parity(serial::ParityNone);
157            settings.set_stop_bits(serial::Stop1);
158            settings.set_flow_control(serial::FlowNone);
159            Ok(())
160        }));
161
162        try!(port.set_timeout(Duration::from_millis(5000)));
163
164        Ok(Qik { reset_pin: Pin::new(reset_pin), port: port })
165    }
166
167    pub fn init(&mut self) -> Result<(), QikError> {
168        if self.reset_pin.is_exported() {
169            try!(self.reset());
170        } else {
171            try!(self.reset_pin.with_exported(|| self.reset()));
172        };
173
174        try!(self.write_byte(0xAA));
175        Ok(())
176    }
177
178    fn reset(&self) -> Result<(), sysfs_gpio::Error> {
179        try!(self.reset_pin.set_value(0));
180        try!(self.reset_pin.set_direction(Direction::Out));
181        thread::sleep(Duration::from_millis(1));
182        try!(self.reset_pin.set_direction(Direction::In));
183        thread::sleep(Duration::from_millis(10));
184        Ok(())
185    }
186
187    pub fn get_firmware_version(&mut self) -> Result<u8, QikError> {
188        let buf: Vec<u8> = vec![ get_cmd_byte(Command::GET_FIRMWARE_VERSION) ];
189        try!(self.write(&buf));
190        self.read_byte()
191    }
192
193    pub fn get_config(&mut self, p: ConfigParam) -> Result<u8, QikError> {
194        let cmd: Vec<u8> = vec![
195            get_cmd_byte(Command::GET_CONFIGURATION_PARAMETER),
196            get_config_param_byte(p)
197        ];
198        try!(self.write(&cmd));
199        self.read_byte()
200    }
201
202    pub fn set_config(&mut self, p: ConfigParam, v: u8) -> Result<u8, QikError> {
203        let cmd: Vec<u8> = vec![
204            get_cmd_byte(Command::SET_CONFIGURATION_PARAMETER),
205            get_config_param_byte(p),
206            v,
207            0x55,
208            0x2A
209        ];
210        try!(self.write(&cmd));
211        self.read_byte()
212    }
213
214    pub fn get_error(&mut self) -> Result<u8, QikError> {
215        let buf: Vec<u8> = vec![ get_cmd_byte(Command::GET_ERROR_BYTE) ];
216        try!(self.write(&buf));
217        self.read_byte()
218    }
219
220    pub fn set_speed(&mut self, m: Motor, speed: i8) -> Result<(), QikError> {
221        if speed >= 0 {
222            // forward
223            let cmd: Vec<u8> = vec![
224                get_cmd_byte(match m {
225                    Motor::M0 => Command::MOTOR_M0_FORWARD_8_BIT,
226                    Motor::M1 => Command::MOTOR_M1_FORWARD_8_BIT
227                }),
228                speed as u8
229            ];
230            self.write(&cmd)
231        } else {
232            // reverse
233            let cmd: Vec<u8> = vec![
234                get_cmd_byte(match m {
235                    Motor::M0 => Command::MOTOR_M0_REVERSE_8_BIT,
236                    Motor::M1 => Command::MOTOR_M1_REVERSE_8_BIT
237                }),
238                (0-speed) as u8
239            ];
240            self.write(&cmd)
241        }
242    }
243
244    /// 2s9v1 only
245    pub fn coast(&mut self, m: Motor) -> Result<(), QikError> {
246        let buf: Vec<u8> = vec![ get_cmd_byte(match m {
247            Motor::M0 => Command::MOTOR_M0_COAST,
248            Motor::M1 => Command::MOTOR_M1_COAST
249        })];
250        self.write(&buf)
251    }
252
253    /// 2s12v10 only
254    pub fn set_brake(&mut self, m: Motor, v: u8) -> Result<(), QikError> {
255        assert!(v<128);
256        let cmd: Vec<u8> = vec![
257            get_cmd_byte(match m {
258                Motor::M0 => Command::MOTOR_M0_BRAKE,
259                Motor::M1 => Command::MOTOR_M1_BRAKE
260            }),
261            v
262        ];
263        self.write(&cmd)
264    }
265
266    /// 2s12v10 only
267    pub fn get_speed(&mut self, m: Motor) -> Result<u8, QikError> {
268        try!(self.write_byte(get_cmd_byte(match m {
269            Motor::M0 => Command::GET_MOTOR_M0_SPEED,
270            Motor::M1 => Command::GET_MOTOR_M1_SPEED
271        })));
272        self.read_byte()
273    }
274
275    /// 2s12v10 only
276    pub fn get_current(&mut self, m: Motor) -> Result<u8, QikError> {
277        let buf: Vec<u8> = vec![ get_cmd_byte(match m {
278            Motor::M0 => Command::GET_MOTOR_M0_CURRENT,
279            Motor::M1 => Command::GET_MOTOR_M1_CURRENT
280        })];
281        try!(self.write(&buf));
282        self.read_byte()
283    }
284
285    /// 2s12v10 only
286    pub fn get_current_milliamps(&mut self, m: Motor) -> Result<u32, QikError> {
287        let c = try!(self.get_current(m));
288        Ok(c as u32 * 150)
289    }
290
291    /// writes a single byte to the serial port
292    fn write_byte(&mut self, b: u8) -> Result<(), QikError> {
293        let buf: Vec<u8> = vec![ b ];
294        try!(self.write(&buf));
295        Ok(())
296    }
297
298    /// writes a byte buffer to the serial port
299    fn write(&mut self, buf: &[u8]) -> Result<(), QikError> {
300        try!(self.port.write_all(buf));
301        Ok(())
302    }
303
304    /// reads a single bytes from the serial port
305    fn read_byte(&mut self) -> Result<u8, QikError> {
306        let buf = try!(self.read(1));
307        Ok(buf[0])
308    }
309
310    /// reads varible number of bytes from the serial port
311    fn read(&mut self, n: usize) -> Result<Vec<u8>, QikError> {
312        let mut buf = vec![0_u8; n];
313        try!(self.port.read_exact(buf.as_mut()));
314        Ok(buf)
315    }
316
317}