| 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 |
|
|---|