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, PWM_PARAMETER, SHUT_DOWN_MOTORS_ON_ERROR, SERIAL_TIMEOUT, MOTOR_M0_ACCELERATION, MOTOR_M1_ACCELERATION, MOTOR_M0_BRAKE_DURATION, MOTOR_M1_BRAKE_DURATION, MOTOR_M0_CURRENT_LIMIT_DIV_2, MOTOR_M1_CURRENT_LIMIT_DIV_2, MOTOR_M0_CURRENT_LIMIT_RESPONSE, MOTOR_M1_CURRENT_LIMIT_RESPONSE, }
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 MOTOR_M0_COAST,
82 MOTOR_M1_COAST,
83
84 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 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 MOTOR_M0_COAST => 0x86,
111 MOTOR_M1_COAST => 0x87,
112 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 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 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 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 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 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 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 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 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 fn write(&mut self, buf: &[u8]) -> Result<(), QikError> {
300 try!(self.port.write_all(buf));
301 Ok(())
302 }
303
304 fn read_byte(&mut self) -> Result<u8, QikError> {
306 let buf = try!(self.read(1));
307 Ok(buf[0])
308 }
309
310 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}