aboutsummaryrefslogtreecommitdiff
path: root/arduino/ace_old/link.c
blob: 408e14e9fbc5fb765ec0ef39e042899316184b33 (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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "link.h"
#include "physical.h"

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

typedef enum {
  WAITING,
  RECEIVING,
  ESCAPING
} link_state;

#define FRAME_ESCAPE 0x02
#define FRAME_START 0x03
#define FRAME_END 0x10


void from_physical_layer(uint8_t byte) {
  static link_state state = WAITING;
  static uint16_t position = 0; //read position
  static uint8_t packet_data_buffer[MAX_PACKET_SIZE];
  static packet received = {packet_data_buffer, 0};
  static uint8_t checksum = 0x00;
  
  static bool previous_exists = false;
  static uint8_t previous_byte;
  
  #define start_receiving() \
    position = 0; \
    previous_exists = false; \
    checksum = 0x00
  
  #define accept(byte) \
    if (position >= MAX_PACKET_SIZE) {start_receiving(); return;} \
    if (previous_exists) { \
      packet_data_buffer[position] = previous_byte; \
      position = position + 1; \
      checksum = checksum ^ previous_byte; \
      previous_byte = byte; \
    } else { \
      previous_byte = byte; \
      previous_exists = true; \
    }
    

  switch(state) {
    case ESCAPING:
      accept(byte);
      state = RECEIVING;
      break;
      
    case WAITING:
      if (byte == FRAME_START) {
        start_receiving();
        state = RECEIVING;
      }
      break;
    case RECEIVING:
      switch(byte) {
        case FRAME_ESCAPE:
          state = ESCAPING;
          break;
        case FRAME_START:
          start_receiving();
          break;
        case FRAME_END:
          state = WAITING;
          uint8_t sent_checksum = previous_byte;
          if (sent_checksum == checksum) {
            received.length = position;
            from_link_layer(&received);
          }
          
          break;
        default:
          accept(byte);
          break;
      }
  }
  
  #undef accept
  #undef start_receiving
}

void to_link_layer(packet* s) {
  uint8_t checksum = 0x00;
  uint8_t byte;
  int i;
  
  to_physical_layer(FRAME_START);
  for (i = 0; i < (s->length); ++i) {
    byte = s->data[i];
    if (byte == FRAME_START || byte == FRAME_END || byte == FRAME_ESCAPE)
      to_physical_layer(FRAME_ESCAPE);
    checksum = checksum ^ byte;
    to_physical_layer(byte);
  }
  if (checksum == FRAME_START || checksum == FRAME_END || checksum == FRAME_ESCAPE)
    to_physical_layer(FRAME_ESCAPE);
  to_physical_layer(checksum);
  to_physical_layer(FRAME_END);
};