aboutsummaryrefslogtreecommitdiff
path: root/arduino/ace/framing.c
blob: 4d9c5ded43ab3ac10b871dee648051b0ee426eae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include "framing.h"

static inline bool is_cmd(uint8_t byte) {
  return (byte == FRAME_START || byte == FRAME_STOP || byte == FRAME_ESCAPE);
}

static inline void reset(framer* f) {
  f->position = -1;
  f->checksum = 0x00;
}

static inline void accept(framer* f, uint8_t byte) {
  
  //if a new byte would cause an overflow, restart frame
  //note that this should not happen if both communicating parties have defined the same maximum frame length
  if (f->position >= MAX_FRAME_SIZE) {
    reset(f);
    return;
  }
  
  if (f->position != -1) { // i.e. a previous byte exists
    f->buffer[f->position] = f->staged; 
    f->checksum = f->checksum ^ f->staged;
  }
  
  f->position += 1;
  f->staged = byte;
}

void receive_byte(framer* f, uint8_t byte) {
  
  switch(f->state) {
    case ESCAPING:
      accept(f, byte);
      f->state = RECEIVING;
      break;
      
    case WAITING:
      if (byte == FRAME_START) {
        reset(f);
        f->state = RECEIVING;
      }
      break;
      
    case RECEIVING:
      switch(byte) {
        case FRAME_ESCAPE:
          f->state = ESCAPING;
          break;
        case FRAME_START:
          reset(f);
          break;
        case FRAME_STOP:
          f->state = WAITING;
          if (f->staged == f->checksum) { //at this point, staged byte is the checksum sent in the frame (last byte of frame)
            f->receiver(f->position, f->buffer);
          }
          break;
          
        default:
          accept(f, byte);
          break;
      }
  }
}

void send_frame(framer* f, int16_t size, const uint8_t * const data_out) {
  uint8_t checksum = 0x00;
  uint8_t byte;
  send_byte_function sender = f->sender;
  
  sender(FRAME_START);
  int i;
  for (i = 0; i < size; ++i) {
    byte = data_out[i];
    if (is_cmd(byte)) sender(FRAME_ESCAPE);
    sender(byte);
    checksum = checksum ^ byte;
  }
  if (is_cmd(checksum)) sender(FRAME_ESCAPE);
  sender(checksum);
  sender(FRAME_STOP);
}

void init_framer(framer* f) {
  f->state = WAITING;
  reset(f);
}