1use std::thread::sleep_ms;
2use std::time::Duration;
3
4extern crate serial;
9
10use std::io::prelude::*;
11use self::serial::prelude::*;
12use self::serial::posix::TTYPort;
13
14#[allow(non_camel_case_types)]
15pub enum Motor {
16 M0,
17 M1
18}
19
20#[allow(non_camel_case_types)]
21pub enum ConfigParam {
22 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, }
35
36#[allow(non_camel_case_types)]
37enum Command {
38 GET_FIRMWARE_VERSION,
39 GET_ERROR_BYTE,
40 GET_CONFIGURATION_PARAMETER,
41 SET_CONFIGURATION_PARAMETER,
42
43 MOTOR_M0_FORWARD,
44 MOTOR_M0_FORWARD_8_BIT,
45 MOTOR_M0_REVERSE,
46 MOTOR_M0_REVERSE_8_BIT,
47 MOTOR_M1_FORWARD,
48 MOTOR_M1_FORWARD_8_BIT,
49 MOTOR_M1_REVERSE,
50 MOTOR_M1_REVERSE_8_BIT,
51
52 MOTOR_M0_COAST,
54 MOTOR_M1_COAST,
55
56 MOTOR_M0_BRAKE,
58 MOTOR_M1_BRAKE,
59 GET_MOTOR_M0_CURRENT,
60 GET_MOTOR_M1_CURRENT,
61 GET_MOTOR_M0_SPEED,
62 GET_MOTOR_M1_SPEED,
63}
64
65fn get_cmd_byte(cmd: Command) -> u8 {
66 use self::Command::*;
67 match cmd {
68 GET_FIRMWARE_VERSION => 0x81,
70 GET_ERROR_BYTE => 0x82,
71 GET_CONFIGURATION_PARAMETER => 0x83,
72 SET_CONFIGURATION_PARAMETER => 0x84,
73 MOTOR_M0_FORWARD => 0x88,
74 MOTOR_M0_FORWARD_8_BIT => 0x89,
75 MOTOR_M0_REVERSE => 0x8A,
76 MOTOR_M0_REVERSE_8_BIT => 0x8B,
77 MOTOR_M1_FORWARD => 0x8C,
78 MOTOR_M1_FORWARD_8_BIT => 0x8D,
79 MOTOR_M1_REVERSE => 0x8E,
80 MOTOR_M1_REVERSE_8_BIT => 0x8F,
81 MOTOR_M0_COAST => 0x86,
83 MOTOR_M1_COAST => 0x87,
84 MOTOR_M0_BRAKE => 0x86,
86 MOTOR_M1_BRAKE => 0x87,
87 GET_MOTOR_M0_CURRENT => 0x90,
88 GET_MOTOR_M1_CURRENT => 0x91,
89 GET_MOTOR_M0_SPEED => 0x92,
90 GET_MOTOR_M1_SPEED => 0x93,
91 }
92}
93
94
95fn get_config_param_byte(p: ConfigParam) -> u8 {
96 use self::ConfigParam::*;
97 match p {
98 DEVICE_ID => 0,
99 PWM_PARAMETER => 1,
100 SHUT_DOWN_MOTORS_ON_ERROR => 2,
101 SERIAL_TIMEOUT => 3,
102 MOTOR_M0_ACCELERATION => 4,
103 MOTOR_M1_ACCELERATION => 5,
104 MOTOR_M0_BRAKE_DURATION => 6,
105 MOTOR_M1_BRAKE_DURATION => 7,
106 MOTOR_M0_CURRENT_LIMIT_DIV_2 => 8,
107 MOTOR_M1_CURRENT_LIMIT_DIV_2 => 9,
108 MOTOR_M0_CURRENT_LIMIT_RESPONSE => 10,
109 MOTOR_M1_CURRENT_LIMIT_RESPONSE => 11,
110 }
111}
112
113
114pub struct Qik {
115 device: String,
116port: TTYPort,
118}
119
120impl Qik {
121
122 pub fn new(device: String, reset_pin: u8) -> Self {
123
124 let mut port = serial::open(&device).unwrap();
125
126 port.reconfigure(&|settings| {
127 settings.set_baud_rate(serial::Baud9600).unwrap();
128 settings.set_char_size(serial::Bits8);
129 settings.set_parity(serial::ParityNone);
130 settings.set_stop_bits(serial::Stop1);
131 settings.set_flow_control(serial::FlowNone);
132 Ok(())
133 }).unwrap();
134
135 port.set_timeout(Duration::from_millis(5000)).unwrap();
136
137 Qik { device: device, port: port }
138 }
139
140 pub fn init(&mut self) {
141self.write_byte(0xAA);
151 }
152
153 pub fn get_firmware_version(&mut self) -> u8 {
154 let buf: Vec<u8> = vec![ get_cmd_byte(Command::GET_FIRMWARE_VERSION) ];
155 self.write(&buf);
156 self.read_byte()
157 }
158
159 pub fn get_config(&mut self, p: ConfigParam) -> u8 {
160 let cmd: Vec<u8> = vec![
161 get_cmd_byte(Command::GET_CONFIGURATION_PARAMETER),
162 get_config_param_byte(p)
163 ];
164 self.write(&cmd);
165 self.read_byte()
166 }
167
168 pub fn set_config(&mut self, p: ConfigParam, v: u8) -> u8 {
169 let cmd: Vec<u8> = vec![
170 get_cmd_byte(Command::SET_CONFIGURATION_PARAMETER),
171 get_config_param_byte(p),
172 v,
173 0x55,
174 0x2A
175 ];
176 self.write(&cmd);
177 self.read_byte()
178 }
179
180 pub fn get_error(&mut self) -> u8 {
181 let buf: Vec<u8> = vec![ get_cmd_byte(Command::GET_ERROR_BYTE) ];
182 self.write(&buf);
183 self.read_byte()
184 }
185
186 pub fn set_speed(&mut self, m: Motor, speed: i8) {
187 if speed >= 0 {
188 let cmd: Vec<u8> = vec![
190 get_cmd_byte(match m {
191 Motor::M0 => Command::MOTOR_M0_FORWARD_8_BIT,
192 Motor::M1 => Command::MOTOR_M1_FORWARD_8_BIT
193 }),
194 speed as u8
195 ];
196 self.write(&cmd);
197 } else {
198 let cmd: Vec<u8> = vec![
200 get_cmd_byte(match m {
201 Motor::M0 => Command::MOTOR_M0_REVERSE_8_BIT,
202 Motor::M1 => Command::MOTOR_M1_REVERSE_8_BIT
203 }),
204 (0-speed) as u8
205 ];
206 self.write(&cmd);
207 }
208 }
209
210 pub fn coast(&mut self, m: Motor) {
212 let buf: Vec<u8> = vec![ get_cmd_byte(match m {
213 Motor::M0 => Command::MOTOR_M0_COAST,
214 Motor::M1 => Command::MOTOR_M1_COAST
215 })];
216 self.write(&buf);
217 }
218
219 pub fn set_brake(&mut self, m: Motor, v: u8) {
221 assert!(v<128);
222 let cmd: Vec<u8> = vec![
223 get_cmd_byte(match m {
224 Motor::M0 => Command::MOTOR_M0_BRAKE,
225 Motor::M1 => Command::MOTOR_M1_BRAKE
226 }),
227 v
228 ];
229 self.write(&cmd);
230 }
231
232 pub fn get_speed(&mut self, m: Motor) -> u8 {
234 self.write_byte(get_cmd_byte(match m {
235 Motor::M0 => Command::GET_MOTOR_M0_SPEED,
236 Motor::M1 => Command::GET_MOTOR_M1_SPEED
237 }));
238 self.read_byte()
239 }
240
241 pub fn get_current(&mut self, m: Motor) -> u8 {
243 let buf: Vec<u8> = vec![ get_cmd_byte(match m {
244 Motor::M0 => Command::GET_MOTOR_M0_CURRENT,
245 Motor::M1 => Command::GET_MOTOR_M1_CURRENT
246 })];
247 self.write(&buf);
248 self.read_byte()
249 }
250
251 pub fn get_current_milliamps(&mut self, m: Motor) -> u32 {
253 self.get_current(m) as u32 * 150
254 }
255
256 fn write_byte(&mut self, b: u8) {
258 let buf: Vec<u8> = vec![ b ];
259 self.write(&buf);
260 }
261
262 fn write(&mut self, buf: &[u8]) {
264 self.port.write_all(buf).unwrap();
265 }
266
267 fn read_byte(&mut self) -> u8 {
269 let buf = self.read(1);
270 buf[0]
271 }
272
273 fn read(&mut self, n: usize) -> Vec<u8> {
275 let mut buf = vec![0_u8; n];
276 self.port.read_exact(buf.as_mut()).unwrap();
277 buf
278 }
279
280}