Contiki 3.x
avr-handler.c
1 #include "avr-handler.h"
2 
3 /**
4  * Turn debuggin on.
5  * NOTE: A lot of debugging calls are disabled as interrupts are not rentrant,
6  * and the debugging calls can cause us to miss interrupts.
7  */
8 //#define DEBUG_ON
9 #ifdef DEBUG_ON
10  #include <stdio.h>
11  #define DEBUG(...) printf(__VA_ARGS__)
12 #else
13  #define DEBUG(...)
14 #endif
15 
16 PROCESS(avr_process, "AVR Process");
17 
18 /**
19  * Event to get data from an AVR
20  */
21 #define AVR_EVENT_GET_DATA 1
22 
23 /**
24  * Event indicating we've received valid data from an AVR
25  */
26 #define AVR_EVENT_GOT_DATA 2
27 
28 /**
29  * Timeout for receiving a reply in seconds
30  */
31 #define AVR_TIMEOUT 10
32 
33 /**
34  * Maximum number of retries.
35  * There will be AVR_RETRY attempts in total.
36  */
37 #define AVR_RETRY 4
38 
39 /**
40  * RS484 AVR protocol defintions
41  */
42 #define AVR_OPCODE_ECHO 0x00
43 #define AVR_OPCODE_LIST 0x01
44 #define AVR_OPCODE_GET_DATA 0x02
45 #define AVR_OPCODE_SET_GAIN 0x03
46 #define AVR_OPCODE_RESPONSE 0xFF
47 #define AVR_MASTER_ADDR 0x00
48 
49 /**
50  * The destination address (ie 1st byte) of the received message.
51  */
52 static uint8_t incm_dest;
53 
54 /**
55  * The type (ie 2nd byte) of the received message.
56  */
57 static uint8_t incm_type;
58 
59 /**
60  * The size of the received message.
61  * This should / could only only be a byte, but the odd number of bytes messes up alignmenent and the compiler generates
62  * broken code (msp430 cannot deal with relocation of unaligned addresses)
63  */
64 static uint16_t incm_num;
65 
66 /**
67  * The crc of the received message (ie last 2 bytes).
68  */
69 static uint8_t incm_crc[2];
70 
71 /**
72  * The avr_data to write the received message payload to.
73  */
74 static struct avr_data *incm_data;
75 
76 /**
77  * True if we're expecting to receive things, false otherwise
78  */
79 static volatile bool isReceiving;
80 
81 /**
82  * Function to write to the serial port.
83  * @param buf The data to write.
84  * @param len The amount of bytes to write.
85  */
86 static void (*serial_write)(uint8_t *buf, int len);
87 
88 /**
89  * Callback for when we're done dealing with an AVR.
90  * @param isSuccess True if we succesfully read data from the AVR and wrote it
91  * to the passed in avr_data, false otherwise.
92  */
93 static void (*callback)(bool isSuccess);
94 
95 /**
96  * Add a byte to a CRC.
97  * @param crc The existing CRC. 0xFFFF should be used as a starting value.
98  * @param a The byte to add
99  * @return The new crc
100  *
101  * Note: This is the exact crc function used in the AVR & python
102  * There is a contiki CRC function but not sure it'll
103  * behave in the same way.
104  */
105 static uint16_t crc16(uint16_t crc, uint8_t a);
106 
107 /**
108  * Add several bytes to a CRC.
109  * @param crc The existing CRC. 0xFFFF should be used as a starting value.
110  * @param buf The bytes to add
111  * @param len The number of bytes to add
112  * @return The new crc
113  */
114 static uint16_t crc16_all(uint16_t crc, uint8_t *buf, uint8_t len);
115 
116 /**
117  * Chack a given message is a valid response message.
118  * (ie the message is for us, is of type response, and has a valid crc).
119  * @param addr The address of the AVR
120  * @param opcode The type of the message
121  * @param payload The payload to send in the message
122  * @parama payload_length The length of the payload
123  * @param crc The two crc bytes of the message
124  */
125 static bool check_message(uint8_t addr, uint8_t opcode, uint8_t *payload, uint8_t payload_length, uint8_t crc[2]);
126 
127 /**
128  * Send a message to an AVR
129  * @param addr The address of the AVR
130  * @param opcode The type of the message
131  * @param payload The payload to send in the message
132  * @parama payload_length The length of the payload
133  * @return True if the message was sent, false otherwise.
134  */
135 static bool send_message(uint8_t addr, uint8_t opcode, uint8_t *payload, uint8_t payload_length);
136 
137 int avr_input_byte(uint8_t byte) {
138  //DEBUG("Got some data!\n");
139 
140  if (!isReceiving) {
141  DEBUG("Not receiving! Discarding data\n");
142  return false;
143  }
144 
145  // If the buffer is full, just ignore whatever extra data comes in
146  if (*incm_data->len >= incm_data->size) {
147  DEBUG("Incm Buffer full, len %d size %d! Discarding data\n", *incm_data->len, incm_data->size);
148  return false;
149  }
150 
151  incm_num++;
152 
153  // Cases 1-4 progressively "load the bases",
154  // default case assumes bases are loaded and simply shuffles everything by one
155  // to store the new byte
156  // Cases 1-3 return directly, as a message of that length can't be valid, so there's no point in checking.
157  switch (incm_num) {
158  case 1:
159  // First byte is the address
160  incm_dest = byte;
161  return true;
162 
163  case 2:
164  // Second byte is the type
165  incm_type = byte;
166  return true;
167 
168  case 3:
169  incm_crc[0] = byte;
170  return true;
171 
172  case 4:
173  incm_crc[1] = byte;
174  break;
175 
176  default:
177  incm_data->data[(*incm_data->len)++] = incm_crc[0];
178  incm_crc[0] = incm_crc[1];
179  incm_crc[1] = byte;
180  break;
181  }
182 
183  // If this is a valid message, notify the process
184  if (check_message(incm_dest, incm_type, incm_data->data, *incm_data->len, incm_crc)) {
185  process_post(&avr_process, AVR_EVENT_GOT_DATA, NULL);
186  }
187 
188  return true;
189 }
190 
191 PROCESS_THREAD(avr_process, ev, data_ptr) {
192  static struct etimer avr_timeout_timer;
193  static uint8_t attempt;
194  static uint8_t num_required;
195  static uint8_t success_num;
196 
197  PROCESS_BEGIN();
198 
199  while (true) {
201 
202  DEBUG("Got event %d\n", ev);
203 
204  if (ev == AVR_EVENT_GET_DATA) {
205 
206  incm_data = data_ptr;
207  num_required = 1;
208 
209  success_num = 0;
210 
211  // If it's a temp accel chain, it needs to be read twice to get valid data
212  if (incm_data->id < 0x10) {
213  num_required = 2;
214  }
215 
216  for (attempt = 0; attempt < AVR_RETRY * num_required; attempt++) {
217 
218  DEBUG("Getting data from avr %x, attempt %d, success_num %d\n", incm_data->id, attempt, success_num);
219 
220  // Reset the len of the payload
221  *incm_data->len = 0;
222  incm_num = 0;
223 
224  etimer_set(&avr_timeout_timer, CLOCK_SECOND * AVR_TIMEOUT);
225 
226  isReceiving = true;
227 
228  // Request data from the node
229  send_message(incm_data->id, AVR_OPCODE_GET_DATA, NULL, (int)NULL);
230 
231  // Wait for the data
232  PROCESS_WAIT_EVENT_UNTIL(ev == AVR_EVENT_GOT_DATA || etimer_expired(&avr_timeout_timer));
233  etimer_stop(&avr_timeout_timer);
234 
235  isReceiving = false;
236 
237  success_num += (ev == AVR_EVENT_GOT_DATA);
238 
239  DEBUG("Received %d bytes. Success_num %d ADDR %u TYPE %u CRC %u: ", incm_num, success_num, incm_dest, incm_type, *((uint16_t *) incm_crc));
240 #ifdef DEBUG_ON
241  int i;
242  for (i = 0; i < *incm_data->len; i++) {
243  printf("%02x,", incm_data->data[i]);
244  }
245  printf("\n");
246 #endif
247 
248  // If we got enough successful rpelies
249  if (success_num >= num_required) {
250  break;
251  }
252  }
253 
254  DEBUG("Done after %d retries\n", attempt);
255 
256  callback(success_num >= num_required);
257  }
258  }
259 
260  PROCESS_END();
261 }
262 
263 uint16_t crc16(uint16_t crc, uint8_t a) {
264  //DEBUG("Starting CRC with 0x%04x\n", crc);
265  uint8_t i;
266  //DEBUG("Processing CRC for 0x%04x\n", a);
267  crc ^= (uint16_t)a;
268  //DEBUG("After XOR = 0x%04x\n", crc);
269  for (i = 0; i < 8; ++i) {
270  if (crc & 1) {
271  crc = (crc >> 1) ^ 0xA001;
272  } else {
273  crc = (crc >> 1);
274  }
275  //DEBUG("CRC r%d = 0x%04x\n",i, crc);
276  }
277  //DEBUG("CRC RET = 0x%04x\n", crc);
278  return crc;
279 }
280 
281 uint16_t crc16_all(uint16_t crc, uint8_t *buf, uint8_t len) {
282  uint8_t i;
283  for (i = 0; i < len; i++) {
284  crc = crc16(crc, buf[i]);
285  }
286  return crc;
287 }
288 
289 bool send_message(uint8_t addr, uint8_t opcode, uint8_t *payload, uint8_t payload_length) {
290  //DEBUG("Dest: %02x\n", addr);
291  //DEBUG("Optcode: %02x\n", opcode);
292  //DEBUG("Payload length: %i\n", payload_length);
293 
294  if (serial_write == NULL) {
295  DEBUG("No writebyte specified\n");
296  return false;
297  }
298 
299  // Add the address and type to the crc
300  uint16_t crc = crc16(0xFFFF, addr);
301  crc = crc16(crc, opcode);
302 
303  // Add the payload to the crc
304  crc = crc16_all(crc, payload, payload_length);
305 
306  DEBUG("CRC is %u High: %x Low: %x High2: %x Low2: %x\n", crc, (crc >> 8) & 0xFF, crc & 0xFF, *(((uint8_t *) &crc) + 1), *((uint8_t *) &crc));
307 
308  serial_write(&addr, 1);
309  serial_write(&opcode, 1);
310  serial_write(payload, payload_length);
311 
312  // MSP430 is little endian - low byte is at lowest address.
313  // We use little endian for the avr proto too
314  serial_write(((uint8_t *) &crc), 2);
315 
316  return true;
317 }
318 
319 bool check_message(uint8_t addr, uint8_t opcode, uint8_t *payload, uint8_t payload_length, uint8_t crc[2]) {
320  if (addr != AVR_MASTER_ADDR) {
321  //DEBUG("Not for us");
322  return false;
323  }
324 
325  if (opcode != AVR_OPCODE_RESPONSE) {
326  //DEBUG("Not a response packet\n");
327  return false;
328  }
329 
330  // MSP430 and avr proto are both little endian, we can just cast the result
331  uint16_t rcv_crc = *((uint16_t *) crc);
332  //DEBUG("Recieved CRC: %d\n", rcv_crc);
333 
334  uint16_t cal_crc = crc16(0xFFFF, addr);
335  cal_crc = crc16(cal_crc, opcode);
336  cal_crc = crc16_all(cal_crc, payload, payload_length);
337 
338  //DEBUG("Calculated CRC: %d\n", cal_crc);
339 
340  if (rcv_crc != cal_crc) {
341  //DEBUG("CRCs do not match: Ignoring\n");
342  return false;
343  }
344 
345  //DEBUG("CRCs match\n");
346 
347  return true;
348 }
349 
350 void avr_set_callback(void (*cb)(bool isSuccess)) {
351  callback = cb;
352 }
353 
354 bool avr_get_data(struct avr_data *data) {
355  // If we don't have a callback set, we can't do anything
356  if (callback == NULL) {
357  DEBUG("Callback not set!\n");
358  return false;
359  }
360 
361  // If we're already in the process of receiving data, try later
362  if (isReceiving) {
363  DEBUG("Already receiving!\n");
364  return false;
365  }
366 
367  DEBUG("Sending event for avr %x, size %d\n", data->id, data->size);
368 
369  return process_post(&avr_process, AVR_EVENT_GET_DATA, data) == PROCESS_ERR_OK;
370 }
371 
372 void avr_set_output(void (*wb)(uint8_t *buf, int len)) {
373  serial_write = wb;
374 }
uint8_t id
The ID of the AVR to sample from.
Definition: avr-handler.h:18
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
uint8_t * data
The data.
Definition: avr-handler.h:28
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
A timer.
Definition: etimer.h:76
uint8_t * len
The length of data.
Definition: avr-handler.h:33
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition: process.h:157
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
void etimer_stop(struct etimer *et)
Stop a pending event timer.
Definition: etimer.c:243
#define NULL
The null pointer.
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
#define PROCESS_ERR_OK
Return value indicating that an operation was successful.
Definition: process.h:74
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
uint8_t size
The size of data.
Definition: avr-handler.h:23
A struct used to request data from an AVR.
Definition: avr-handler.h:13
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120