-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdigimesh.c
159 lines (142 loc) · 5.04 KB
/
digimesh.c
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* Copyright (c) 2015 Randy Westlund, All rights resrved.
* This code is under the BSD-2-Clause license
*/
#include <stdint.h> /* integer type definitions */
#include <string.h> /* memcpy */
#include "digimesh.h"
/* declared as extern in the header */
volatile uint8_t xbee_comm_err_count;
/* internal helper functions */
static uint8_t get_frame_id(void);
/******************************************
* RECEIVE FUNCTIONS
******************************************/
/* Should be called once for each incoming byte. Will return an xbee_packet
* pointer when a packet has been completed */
struct xbee_packet *
xbee_add_byte(uint8_t c) {
/* Two buffers for receiving packets. We receive into one, then swap
* pointers and receive into the other. This lets the application handle a
* packet while we read the next, without using memcpy. Obviously the
* application must read it quickly */
static struct xbee_packet p1, p2;
/* start out using the first Rx buffer */
static struct xbee_packet *p = &p1;
/* holds the payload length of the packet we're receiving */
static uint16_t len;
/* oob error -- drop the packet before we overflow */
if(p->len >= XBEE_BUFFER_SIZE) {
p->len = 0; len = 0;
/* log the err */
if (xbee_comm_err_count < 255) xbee_comm_err_count++;
}
/* if no data in buffer, next byte must be START */
if(!p->len && c != XBEE_START) {
/* log the err */
if (xbee_comm_err_count < 255) xbee_comm_err_count++;
return NULL;
}
/* read in next byte */
p->buf[p->len++] = c;
/* if we just got the payload length */
if(p->len == 3) {
len = ((uint16_t)p->buf[1])<<8 | p->buf[2];
return NULL;
}
/* if we've finished the packet */
if (len && (p->len == len + 4)) {
/* if the packet is valid */
if(p->buf[p->len-1] == xbee_calc_checksum(p)) {
len = 0;
/* swap which buffer we're using and return a pointer to the one we
* just filled. This gives us double-buffering without the memcpy */
if (p == &p1) {
p = &p2;
p->len = 0;
return &p1;
}
else {
p = &p1;
p->len = 0;
return &p2;
}
}
/* drop the bad packet */
else {
p->len = 0; len = 0;
/* log the err */
if (xbee_comm_err_count < 255) xbee_comm_err_count++;
}
}
return NULL;
}
/******************************************
* TRANSMIT FUNCTIONS
******************************************/
/* Build packet for an AT command. Pass a pointer to an empty xbee_packet, a
* pointer to the buffer to use for the payload, and the length of the payload.
* Returns the frame_id used. Example arg: "NITEST" set NI to "TEST" */
uint8_t
xbee_build_command_packet(struct xbee_packet *p, const uint8_t *data,
uint16_t bytes) {
/* use 0 for the frame_id if ACKs are disabled */
uint8_t frame_id = p->disable_ack ? 0x00 : get_frame_id();
p->len = bytes + 6;
p->buf[0] = XBEE_START;
p->buf[1] = (uint8_t)((p->len-4)>>8);
p->buf[2] = (uint8_t)(p->len-4);
p->buf[3] = XBEE_FRAME_AT_COMMAND;
p->buf[4] = frame_id;
memcpy(p->buf+5, data, bytes);
p->buf[p->len-1] = xbee_calc_checksum(p);
return frame_id;
}
/* Build a data packet (send a buffer to an address). An empty addr means
* broadcast. Returns the frame_id used */
uint8_t
xbee_build_data_packet(struct xbee_packet *p, uint64_t addr,
const uint8_t *data, uint16_t bytes) {
p->len = bytes + 18;
/* use 0 for the frame_id if ACKs are disabled */
uint8_t frame_id = p->disable_ack ? 0x00 : get_frame_id();
if(!addr) addr = XBEE_BROADCAST_ADDRESS;
p->buf[0] = XBEE_START;
p->buf[1] = (uint8_t)((p->len-4)>>8); /* len upper */
p->buf[2] = (uint8_t)((p->len-4)); /* len lower */
p->buf[3] = XBEE_FRAME_TRANSMIT_REQUEST;
p->buf[4] = frame_id;
p->buf[5] = addr>>56; /* addr high */
p->buf[6] = addr>>48;
p->buf[7] = addr>>40;
p->buf[8] = addr>>32;
p->buf[9] = addr>>24;
p->buf[10] = addr>>16;
p->buf[11] = addr>>8;
p->buf[12] = addr; /* addr low */
p->buf[13] = 0xff; /* reserved */
p->buf[14] = 0xfe; /* reserved */
p->buf[15] = 0x00; /* max hops */
p->buf[16] = 0x00; /* Tx options */
memcpy((uint8_t*)p->buf+17, data, bytes); /* insert data payoad */
p->buf[p->len-1] = xbee_calc_checksum(p);
return frame_id;
}
/******************************************
* INTERNAL HELPER FUNCTIONS
******************************************/
/* Calculate and return checksum from a message buffer */
uint8_t
xbee_calc_checksum(const struct xbee_packet *p) {
uint16_t i;
uint8_t chksum = 0;
for(i = 3; i < p->len-1; i++) chksum += p->buf[i];
return 0xff - chksum;
}
/* Return consecutive frame IDs, skipping zero */
uint8_t
get_frame_id() {
static uint8_t frame_id;
/* don't use ID 0, it means no ACK */
if(frame_id == 255) frame_id = 0;
return ++frame_id;
}