-
Notifications
You must be signed in to change notification settings - Fork 0
/
XBEE_Controller.c
273 lines (225 loc) · 8.5 KB
/
XBEE_Controller.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
/*
* XBEE_controller (c) Copyright 2015 B. Seeger
* XBEE_controller can be copied and distributed freely for
* any non-commercial purposes. XBEE_controller can only be
* incorporated into commercial software with the permission
* of the current author [B. Seeger].
*
* Written By: B. Seeger
* Date: 1/23/2015
*
*
* XBEE_controller - listens for XBEE broadcast on port PORT
* and will print out information to stdout based on what
* it finds.
* You can configure this software to work with many different
* devices hanging off of the XBEE.
*
* Currently supported devices:
* 1) TMP36 - callback: TMP36_processor
*
*
* @TODO - add timeout so the client doesn't wait forever to
* get data from a potentially dead XBEE
*
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <signal.h>
#include "XBEE_Controller.h"
#define VREF 2500 /* 250 mv, or 1250 (1.25 mv) */
#define MSB 0
#define LSB 1
#define TRUE 1
#define FALSE 0
int g_verbose = FALSE;
int g_mo_mode = FALSE; /* minimal output mode */
typedef struct {
unsigned char number1[2]; /* 0, 1 */
unsigned char number2[2]; /* 2, 3 */
unsigned char packetID; /* 4 */
unsigned char encryptPad; /* 5 */
unsigned char commandID; /* 6 */
unsigned char commandOpt; /* 7 */
unsigned char numSamples; /* 8 */
unsigned char digitalMask[2]; /* 9, 10 */
unsigned char analogMask; /* 11 */
/* If digitalMask is anything other then zero, the samples[0] & samples[1] will
* represent the digital Sample. Then the analog samples will start at samples[2].
*
* If digitalMask == 0, then there will be no digital sample and analog samples will
* start at samples[0].
*/
unsigned char samples[32];
} XBEE_Message;
#define TMP36_OFFSET_VOLTAGE 500 /* think 500 mv = 0 celsius */
void TMP36_processor(int id, unsigned char data1, unsigned char data2, XBEE_Message_Output *output) {
int AD_dec = (data1 << 8) | data2;
float AD_mv = ((AD_dec * VREF) / 1023) - TMP36_OFFSET_VOLTAGE;
float celsius = (AD_mv / 10); /* 10 mv per degree C */
float fahrenheit = celsius * 1.8 + 32;
if (g_verbose) {
printf("Signal %d: A/D dec: %d A/D mV: %g %g C %g f\n", id, AD_dec, AD_mv, celsius, fahrenheit);
}
if (g_mo_mode) {
printf("%g,", fahrenheit);
} else {
printf("Signal %d: %g f\n", id, fahrenheit);
}
// check this here, so we can at least get printf's if the output is not set.
if (output) {
output->celsius = celsius;
}
}
void quit(char *msg) {
perror(msg);
exit(EXIT_SUCCESS); // should this be failure?
}
void signal_handler(int sig) {
if (sig == SIGINT) {
printf("Good Bye!");
exit (EXIT_SUCCESS);
}
printf("Recieved signal %d (%s)\n", sig, strsignal(sig));
exit (EXIT_SUCCESS);
}
void print_XBEE_Message(XBEE_Message *message) {
if (message == NULL) return;
printf("Number 1: %02X %02X\n", message->number1[0], message->number1[1]);
printf("Number 2: %02X %02X\n", message->number2[0], message->number2[1]);
printf("Packet ID: %02X\n", message->packetID);
printf("Encryption Pad: %02X\n", message->encryptPad);
printf("Command ID: %02X\n", message->commandID);
printf("Command Options: %02X\n", message->commandOpt);
printf("Number of Samples: %02X\n", message->numSamples);
printf("Digital Mask: %02X %02X\n", message->digitalMask[MSB], message->digitalMask[LSB]);
printf("Analog Mask: %02X\n", message->analogMask);
int spot = 0;
int sampleNo = 0;
if (message->digitalMask[MSB] & 0xFF || message->digitalMask[LSB] & 0xFF) {
printf("Digital Sample: %02X %02X\n", message->samples[sampleNo], message->samples[sampleNo+1]);
sampleNo += 2;
}
for (spot = 0; spot < 8; spot++) {
unsigned char mask = 1 << spot;
if (mask & message->analogMask) {
printf("Analog %d: %02X %02X\n", sampleNo / 2, message->samples[sampleNo], message->samples[sampleNo+1]);
}
sampleNo += 2;
}
}
void usage(char *progname) {
printf("Usage: \n\tXBEE_Controller %s [-c NUM]\n", progname);
printf("\t-c NUM where NUM is the number of times to listen for data. Default: 1\n");
printf("\t-m minimal output mode, just output TMP1, TMP2, etc.\n");
}
int main (int argc, char **argv) {
struct sockaddr_in si_server;
struct sockaddr_in si_mine;
int option = 0;
int run_count = 1;
int timeout = 30; /* seconds */
int sockfd = 0;
socklen_t sockaddr_len = sizeof(si_server);
int msgsize = 0;
XBEE_Message message;
XBEE_Config config;
XBEE_Message_Output output;
memset(&message, 0, sizeof(message));
memset(&config, 0, sizeof(config));
memset(&output, 0, sizeof(output));
while ((option = getopt(argc, argv, "c:mv")) != -1) {
switch(option) {
case 'c':
run_count = atoi(optarg);
break;
case 'm':
g_mo_mode = TRUE;
break;
case 'v':
g_verbose = TRUE;
break;
default: usage(argv[0]);
}
}
/* This directs the code to the right data processor,
* based on what is physically connected to your board.
* In my case, we have a TMP36 hooked up to analog 1
* and that is all.
*/
config.analog_processors[0] = &TMP36_processor;
config.analog_processors[1] = &TMP36_processor;
/* register signal handler, so we can kill the program gracefully */
if (signal(SIGINT, signal_handler) == SIG_ERR) {
quit("Unable to register signal handler for SIGINT");
}
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd == -1) {
quit("Unable to open socket");
}
memset((char*)&si_server, 0, sockaddr_len);
memset(&(si_mine), 0, sizeof(si_mine));
si_mine.sin_family = AF_INET;
si_mine.sin_addr.s_addr = INADDR_ANY;
si_mine.sin_port = htons(PORT);
if (bind(sockfd, (struct sockaddr *)&si_mine, sizeof(struct sockaddr)) == -1) {
quit("Bind failed");
}
if (g_verbose) {
printf("Listening on port %d now...\n", PORT);
}
while (run_count > 0) {
if ((msgsize = recvfrom(sockfd, (unsigned char*)&message, sizeof(message), 0, (struct sockaddr *) &si_server, &sockaddr_len)) == -1) {
quit("Received bad packet. Goodbye!\n");
}
if (g_verbose) {
printf("Got message. It is %d bytes long\n", msgsize);
printf("-----\n");
print_XBEE_Message(&message);
}
// verify that the first two numbers XOR into 0x4242
unsigned char msb_fortytwo = message.number1[1] ^ message.number2[1];
unsigned char lsb_fortytwo = message.number1[0] ^ message.number2[0];
if (g_verbose) {
printf("Sanity check (should be 0x4242) 0x%02X%02X\n", msb_fortytwo, lsb_fortytwo);
}
int sampleNo = 0;
int spot = 0;
if (message.digitalMask[MSB] & 0xFF || message.digitalMask[LSB] & 0xFF) {
// this is untested - I don't have anything on the DIO stuff.
if (config.digital_processor != NULL) {
config.digital_processor(sampleNo/2, message.samples[sampleNo], message.samples[sampleNo+1], &output);
}
// Always move past, since there is a digital sample, even if there is
// no processor for it.
sampleNo+=2; // move past digital sample
}
for(spot = 0; spot < 8; spot++) {
unsigned char mask = 1 << spot;
if (message.analogMask & mask) {
/* then run this spot! */
if (config.analog_processors[spot] != NULL) {
if (g_verbose) {
printf("Processing analog signal %d. \n", spot);
}
config.analog_processors[spot](sampleNo/2, message.samples[sampleNo], message.samples[sampleNo+1], &output);
} else {
printf("Skipping analog signal %d: no processor registered for it.\n", spot+1);
}
sampleNo+=2;
}
}
// TODO - ship off the XBEE_Message_Output to somewhere.
memset(&message, 0, sizeof(message));
run_count -= 1;
}
if (g_verbose) {
printf("Goodbye!");
}
exit(EXIT_SUCCESS);
}