/** * Firmware of the Arduino GPS reciever. * * This code was inspired by http://quaxio.com/arduino_gps/ , * http://playground.arduino.cc/Tutorials/GPS and * http://blog.bouni.de/blog/2012/06/25/a-arduino-telnet-server/ * * * Autor: Max Knötig */ #include #include #include #include #include #define MAX_CMD_LENGTH 15 //define led pins for display on the box int arduLed = 8; // on: arduino is on. blinking: serial message parsed int gpsLed = 7; // on: venus gps chip on. blinking: gps locked int vetoLed = 6; // on: veto active. off: veto not active ( active low btw. ) int arduLedOn = 0; int gpsLedOn = 0; int vetoLedOn = 0; //define inputs and outputs for the veto system int vetoPin = 3; // the veto output pin ( active low ) int navPin = 2; // the nav pin, from the venus gps. this is for steering the gpsLed //globals for storing the serial nema message int byteGPS=-1; // will become the read byte from the Venus GPS char cmd[7] = "$GPGGA"; // the NMEA message type we want to know int counter = 0; // counts how many bytes were received (max 300) char buf[300] = ""; // buffer to store the message String nemaMsg; // this buffer stores the last complete nema message //variables to save (or dump) nema message parts int seconds = 0; // this will become the veto trigger criterion ( seconds = 59 -> veto ) int dump = 0; // the other variables are used when sscanf the nema message char cdump = '0'; // for dumping reasons char hexdump[8]="0000000"; //the addresses for the shield (commented: ethz mode): byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xB9, 0x32 }; byte ip[] = { 10, 0, 100, 112 }; //byte ip[] = { 192, 33, 103, 241 }; //byte dns[] = { 129, 132, 98, 12 }; //byte gatew[] = { 192, 33, 96, 1 }; //byte smask[] = { 255, 255, 248, 0 }; //the globals for the ethernet communication String etherCmd; // store the ethernet command in here EthernetServer server = EthernetServer(23); EthernetClient client; boolean connected = false; //the state as decided by the user. 0 = veto_off, 1 = veto_60, 2 = veto_on int state = 1; /** * Setup arduino and gps */ void setup() { // define I/O pins pinMode(arduLed, OUTPUT); // Initialize Arduino LED pin pinMode(gpsLed, OUTPUT); // Initialize GPS LED pin pinMode(vetoLed, OUTPUT); // Initialize Veto LED pin pinMode(vetoPin, OUTPUT); // Initialize Veto pin pinMode(navPin, INPUT); // Initialize Nav pin // set their startup modes digitalWrite(vetoPin, HIGH); // put veto to high ( no veto ) in startup mode digitalWrite(arduLed, HIGH); // put the arduino led high when starting arduLedOn = 1; //begin the ethernet and serial connections Ethernet.begin(mac, ip); //, dns, gatew, smask); // this is to begin (ethz) ethernet Serial.begin(115200); // the gps serial connection server.begin(); reset(); // reset the counters (just in case) } /** * the loop which processes ethernet and serial connections */ void loop() { //serial part byteGPS=Serial.read(); // Read a byte of the serial port if (byteGPS == -1) { // See if the port is empty yet delay(1); } else { if (!handle_byte(byteGPS)) { reset(); Serial.flush(); } } //ethernet part client = server.available(); // check if the server is available if (client == true) { // if there is a new client if (!connected) { client.flush(); connected = true; } while (client.available() > 0) { // while there is incoming data read it readEthernetCommand(client.read()); } } if( digitalRead(navPin) == 0){ // test if the gps blinkes, if yes, blink the gps led as well digitalWrite(gpsLed, HIGH); gpsLedOn=1; } else { digitalWrite(gpsLed, LOW); gpsLedOn=0; } } /** * handle the byte read from the GPS module */ int handle_byte(int byteGPS) { if (counter == 300) { // if the buffer is full return 0 return 0; } //read the first char buf[counter] = byteGPS; if (counter == 6) { // if 6 chars are read, check if it is the beg. of the correct message for(int j=0; j<6; j++) { // if not return 0 if (buf[j] != cmd[j]) { return 0; } } } //check if recieved message is gpgga compatible if ( byteGPS == '\n' ) { // when '\n' read (i.e. end of message ), check if variables are at the correct pos. then continue 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", &dump,&dump,&seconds,&dump,&dump,&dump,&cdump,&dump,&dump,&cdump,&dump,&dump,&dump,&dump,&dump,&dump,&dump,&dump,&hexdump ) != 19 ) { return 0; } blinkLed(0); // everything is ok -> message parsed, blink arduino led decideVeto(); // as we have found the interesting part, do something nemaMsg=buf; // save the found message to the nema string // remove \r and \n from the string nemaMsg = nemaMsg.substring(0,counter-1); return 0; // return 0 as we found the interesting part } //continue with the next char if none of the actions before were needed if(buf[0]=='$' || byteGPS=='$') { counter++; // count one up, if it is the correct message ( the '$' at front ) } return 1; // continue (return 1) if we cannot yet decide to stop } /** * decideVeto() veto something if the state and time demand it */ void decideVeto() { if( state == 0 ) { // veto off digitalWrite(vetoPin, HIGH); // put veto to not active ( HIGH ) digitalWrite(vetoLed, LOW); // put veto Led to not active vetoLedOn = 0; } else if( state == 2 ) { // veto on digitalWrite(vetoPin, LOW); // put veto to active digitalWrite(vetoLed, HIGH); // put veto Led to active vetoLedOn = 1; } else if( state == 1 ) { // veto the full minute if( seconds == 59 ) { // if it is time to veto digitalWrite(vetoPin, LOW); // put veto to active digitalWrite(vetoLed, HIGH); // put veto Led to active vetoLedOn = 1; } else { digitalWrite(vetoPin, HIGH); // put veto to not active digitalWrite(vetoLed, LOW); // put veto Led to not active vetoLedOn = 0; } } } /** * reset() the counters if needed */ void reset() { counter = 0; } /** * blinkLed() toggle the Led (on or off) * type: int, 0 = arduino LED, 1 = gps LED, 2 = veto LED */ void blinkLed( int type ) { if(type == 0){ if(arduLedOn==0) { digitalWrite(arduLed, HIGH); arduLedOn=1; } else { digitalWrite(arduLed, LOW); arduLedOn=0; } }/* else if (type == 1) { if(gpsLedOn==0) { digitalWrite(gpsLed, HIGH); gpsLedOn=1; } else { digitalWrite(gpsLed, LOW); gpsLedOn=0; } } else if (type == 2) { if(vetoLedOn==0) { digitalWrite(vetoLed, HIGH); vetoLedOn=1; } else { digitalWrite(vetoLed, LOW); vetoLedOn=0; } }*/ } /** * read ethernet command */ void readEthernetCommand(char c) { if(etherCmd.length() == MAX_CMD_LENGTH) { etherCmd = ""; } etherCmd += c; if(c == '\n') { if(etherCmd.length() > 2) { // remove \r and \n from the string etherCmd = etherCmd.substring(0,etherCmd.length() - 2); parseCommand(); } } } /** * parse ethernet command */ void parseCommand() { if(etherCmd.equals("quit")) { client.stop(); connected = false; } else if(etherCmd.equals("help")) { server.println("-- GPS Clock Arduino Help --"); server.println("---- Autor: Max Knoetig ----"); server.println("--- mknoetig@phys.ethz.ch --"); server.println("get_nema : get the last complete NEMA message"); server.println("get_status: get the status, veto_off, veto_60 or veto_on"); server.println("veto_off : switch off veto"); server.println("veto_on : switch on veto"); server.println("veto_60 : veto every pps to the full GPS UTC minute"); server.println("quit : close the connection"); } else if(etherCmd.equals("get_nema")) { server.println(nemaMsg); } else if(etherCmd.equals("get_status")) { if(state==1) { server.println("veto_60"); } else if(state==0) { server.println("veto_off"); } else if(state==2) { server.println("veto_on"); } else { server.println("system state unknown"); } } else if(etherCmd.equals("veto_off")) { state=0; server.println("veto now off"); } else if(etherCmd.equals("veto_60")) { state=1; server.println("veto 60 now on"); } else if(etherCmd.equals("veto_on")) { state=2; server.println("veto now on"); } else { server.println("Invalid command, type help"); } etherCmd = ""; }