Contiki 2.5
stepper-process.c
1 #include <stepper-process.h>
2 #include <stepper-steps.h>
3 #include <stepper.h>
4 #include <stepper-move.h>
5 #include <string.h>
6 #include <interrupt-utils.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <net/uip.h>
10 #include <dev/cc2420.h>
11 
12 
13 #undef putchar
14 
15 
16 static unsigned int
17 parse_uint_hex(const char **pp, const char *end)
18 {
19  unsigned int v = 0;
20  while(*pp < end) {
21  char ch;
22  if ((ch = **pp) >= '0' && ch <= '9') {
23  v = v* 16 + (ch - '0');
24  } else if (ch >= 'A' && ch <= 'F') {
25  v = v* 16 + (ch - 'A') + 10;
26  } else break;
27  (*pp)++;
28  }
29  return v;
30 }
31 
32 static int
33 parse_int_hex(const char **pp, const char *end)
34 {
35  if (*pp == end) return 0;
36  if (**pp == '-') {
37  (*pp)++;
38  return -parse_uint_hex(pp, end);
39  } else {
40  return parse_uint_hex(pp, end);
41  }
42 }
43 
44 static void
45 skip_white(const char **pp, const char *end)
46 {
47  char ch;
48  while(*pp < end && ((ch = **pp) == ' ' || ch == '\t')) (*pp)++;
49 }
50 
51 static const char hex_chars[] =
52  {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
53 
54 static void
55 format_uint_hex(char **str, char *end, unsigned int v)
56 {
57  char buffer[10];
58  char *p = buffer+10;
59  if (*str == end) return;
60  if (v == 0) {
61  *(*str)++ = '0';
62  return;
63  }
64  while(v > 0) {
65  *--p = hex_chars[v&0xf];
66  v >>= 4;
67  }
68  while((p < buffer+10) && (*str < end)) {
69  *(*str)++ = *p++;
70  }
71 }
72 
73 static void
74 format_int_hex(char **str, char *end, int v)
75 {
76  if (v < 0) {
77  if (*str == end) return;
78  *(*str)++ = '-';
79  v = -v;
80  }
81  format_uint_hex(str, end, v);
82 }
83 
84 static void
85 format_ull_hex(char **str, char *end, unsigned long long int v)
86 {
87  char buffer[16];
88  char *p = buffer+10;
89  if (*str == end) return;
90  if (v == 0) {
91  *(*str)++ = '0';
92  return;
93  }
94  while(v > 0) {
95  *--p = hex_chars[v&0xf];
96  v >>= 4;
97  }
98  while((p < buffer+10) && (*str < end)) {
99  *(*str)++ = *p++;
100  }
101 }
102 static void
103 format_ll_hex(char **str, char *end, long long v)
104 {
105  if (v < 0) {
106  if (*str == end) return;
107  *(*str)++ = '-';
108  v = -v;
109  }
110  format_ull_hex(str, end, v);
111 }
112 
113 typedef struct _ReplyBuffer ReplyBuffer;
114 
115 struct _ReplyBuffer
116 {
117  char buffer[70]; /* Should be small enough to fit in one packet */
118  char *write;
119 };
120 
121 static ReplyBuffer tcp_reply;
122 static ReplyBuffer udp_reply;
123 
124 #define REPLY_BUFFER_END(reply) ((reply)->buffer+sizeof((reply)->buffer))
125 #define REPLY_BUFFER_LEFT(reply) \
126 ((reply)->buffer+sizeof((reply)->buffer) - (reply)->write)
127 
128 static void
129 reply_char(ReplyBuffer *reply, char c)
130 {
131  if (REPLY_BUFFER_LEFT(reply) > 0) {
132  *reply->write++ = c;
133  }
134 }
135 
136 static void
137 reply_str(ReplyBuffer *reply, char *str)
138 {
139  while(reply->write < REPLY_BUFFER_END(reply) && *str != '\0')
140  *reply->write++ = *str++;
141 }
142 
143 static void
144 stepper_reply(ReplyBuffer *reply, StepperResult res)
145 {
146  switch(res) {
147  case STEPPER_OK:
148  reply_str(reply, "OK");
149  break;
150  case STEPPER_ERR_MEM:
151  reply_str(reply, "ERR MEM");
152  break;
153  case STEPPER_ERR_TOO_LATE:
154  reply_str(reply, "ERR LATE");
155  break;
156  case STEPPER_ERR_INDEX: /* Sholdn't happen here */
157  reply_str(reply, "ERR INDEX");
158  break;
159  default:
160  reply_str(reply, "ERR");
161  }
162  reply_char(reply, '\n');
163 }
164 
165 #define CHECK_INPUT_LEFT(x) \
166 do {\
167 if ((x) > inend - input_line) {reply_str(reply, "ERR\n");return 0;}\
168 } while(0)
169 
170 static int
171 handle_line(const char *input_line, const char *inend, ReplyBuffer *reply)
172 {
173  unsigned long when;
174 #if 0
175  {
176  const char *p = input_line;
177  printf("Got line: '");
178  while(p < inend) {
179  putchar(*p++);
180  }
181  printf("'\n");
182  fsync(1);
183  }
184 #endif
185  skip_white(&input_line, inend);
186  CHECK_INPUT_LEFT(1);
187  if (*input_line == '#') {
188  input_line++;
189  reply_char(reply, '#');
190  while (input_line < inend &&*input_line != ' ') {
191  reply_char(reply, *input_line++);
192  }
193  reply_char(reply, ' ');
194  }
195  skip_white(&input_line, inend);
196 
197  if (*input_line == '@') {
198  input_line++;
199  when = parse_uint_hex(&input_line, inend);
200  } else {
201  when = stepper_current_period() + 3;
202  }
203  skip_white(&input_line, inend);
204  CHECK_INPUT_LEFT(1);
205  if (input_line[0] == 'L' || input_line[0] == 'R') {
206  unsigned int stepper_index = (input_line[0] == 'R' ? 1 : 0);
207  CHECK_INPUT_LEFT(1);
208  input_line++;
209  if (input_line[0] == 'S') {
210  int speed;
211  input_line++;
212  if (input_line == inend) {
213  /* printf("Speed: %ld\n",
214  stepper_current_velocity(stepper_index)/VEL_SCALE);*/
215  reply_char(reply, input_line[-2]);
216  reply_char(reply, 'S');
217  format_int_hex(&reply->write, REPLY_BUFFER_END(reply),
218  stepper_current_velocity(stepper_index)/VEL_SCALE);
219  reply_char(reply, '\n');
220  } else {
221  speed = parse_int_hex(&input_line, inend);
222  if (*input_line == ',') {
223  StepperResult res;
224  unsigned int acc;
225  input_line++;
226  acc = parse_uint_hex(&input_line, inend);
227  /* printf("Speed=%d, Acc=%u\n", speed, acc); */
228  res = stepper_set_velocity(stepper_index, &when,
229  acc, speed*VEL_SCALE);
230 
231  stepper_reply(reply, res);
232  } else {
233  reply_str(reply, "ERR\n");
234  }
235  }
236  } else if (input_line[0] == 'C') {
237  reply_char(reply, input_line[-1]);
238  reply_char(reply, 'C');
239  format_ll_hex(&reply->write, REPLY_BUFFER_END(reply),
240  stepper_current_step(stepper_index));
241  reply_char(reply, '\n');
242  } else if (input_line[0] == 'M') {
243  unsigned int speed;
244  unsigned int acc;
245  int move;
246  input_line++;
247  speed = parse_uint_hex(&input_line, inend);
248  CHECK_INPUT_LEFT(1);
249  if (*input_line == ',') {
250  input_line++;
251  acc = parse_uint_hex(&input_line, inend);
252  if (*input_line == ',') {
253  StepperResult res;
254  input_line++;
255  move = parse_int_hex(&input_line, inend);
256  /*printf("Speed=%u, Acc=%u, Move=%d\n", speed, acc, move);*/
257  res = stepper_move(stepper_index, &when,
258  acc,speed*VEL_SCALE,move*DIST_SCALE);
259  stepper_reply(reply, res);
260  } else {
261  reply_str(reply, "ERR\n");
262  }
263  } else {
264  reply_str(reply, "ERR\n");
265  }
266  } else {
267  reply_str(reply, "ERR\n");
268  }
269  } else if (input_line[0] == 'E') {
270  STEPPER_ENABLE();
271  printf("Stepper enabled\n");
272  reply_str(reply, "OK\n");
273  } else if (input_line[0] == 'D') {
274  STEPPER_DISABLE();
275  printf("Stepper disabled\n");
276  reply_str(reply, "OK\n");
277  } else if (input_line[0] == 'p') {
278  reply_char(reply, 'p');
279  format_int_hex(&reply->write, REPLY_BUFFER_END(reply),
280  cc2420_last_rssi);
281  reply_char(reply, ',');
282  format_uint_hex(&reply->write, REPLY_BUFFER_END(reply),
283  cc2420_last_correlation);
284  reply_char(reply, '\n');
285  } else if (input_line[0] == 'T') {
286  reply_char(reply, 'T');
287  format_int_hex(&reply->write, REPLY_BUFFER_END(reply),
288  stepper_current_period());
289  reply_char(reply, '\n');
290  } else if (input_line[0] == 'q') {
291  return 1;
292  } else {
293  reply_str(reply, "ERR\n");
294  }
295  return 0;
296 }
297 static unsigned int transmit_len = 0;
298 
299 static void
300 send_reply()
301 {
302  if (transmit_len == 0) {
303  transmit_len = tcp_reply.write - tcp_reply.buffer;
304  if (transmit_len > 0) {
305  /* printf("Sending len = %d\n", transmit_len); */
306  uip_send(tcp_reply.buffer, transmit_len);
307  }
308  }
309 }
310 
311 
312 static void
313 handle_connection()
314 {
315  static char exiting = 0;
316  static char line_buffer[100];
317  static char *line_end;
318  if (uip_connected()) {
319  exiting = 0;
320  transmit_len = 0;
321  line_end = line_buffer;
322  tcp_reply.write = tcp_reply.buffer;
323  reply_str(&tcp_reply, "Ready\n");
324  send_reply();
325  }
326  if (uip_acked()) {
327  if (tcp_reply.write - tcp_reply.buffer > transmit_len) {
328  memmove(tcp_reply.buffer, tcp_reply.buffer + transmit_len,
329  tcp_reply.write - tcp_reply.buffer - transmit_len);
330  }
331  tcp_reply.write -= transmit_len;
332  /* printf("Acked: %d left\n", reply_buffer.write-reply_buffer.buffer); */
333  transmit_len = 0;
334  if (exiting && tcp_reply.write == tcp_reply.buffer) {
335  uip_close();
336  exiting = 0;
337  }
338  }
339  if (uip_newdata()) {
340  const char *read_pos = uip_appdata;
341  const char *read_end = read_pos + uip_len;
342  /* printf("Got data\n"); */
343  while(read_pos < read_end) {
344  if (line_end == line_buffer+sizeof(line_buffer)) {
345  /* Buffer too small, just discard everything */
346  line_end = line_buffer;
347  }
348  *line_end++ = *read_pos++;
349  if (line_end[-1] == '\n' || line_end[-1] == '\r' || line_end[-1] == ';'){
350  if (line_end - 1 != line_buffer) {
351  if (handle_line(line_buffer, line_end - 1, &tcp_reply)) {
352  send_reply();
353  /* Postpone closing if there's reply data left to be sent. */
354  if (transmit_len == 0)
355  uip_close();
356  else
357  exiting = 1;
358  break;
359  }
360  }
361  line_end = line_buffer;
362  }
363  }
364  send_reply();
365  }
366 
367  if (uip_poll()) {
368  send_reply();
369  }
370  if(uip_rexmit()) {
371  printf("Retransmit\n");
372  if (transmit_len > 0)
373  uip_send(tcp_reply.buffer, transmit_len);
374  }
375 
376 }
377 
378 PROCESS(udp_stepper_process, "UDP stepper process");
379 
380 PROCESS_THREAD(udp_stepper_process, ev, data)
381 {
382  static struct etimer timer;
383  static struct uip_udp_conn *conn;
384  static char listening = 1; /* Listen for connections from anyone */
385  static uip_ipaddr_t any;
386  PROCESS_EXITHANDLER(goto exit);
387  PROCESS_BEGIN();
388 
389  printf("udp_stepper_process starting\n");
390 
391  uip_ipaddr(&any, 0,0,0,0);
392  conn = udp_new(&any, UIP_HTONS(0), NULL);
393  if (!conn) goto exit;
394  uip_udp_bind(conn, UIP_HTONS(1010));
396  while(1) {
397  PROCESS_YIELD();
398 
399  if(ev == tcpip_event) {
400  if (uip_newdata()) {
401  struct uip_udpip_hdr *header = (struct uip_udpip_hdr *)uip_buf;
402  const char *line_start = uip_appdata;
403  const char *line_end = line_start;
404  const char *packet_end = line_start + uip_len;
405  udp_reply.write = udp_reply.buffer;
406  while(line_end < packet_end) {
407  if (*line_end == '\n' || *line_end == '\r' || *line_end == ';' ) {
408  if (line_end != line_start) {
409  handle_line(line_start, line_end, &udp_reply);
410  }
411  line_start = line_end+1;
412  }
413  line_end++;
414  }
415  /* Check if we are connected to a client, if not reconnect */
416  if (listening) {
417  uip_udp_remove(conn);
418  conn = udp_new(&header->srcipaddr, header->srcport, &conn);
419  if (!conn) goto exit;
420  uip_udp_bind(conn, UIP_HTONS(1010));
421  listening = 0;
422  }
424  tcpip_poll_udp(conn);
425  } else if (uip_poll()) {
426  if (data == &conn) {
427  uip_send(udp_reply.buffer, udp_reply.write - udp_reply.buffer);
428  /* printf("sent %ld\n", udp_reply.write - udp_reply.buffer); */
429  }
430  }
431  } else if (ev == PROCESS_EVENT_TIMER) {
432  uip_udp_remove(conn);
433  conn = udp_new(&any, UIP_HTONS(0), NULL);
434  if (!conn) goto exit;
435  uip_udp_bind(conn, UIP_HTONS(1010));
436  listening = 1;
437  }
438  }
439 
440  exit:
441  /* Contiki does automatic garbage collection of uIP state and we
442  * need not worry about that. */
443  printf("udprecv_process exiting\n");
444  PROCESS_END();
445 }
446 
447 static const uint32_t stepper0_steps_acc[] = MICRO_STEP(0,3);
448 static const uint32_t stepper0_steps_run[] = MICRO_STEP(0,2);
449 static const uint32_t stepper0_steps_hold[] = MICRO_STEP(0,1);
450 
451 static const uint32_t stepper1_steps_acc[] = MICRO_STEP(1,3);
452 static const uint32_t stepper1_steps_run[] = MICRO_STEP(1,2);
453 static const uint32_t stepper1_steps_hold[] = MICRO_STEP(1,1);
454 
455 static StepperAccSeq seq_heap[40];
456 
457 static void
458 init_seq_heap()
459 {
460  unsigned int i;
461  for(i = 0; i < sizeof(seq_heap)/sizeof(seq_heap[0]); i++) {
462  seq_heap[i].next = NULL;
463  stepper_free_seq(&seq_heap[i]);
464  }
465 }
466 
467 static void
468 robot_stepper_init()
469 {
470  disableIRQ();
471  init_seq_heap();
472  stepper_init(AT91C_BASE_TC0, AT91C_ID_TC0);
473  *AT91C_PIOA_OER = STEPPER_INHIBIT;
474  *AT91C_PIOA_MDER = STEPPER_INHIBIT; /* | STEPPER0_IOMASK; */
475  *AT91C_PIOA_CODR = STEPPER_INHIBIT;
476  stepper_init_io(1, STEPPER_IOMASK(0), stepper0_steps_acc,
477  stepper0_steps_run, stepper0_steps_hold,
478  (sizeof(stepper0_steps_run) / sizeof(stepper0_steps_run[0])));
479  stepper_init_io(0, STEPPER_IOMASK(1), stepper1_steps_acc,
480  stepper1_steps_run, stepper1_steps_hold,
481  (sizeof(stepper1_steps_run) / sizeof(stepper1_steps_run[0])));
482  enableIRQ();
483 }
484 
485 
486 PROCESS(stepper_process, "Stepper control process");
487 
488 PROCESS_THREAD(stepper_process, ev, data)
489 {
490  PROCESS_EXITHANDLER(goto exit);
491  PROCESS_BEGIN();
492  robot_stepper_init();
493  tcp_listen(UIP_HTONS(1010));
494 
495  process_start(&udp_stepper_process, NULL);
496  printf("Stepper starting\n");
497 
498  while(1) {
500  if(uip_connected()) {
501  /* printf("connected\n"); */
502  handle_connection(); /* Initialise parser */
503  while(!(uip_aborted() || uip_closed() || uip_timedout())) {
505  handle_connection();
506  }
507  }
508  printf("disconnected\n");
509  }
510 
511  exit:
512  /* Contiki does automatic garbage collection of uIP state and we
513  * need not worry about that. */
514  printf("Stepper exiting\n");
515  PROCESS_END();
516 }
517