1 | /**
|
---|
2 | * Firmware of the Arduino GPS reciever.
|
---|
3 | *
|
---|
4 | * This code was inspired by http://quaxio.com/arduino_gps/ ,
|
---|
5 | * http://playground.arduino.cc/Tutorials/GPS and
|
---|
6 | * http://blog.bouni.de/blog/2012/06/25/a-arduino-telnet-server/
|
---|
7 | *
|
---|
8 | *
|
---|
9 | * Autor: Max Knötig
|
---|
10 | */
|
---|
11 |
|
---|
12 | #include <SoftwareSerial.h>
|
---|
13 | #include <string.h>
|
---|
14 | #include <stdio.h>
|
---|
15 | #include <SPI.h>
|
---|
16 | #include <Ethernet.h>
|
---|
17 |
|
---|
18 | #define MAX_CMD_LENGTH 15
|
---|
19 |
|
---|
20 | //define led pins for display on the box
|
---|
21 | int arduLed = 8; // on: arduino is on. blinking: serial message parsed
|
---|
22 | int gpsLed = 7; // on: venus gps chip on. blinking: gps locked
|
---|
23 | int vetoLed = 6; // on: veto active. off: veto not active ( active low btw. )
|
---|
24 |
|
---|
25 | int arduLedOn = 0;
|
---|
26 | int gpsLedOn = 0;
|
---|
27 | int vetoLedOn = 0;
|
---|
28 |
|
---|
29 | //define inputs and outputs for the veto system
|
---|
30 | int vetoPin = 3; // the veto output pin ( active low )
|
---|
31 | int navPin = 2; // the nav pin, from the venus gps. this is for steering the gpsLed
|
---|
32 |
|
---|
33 | //globals for storing the serial nema message
|
---|
34 | int byteGPS=-1; // will become the read byte from the Venus GPS
|
---|
35 | char cmd[7] = "$GPGGA"; // the NMEA message type we want to know
|
---|
36 | int counter = 0; // counts how many bytes were received (max 300)
|
---|
37 | char buf[300] = ""; // buffer to store the message
|
---|
38 | String nemaMsg; // this buffer stores the last complete nema message
|
---|
39 |
|
---|
40 | //variables to save (or dump) nema message parts
|
---|
41 | int seconds = 0; // this will become the veto trigger criterion ( seconds = 59 -> veto )
|
---|
42 | int dump = 0; // the other variables are used when sscanf the nema message
|
---|
43 | char cdump = '0'; // for dumping reasons
|
---|
44 | char hexdump[8]="0000000";
|
---|
45 |
|
---|
46 | //the addresses for the shield (commented: ethz mode):
|
---|
47 | byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xB9, 0x32 };
|
---|
48 | byte ip[] = { 10, 0, 100, 112 };
|
---|
49 | //byte ip[] = { 192, 33, 103, 241 };
|
---|
50 | //byte dns[] = { 129, 132, 98, 12 };
|
---|
51 | //byte gatew[] = { 192, 33, 96, 1 };
|
---|
52 | //byte smask[] = { 255, 255, 248, 0 };
|
---|
53 |
|
---|
54 |
|
---|
55 | //the globals for the ethernet communication
|
---|
56 | String etherCmd; // store the ethernet command in here
|
---|
57 | EthernetServer server = EthernetServer(23);
|
---|
58 | EthernetClient client;
|
---|
59 | boolean connected = false;
|
---|
60 |
|
---|
61 | //the state as decided by the user. 0 = veto_off, 1 = veto_60, 2 = veto_on
|
---|
62 | int state = 1;
|
---|
63 |
|
---|
64 | /**
|
---|
65 | * Setup arduino and gps
|
---|
66 | */
|
---|
67 | void setup() {
|
---|
68 | // define I/O pins
|
---|
69 | pinMode(arduLed, OUTPUT); // Initialize Arduino LED pin
|
---|
70 | pinMode(gpsLed, OUTPUT); // Initialize GPS LED pin
|
---|
71 | pinMode(vetoLed, OUTPUT); // Initialize Veto LED pin
|
---|
72 | pinMode(vetoPin, OUTPUT); // Initialize Veto pin
|
---|
73 | pinMode(navPin, INPUT); // Initialize Nav pin
|
---|
74 |
|
---|
75 | // set their startup modes
|
---|
76 | digitalWrite(vetoPin, HIGH); // put veto to high ( no veto ) in startup mode
|
---|
77 | digitalWrite(arduLed, HIGH); // put the arduino led high when starting
|
---|
78 | arduLedOn = 1;
|
---|
79 |
|
---|
80 | //begin the ethernet and serial connections
|
---|
81 | Ethernet.begin(mac, ip); //, dns, gatew, smask); // this is to begin (ethz) ethernet
|
---|
82 | Serial.begin(115200); // the gps serial connection
|
---|
83 | server.begin();
|
---|
84 |
|
---|
85 | reset(); // reset the counters (just in case)
|
---|
86 | }
|
---|
87 |
|
---|
88 | /**
|
---|
89 | * the loop which processes ethernet and serial connections
|
---|
90 | */
|
---|
91 | void loop()
|
---|
92 | {
|
---|
93 | //serial part
|
---|
94 | byteGPS=Serial.read(); // Read a byte of the serial port
|
---|
95 |
|
---|
96 | if (byteGPS == -1) { // See if the port is empty yet
|
---|
97 | delay(1);
|
---|
98 | } else {
|
---|
99 | if (!handle_byte(byteGPS)) {
|
---|
100 | reset();
|
---|
101 | Serial.flush();
|
---|
102 | }
|
---|
103 | }
|
---|
104 |
|
---|
105 | //ethernet part
|
---|
106 | client = server.available(); // check if the server is available
|
---|
107 |
|
---|
108 | if (client == true) { // if there is a new client
|
---|
109 | if (!connected) {
|
---|
110 | client.flush();
|
---|
111 | connected = true;
|
---|
112 | }
|
---|
113 |
|
---|
114 | while (client.available() > 0) { // while there is incoming data read it
|
---|
115 | readEthernetCommand(client.read());
|
---|
116 | }
|
---|
117 | }
|
---|
118 |
|
---|
119 | if( digitalRead(navPin) == 0){ // test if the gps blinkes, if yes, blink the gps led as well
|
---|
120 | digitalWrite(gpsLed, HIGH);
|
---|
121 | gpsLedOn=1;
|
---|
122 | } else {
|
---|
123 | digitalWrite(gpsLed, LOW);
|
---|
124 | gpsLedOn=0;
|
---|
125 | }
|
---|
126 | }
|
---|
127 |
|
---|
128 | /**
|
---|
129 | * handle the byte read from the GPS module
|
---|
130 | */
|
---|
131 | int handle_byte(int byteGPS) {
|
---|
132 |
|
---|
133 | if (counter == 300) { // if the buffer is full return 0
|
---|
134 | return 0;
|
---|
135 | }
|
---|
136 |
|
---|
137 | //read the first char
|
---|
138 | buf[counter] = byteGPS;
|
---|
139 |
|
---|
140 | if (counter == 6) { // if 6 chars are read, check if it is the beg. of the correct message
|
---|
141 | for(int j=0; j<6; j++) { // if not return 0
|
---|
142 | if (buf[j] != cmd[j]) {
|
---|
143 | return 0;
|
---|
144 | }
|
---|
145 | }
|
---|
146 | }
|
---|
147 |
|
---|
148 | //check if recieved message is gpgga compatible
|
---|
149 | if ( byteGPS == '\n' ) { // when '\n' read (i.e. end of message ), check if variables are at the correct pos. then continue
|
---|
150 | if( sscanf( buf,"$GPGGA,%2d%2d%2d.%d,%d.%d,%c,%d.%d,%c,%d,%d,%d.%d,%d.%d,M,%d.%d,M,%7s\r\n",
|
---|
151 | &dump,&dump,&seconds,&dump,&dump,&dump,&cdump,&dump,&dump,&cdump,&dump,&dump,&dump,&dump,&dump,&dump,&dump,&dump,&hexdump ) != 19 )
|
---|
152 | {
|
---|
153 | return 0;
|
---|
154 | }
|
---|
155 |
|
---|
156 | blinkLed(0); // everything is ok -> message parsed, blink arduino led
|
---|
157 | decideVeto(); // as we have found the interesting part, do something
|
---|
158 | nemaMsg=buf; // save the found message to the nema string
|
---|
159 | // remove \r and \n from the string
|
---|
160 | nemaMsg = nemaMsg.substring(0,counter-1);
|
---|
161 |
|
---|
162 | return 0; // return 0 as we found the interesting part
|
---|
163 | }
|
---|
164 |
|
---|
165 | //continue with the next char if none of the actions before were needed
|
---|
166 | if(buf[0]=='$' || byteGPS=='$') {
|
---|
167 | counter++; // count one up, if it is the correct message ( the '$' at front )
|
---|
168 | }
|
---|
169 |
|
---|
170 | return 1; // continue (return 1) if we cannot yet decide to stop
|
---|
171 | }
|
---|
172 |
|
---|
173 | /**
|
---|
174 | * decideVeto() veto something if the state and time demand it
|
---|
175 | */
|
---|
176 | void decideVeto() {
|
---|
177 | if( state == 0 ) { // veto off
|
---|
178 | digitalWrite(vetoPin, HIGH); // put veto to not active ( HIGH )
|
---|
179 | digitalWrite(vetoLed, LOW); // put veto Led to not active
|
---|
180 | vetoLedOn = 0;
|
---|
181 | } else if( state == 2 ) { // veto on
|
---|
182 | digitalWrite(vetoPin, LOW); // put veto to active
|
---|
183 | digitalWrite(vetoLed, HIGH); // put veto Led to active
|
---|
184 | vetoLedOn = 1;
|
---|
185 | } else if( state == 1 ) { // veto the full minute
|
---|
186 | if( seconds == 59 ) { // if it is time to veto
|
---|
187 | digitalWrite(vetoPin, LOW); // put veto to active
|
---|
188 | digitalWrite(vetoLed, HIGH); // put veto Led to active
|
---|
189 | vetoLedOn = 1;
|
---|
190 | } else {
|
---|
191 | digitalWrite(vetoPin, HIGH); // put veto to not active
|
---|
192 | digitalWrite(vetoLed, LOW); // put veto Led to not active
|
---|
193 | vetoLedOn = 0;
|
---|
194 | }
|
---|
195 | }
|
---|
196 | }
|
---|
197 |
|
---|
198 | /**
|
---|
199 | * reset() the counters if needed
|
---|
200 | */
|
---|
201 | void reset() {
|
---|
202 | counter = 0;
|
---|
203 | }
|
---|
204 |
|
---|
205 | /**
|
---|
206 | * blinkLed() toggle the Led (on or off)
|
---|
207 | * type: int, 0 = arduino LED, 1 = gps LED, 2 = veto LED
|
---|
208 | */
|
---|
209 | void blinkLed( int type ) {
|
---|
210 | if(type == 0){
|
---|
211 | if(arduLedOn==0) {
|
---|
212 | digitalWrite(arduLed, HIGH);
|
---|
213 | arduLedOn=1;
|
---|
214 | } else {
|
---|
215 | digitalWrite(arduLed, LOW);
|
---|
216 | arduLedOn=0;
|
---|
217 | }
|
---|
218 | }/* else if (type == 1) {
|
---|
219 | if(gpsLedOn==0) {
|
---|
220 | digitalWrite(gpsLed, HIGH);
|
---|
221 | gpsLedOn=1;
|
---|
222 | } else {
|
---|
223 | digitalWrite(gpsLed, LOW);
|
---|
224 | gpsLedOn=0;
|
---|
225 | }
|
---|
226 | } else if (type == 2) {
|
---|
227 | if(vetoLedOn==0) {
|
---|
228 | digitalWrite(vetoLed, HIGH);
|
---|
229 | vetoLedOn=1;
|
---|
230 | } else {
|
---|
231 | digitalWrite(vetoLed, LOW);
|
---|
232 | vetoLedOn=0;
|
---|
233 | }
|
---|
234 | }*/
|
---|
235 | }
|
---|
236 |
|
---|
237 | /**
|
---|
238 | * read ethernet command
|
---|
239 | */
|
---|
240 | void readEthernetCommand(char c) {
|
---|
241 |
|
---|
242 | if(etherCmd.length() == MAX_CMD_LENGTH) {
|
---|
243 | etherCmd = "";
|
---|
244 | }
|
---|
245 |
|
---|
246 | etherCmd += c;
|
---|
247 |
|
---|
248 | if(c == '\n') {
|
---|
249 | if(etherCmd.length() > 2) {
|
---|
250 | // remove \r and \n from the string
|
---|
251 | etherCmd = etherCmd.substring(0,etherCmd.length() - 2);
|
---|
252 | parseCommand();
|
---|
253 | }
|
---|
254 | }
|
---|
255 | }
|
---|
256 |
|
---|
257 | /**
|
---|
258 | * parse ethernet command
|
---|
259 | */
|
---|
260 | void parseCommand() {
|
---|
261 |
|
---|
262 | if(etherCmd.equals("quit")) {
|
---|
263 | client.stop();
|
---|
264 | connected = false;
|
---|
265 | } else if(etherCmd.equals("help")) {
|
---|
266 | server.println("-- GPS Clock Arduino Help --");
|
---|
267 | server.println("---- Autor: Max Knoetig ----");
|
---|
268 | server.println("--- mknoetig@phys.ethz.ch --");
|
---|
269 | server.println("get_nema : get the last complete NEMA message");
|
---|
270 | server.println("get_status: get the status, veto_off, veto_60 or veto_on");
|
---|
271 | server.println("veto_off : switch off veto");
|
---|
272 | server.println("veto_on : switch on veto");
|
---|
273 | server.println("veto_60 : veto every pps to the full GPS UTC minute");
|
---|
274 | server.println("quit : close the connection");
|
---|
275 | } else if(etherCmd.equals("get_nema")) {
|
---|
276 | server.println(nemaMsg);
|
---|
277 | } else if(etherCmd.equals("get_status")) {
|
---|
278 | if(state==1) {
|
---|
279 | server.println("veto_60");
|
---|
280 | } else if(state==0) {
|
---|
281 | server.println("veto_off");
|
---|
282 | } else if(state==2) {
|
---|
283 | server.println("veto_on");
|
---|
284 | } else {
|
---|
285 | server.println("system state unknown");
|
---|
286 | }
|
---|
287 | } else if(etherCmd.equals("veto_off")) {
|
---|
288 | state=0;
|
---|
289 | server.println("veto now off");
|
---|
290 | } else if(etherCmd.equals("veto_60")) {
|
---|
291 | state=1;
|
---|
292 | server.println("veto 60 now on");
|
---|
293 | } else if(etherCmd.equals("veto_on")) {
|
---|
294 | state=2;
|
---|
295 | server.println("veto now on");
|
---|
296 | } else {
|
---|
297 | server.println("Invalid command, type help");
|
---|
298 | }
|
---|
299 | etherCmd = "";
|
---|
300 | }
|
---|
301 |
|
---|