[Flightcomputer] HoHoHo 1

hohoho1flightcompheader

This was the flightcomputer (Arduino C++ based) used for This Project.

It gets serial data from TWO GPS devices, the atmel processor of the arduino parses it to a NTX2 443mhz radio output, and at the right time sends some text messages on touchdown. The nice thing is that it uses the info from two GPS devices, which means you need two serial inputs. In this case i used a Libelium Vinotech sirfIII GPS and a Falcom FSA03 (which sucks). But they performed equally well. Their localization is subsequently parsed through the radio. Oh yeah, it also logs ALL the info from the GPS devices to a SD card!

Parts List

  • Arduino or equivalent
  • Radio transmitter
  • Radio receiver
  • Sony Ericsson with serial interface
  • GPS
  • another GPS
  • Temp Sensor/Hum. Sensor
  • SD card

Code

  1.  
  2. // Project Hollands Hoogte © July 2010
  3. // By Tim Zaman
  4. // Help from Terry Baume (& ntx2 by jharrison)
  5.  
  6. // Digital Pins
  7. #define GPS_PIN_1               9       // GPS serial pin RX
  8. #define GPS_PIN_2               8       // GPS serial pin TX
  9. #define RTTY_PIN_1 		5	// RTTY space pin
  10. #define RTTY_PIN_2 		6	// RTTY mark pin
  11. #define RTTY_LED                30      // RTTY busy led
  12. #define GPS_LED 		22	// Which LED to light when we have a GPS lock?
  13. #define SDPWR                   48      // SD power pin
  14. #define CHECKPIN                13      // Pin that lights up when things are checked
  15.  
  16. // Analog pins
  17. #define HUMINTPIN               13      //Humidity
  18. #define TEMPINTPIN              14      //Temp inside
  19. #define TEMPEXTPIN              15      //Temp outside
  20.  
  21. // T68i
  22. #define num_to_char(number)   ((number) < 10 ?
  23.                                                ('0' + (number)) :
  24.                                                (('A' - 10) + (number)) )
  25. #define first_four(byte)       (0x0F & (byte))
  26. #define last_four(byte)      ((0xF0 & (byte)) >> 4)
  27. #define hexdump_a(byte)  num_to_char( last_four(byte))
  28. #define hexdump_b(byte)  num_to_char(first_four(byte))
  29.  
  30.  
  31. // Misc
  32. #define RTTY_ASCII      7       // ASCII set for RTTY (7/8bit)
  33. #define GPSRATE         9600    // GPS baud rate
  34. #define BUFFERSIZE      90      // How many bytes of input to buffer from the GPS?
  35. #define ENDLN           "rn"  // SD
  36.  
  37. #include <util/crc16.h>
  38. #include <fat16.h>
  39. #include <flash.h>
  40. #include <streaming.h>
  41. #include <softwareSerial.h>
  42.  
  43.  
  44. // Initialize flight variables
  45. int numSats = 0;
  46. int fixType = 0;
  47. int time[] = {
  48.   0, 0, 0};
  49. double latitude = 0.0;
  50. double longitude = 0.0;
  51. long altitude = 0;
  52. long maxAlt = 0;
  53. int speed = 0;
  54. int txCount = 0;
  55. int intTemp = 0;
  56. int extTemp = 0;
  57. int intHum = 0;
  58. int bitRate = 50;
  59. int descent = 0;
  60.  
  61. int FalcomCheck = 0;
  62. int LogCheck =0;
  63. int GpsModule = 1;          // 1= Falcom,    2=Tyco
  64. char* GpsModLock = "X";      // F=Falcom, T=Tyco
  65.  
  66. unsigned long GpsOffTime = 0;   // Tijd dat GPS uit gaat
  67. unsigned long SmsStart = 0;     // SMS-time
  68. unsigned long GpsAltTime = 1800000;    // 1.800.000ms=1.800s=30min
  69. int ExecOnce=0;             // execut0r
  70. int ExecOnceGPS=0;          // voor 24km limit ding
  71. int ExecOncePin=0;          // zodat ie de pin niet steeds aanzet
  72. char buffer[BUFFERSIZE];
  73. byte nxtln[] = ENDLN;                       //SD ENDLNn
  74. unsigned long NXTlength = sizeof(ENDLN)-1;  //SD ENDLNn length
  75.  
  76. SdCard card;
  77. Fat16 Logger;
  78. SoftwareSerial mySerial = SoftwareSerial(GPS_PIN_1, GPS_PIN_2);  //(rx,tx)
  79.  
  80.  
  81. void setup() {
  82.  
  83.   // Start up serial ports
  84.   Serial1.begin(38400);
  85.   Serial3.begin(9600);
  86.   Serial.begin(9600);
  87.   Serial.println("Serial started");
  88.   mySerial.begin(4800);
  89.  
  90.   // SD kaartje poweren met pin..
  91.   pinMode(SDPWR, OUTPUT);
  92.   digitalWrite(SDPWR, HIGH);
  93.  
  94.   // LED's
  95.   pinMode(CHECKPIN, OUTPUT);
  96.   pinMode(RTTY_LED, OUTPUT);
  97.   pinMode(GPS_LED, OUTPUT);
  98.   delay(1000);
  99.   mySerial.println("$PSTMNMEACONFIG,0,4800,1,1");
  100.   mySerial.println("$PSTMINITGPS,5200.000,N,00421.000,E,0197,22,10,2007,11,40,00");
  101.   mySerial.println("$PSRF103,02,00,00,01*26");
  102.  
  103.   // Setup for RTTY
  104.   pinMode(RTTY_PIN_1, OUTPUT);
  105.   pinMode(RTTY_PIN_2, OUTPUT);
  106.  
  107.   //Extra GPS
  108.   pinMode(GPS_PIN_1, INPUT);
  109.   pinMode(GPS_PIN_2, OUTPUT);
  110.   pinMode(7, OUTPUT);
  111.   digitalWrite(7, HIGH);
  112.  
  113.   // Ensure we can access the SD card
  114.   if (!card.init()) Serial << F("* SD card init. failed!") << ENDLN;
  115.   if (!Fat16::init(card)) Serial << F("* FAT16 init. failed!") << ENDLN;
  116.  
  117.   // Check for an available filename
  118.   char fileName[12];
  119.   Serial << F("* Trying to open logging file...") << ENDLN;
  120.   for (int i = 0; i < 1000; i++) {
  121.     sprintf(fileName, "LOG%03d.TXT", i);
  122.     if (Logger.open(fileName, O_CREAT | O_EXCL | O_WRITE)) break;
  123.   }
  124.  
  125.   // Ensure we opened the file without error
  126.   if (!Logger.isOpen()) {
  127.     Serial << F("* Failed to open logging file!") << ENDLN;
  128.     LogCheck = 0;
  129.   }
  130.   else {
  131.     LogCheck = 1;
  132.     Logger.writeError = false;
  133.     Serial << F("* Logging to ") << fileName << ENDLN;
  134.     Logger << F("Project HoHoHo booted!") << ENDLN;
  135.     if (Logger.writeError || !Logger.sync()){
  136.       Serial << F("* Error writing to SD card!") << ENDLN;
  137.       LogCheck =0;
  138.     }
  139.   }
  140.   Serial << ENDLN;
  141.  
  142.  
  143.  
  144.  
  145.  
  146.   delay(2000); // Give the GPS time to come boot
  147.  
  148.   // Set the baud rate to 9600, 38.4k is too fast
  149.   Serial.print("Setting uBlox port mode: ");
  150.   uint8_t setPort[] = {
  151.     0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x95            };
  152.   sendUBX(setPort, sizeof(setPort)/sizeof(uint8_t));
  153.  
  154.   // Switch baud rates
  155.   Serial.println("Switching to 9600b GPS serial");
  156.   Serial1.begin(9600);
  157.   delay(1000);
  158.  
  159.   // Set the navigation mode (Airborne, 1G)
  160.   Serial.print("Setting uBlox nav mode: ");
  161.   uint8_t setNav[] = {
  162.     0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xDC            };
  163.   sendUBX(setNav, sizeof(setNav)/sizeof(uint8_t));
  164.   getUBX_ACK(setNav);
  165.  
  166.   // Switch off GLL
  167.   Serial.print("Switching off NMEA GLL: ");
  168.   uint8_t setGLL[] = {
  169.     0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x2B             };
  170.   sendUBX(setGLL, sizeof(setGLL)/sizeof(uint8_t));
  171.   getUBX_ACK(setGLL);
  172.  
  173.   // Switch off GSA
  174.   Serial.print("Switching off NMEA GSA: ");
  175.   uint8_t setGSA[] = {
  176.     0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x32             };
  177.   sendUBX(setGSA, sizeof(setGSA)/sizeof(uint8_t));
  178.   getUBX_ACK(setGSA);
  179.  
  180.   // Switch off GSV
  181.   Serial.print("Switching off NMEA GSV: ");
  182.   uint8_t setGSV[] = {
  183.     0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x39             };
  184.   sendUBX(setGSV, sizeof(setGSV)/sizeof(uint8_t));
  185.   getUBX_ACK(setGSV);
  186.  
  187.   // Switch off RMC
  188.   Serial.print("Switching off NMEA RMC: ");
  189.   uint8_t setRMC[] = {
  190.     0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x40             };
  191.   sendUBX(setRMC, sizeof(setRMC)/sizeof(uint8_t));
  192.   getUBX_ACK(setRMC);
  193.  
  194. if (FalcomCheck == 5){
  195.   Logger << F("OK uBlox Falcom checks") << ENDLN;
  196.   if(LogCheck==1){
  197.     digitalWrite(CHECKPIN, HIGH);
  198.   }
  199.   send_sms("Sms werkt, Falcom checks OK. Over en uit.");
  200. }
  201. else{
  202.   Logger << F("FAILED uBlox Falcom checks") << ENDLN;
  203. }
  204. }
  205.  
  206.  
  207. void loop() {
  208.  
  209.   // Flush() de zooi ivm delay's
  210.   Serial1.flush();
  211.  
  212.   // Get a GGA string from the GPS,
  213.   // check if it's a valid fix, and extract the data
  214.   getNMEA("$GPGGA");
  215.   Logger << buffer << ENDLN;
  216.   numSats = getSats();
  217.   fixType = getFixType();
  218.  
  219.   // Make sure we have a valid fix
  220.   if (fixType != 0) {
  221.     if (GpsModule == 1){    // 1 = Falcom
  222.       GpsModLock = "F";     //Falcom heeft lock
  223.     }
  224.     else{                   // 2 = Tyco (Libelium)
  225.       GpsModLock = "T" ;    //Tyco heeft lock
  226.     }
  227.     getTime(time);
  228.     latitude = getLat();
  229.     longitude = getLong();
  230.     altitude = getAlt();
  231.     digitalWrite(GPS_LED, HIGH);
  232.  
  233.     // Keep track of the maximum altitude
  234.     if (altitude > maxAlt) {
  235.       maxAlt = altitude;
  236.     }
  237.  
  238.     // Check to see if we've fallen 1000m, if so switch to descent mode
  239.     if (altitude < (maxAlt - 1000)) {
  240.       descent = 1;
  241.     }
  242.    }
  243.   else {
  244.     digitalWrite(GPS_LED, LOW);
  245.   }
  246.  
  247.   // Get the speed from a VTG message
  248.   //getNMEA("$GPVTG");
  249.   //Logger << buffer << ENDLN;                     ?
  250.   //speed = getSpeed();
  251.  
  252.   // Convert lat & long into strings
  253.   char latString[12];
  254.   char longString[12];
  255.   doubleToString(latitude, 4, latString);
  256.   doubleToString(longitude, 4, longString);
  257.  
  258.   intTemp= getTemp(TEMPINTPIN);  //inside temp
  259.   extTemp= getTemp(TEMPEXTPIN);  //outside temp
  260.   intHum= getHum(HUMINTPIN);     //humidity
  261.  
  262.   Logger << ("Sensors;") << intTemp << F(";") << extTemp << F(";") << intHum << ENDLN;
  263.  
  264.   if (GpsModule ==1){ // = Falcom
  265.   sprintf(buffer, "$$TBL,%d,%02d:%02d:%02d,%s,%s,%ld,%s", txCount, time[0], time[1], time[2], latString, longString, altitude, GpsModLock);
  266.   GpsModule = 2;
  267.   }
  268.   else{               // = Tyco
  269.   sprintf(buffer, "$$TBB,%d,%02d:%02d:%02d,%s,%s,%ld,%s", txCount, time[0], time[1], time[2], latString, longString, altitude, GpsModLock);
  270.   GpsModule = 1;
  271.   txCount++;
  272.   }
  273.  
  274.   if(txCount == 10){
  275.     send_sms(buffer);
  276.   }
  277.  
  278.  
  279.   // Transmit and log to SD card
  280.   TxString(buffer);
  281.  
  282.  
  283.   // Force an update on the SD card
  284.   Logger.sync();
  285.  
  286.   // Delay a moment before restarting loop
  287.   delay(100);
  288.  
  289.   // GPS 1 uitval boven 23.5km
  290.   if (altitude > 23500){
  291.     if (ExecOnceGPS == 0){
  292.       ExecOnceGPS = 1;
  293.       digitalWrite(7, LOW); // GPS voeding uit
  294.       GpsOffTime = millis();
  295.       TxString("lim reached lim reached lim reached lim reached lim reached");
  296.     }
  297.   }
  298.  
  299.  
  300.   // Als hij boven de hoogte uit is gekomen..
  301.   if (ExecOnceGPS == 1){         // Zorg dat hij gedefineerd is
  302.     if ((millis() - GpsOffTime) > GpsAltTime){  //na 23.5km 30min wachten
  303.       if (ExecOncePin == 0){  //zodat die de pin niet steeds aanzet
  304.         digitalWrite(7, HIGH); // GPS weer aan
  305.         ExecOncePin = 1;
  306.         TxString("gps on gps on gps on gps on gps on gps on");
  307.       }
  308.     }
  309.     if(altitude < 23000){ // als hij dan toch is gedropt door een lagere meting
  310.       if (ExecOncePin == 0){  //zodat die de pin niet steeds aanzet
  311.         digitalWrite(7, HIGH); // GPS weer aan
  312.         ExecOncePin = 1;
  313.         TxString("gps on gps on gps on gps on gps on gps on");
  314.       }
  315.     }
  316.   }
  317.  
  318.  
  319.  
  320.   // SMS <1000m mode
  321.   if (descent == 1){
  322.     if (altitude < 900){
  323.  
  324.       if (ExecOnce == 0){
  325.         SmsStart = millis();
  326.         ExecOnce = 1;
  327.         send_sms(buffer);
  328.         Logger << F("SMS verstuurd...") << ENDLN;
  329.         delay(50);
  330.       }
  331.       if (millis() - SmsStart > 26000){
  332.         ExecOnce =0;
  333.       }
  334.  
  335.     }
  336.   }
  337.  
  338.  
  339. } //end
  340.  
  341.  
  342.  
  343.  
  344.  
  345.  
  346.  
  347. // ----------  GPS MEUK -------------
  348.  
  349. // Send a byte array of UBX protocol to the GPS
  350. void sendUBX(uint8_t *MSG, uint8_t len) {
  351.   for(int i=0; i<len; i++) {
  352.     Serial1.print(MSG[i], BYTE);
  353.     Serial.print(MSG[i], HEX);
  354.   }
  355.   Serial.println();
  356. }
  357.  
  358. // Calculate expected UBX ACK packet and parse UBX response from GPS
  359. boolean getUBX_ACK(uint8_t *MSG) {
  360.   uint8_t b;
  361.   uint8_t ackByteID = 0;
  362.   uint8_t ackPacket[10];
  363.   int startTime = millis();
  364.   Serial.print(" * Reading ACK response: ");
  365.  
  366.   // Construct the expected ACK packet
  367.   ackPacket[0] = 0xB5;	// header
  368.   ackPacket[1] = 0x62;	// header
  369.   ackPacket[2] = 0x05;	// class
  370.   ackPacket[3] = 0x01;	// id
  371.   ackPacket[4] = 0x02;	// length
  372.   ackPacket[5] = 0x00;
  373.   ackPacket[6] = MSG[2];	// ACK class
  374.   ackPacket[7] = MSG[3];	// ACK id
  375.   ackPacket[8] = 0;		// CK_A
  376.   ackPacket[9] = 0;		// CK_B
  377.  
  378.   // Calculate the checksums
  379.   for (uint8_t i=2; i<8; i++) {
  380.     ackPacket[8] = ackPacket[8] + ackPacket[i];
  381.     ackPacket[9] = ackPacket[9] + ackPacket[8];
  382.   }
  383.  
  384.   while (1) {
  385.  
  386.     // Test for success
  387.     if (ackByteID > 9) {
  388.       // All packets in order!
  389.       Serial.println(" (SUCCESS!)");
  390.       FalcomCheck=FalcomCheck+1;
  391.       return true;
  392.     }
  393.  
  394.     // Timeout if no valid response in 3 seconds
  395.     if (millis() - startTime > 3000) {
  396.       Serial.println(" (FAILED!)");
  397.       return false;
  398.     }
  399.  
  400.     // Make sure data is available to read
  401.     if (Serial1.available()) {
  402.       b = Serial1.read();
  403.  
  404.       // Check that bytes arrive in sequence as per expected ACK packet
  405.       if (b == ackPacket[ackByteID]) {
  406.         ackByteID++;
  407.         Serial.print(b, HEX);
  408.       }
  409.       else {
  410.         ackByteID = 0;	// Reset and look again, invalid order
  411.       }
  412.  
  413.     }
  414.   }
  415. }
  416.  
  417.  
  418.  
  419. // ------- GPS Parsing ----------
  420.  
  421. // Reads a line from the GPS NMEA serial output
  422. // Give up after trying to read 1000 bytes (~2 seconds)
  423. int readLine(void) {
  424.   char c;
  425.   byte bufferIndex = 0;
  426.   boolean startLine = 0;
  427.   byte retries = 0;
  428.   while (retries < 20) {
  429.     //if (mySerial.available() > 0) {         //Serial1=falcom, mySerial= andere
  430.       if (GpsModule==1){  //Falcom
  431.       c = Serial1.read();
  432.       }
  433.       else{               //Tyco
  434.       c= mySerial.read();
  435.       }
  436.  
  437.       if (c == -1) {
  438.         delay(2);
  439.         continue;
  440.       }
  441.       if (c == 'n') continue;
  442.       if (c == '$') startLine = 1;
  443.       if ((bufferIndex == BUFFERSIZE-1) || (c == 'r')) {
  444.         if (startLine) {
  445.           buffer[bufferIndex] = 0;
  446.           return 1;
  447.         }
  448.       }
  449.       if (startLine) buffer[bufferIndex++] = c;
  450.     //}
  451.     else {
  452.       retries++;
  453.       delay(50);
  454.     }
  455.   }
  456.   return 0;
  457. }
  458.  
  459. // Returns a specific field from the buffer
  460. void getField(int getId, char *field, int maxLen) {
  461.   byte bufferIndex = 0;
  462.   byte fieldId = 0;
  463.   byte i = 0;
  464.   while (bufferIndex < sizeof(buffer)) {
  465.     if (fieldId == getId) {
  466.       // End of string, or string overflow
  467.       if (buffer[bufferIndex] == ',' || i > (maxLen - 2)) {
  468.         field[i] = 0;	// Null terminate
  469.         return;
  470.       }
  471.       // Buffer chars to field
  472.       field[i++] = buffer[bufferIndex++];
  473.     }
  474.     else {
  475.       // Advance field on comma
  476.       if (buffer[bufferIndex] == ',') {
  477.         bufferIndex++;						// Advance in buffer
  478.         fieldId++;							// Increase field position counter
  479.       }
  480.       else {
  481.         bufferIndex++;						// Advance in buffer
  482.       }
  483.     }
  484.   }
  485.   // Null terminate incase we didn't already..
  486.   field[i] = 0;
  487. }
  488.  
  489. // Polls for an NMEA sentence of type requested
  490. // Validates checksum, silently retries on failed checksums
  491. int getNMEA(char *getType) {
  492.   char type[7];
  493.   byte retries = 0;
  494.   while (retries < 2) {
  495.     if (readLine() && validateChecksum()) {
  496.       ;
  497.       getField(0, type, sizeof(type));
  498.       if (strcmp(type, getType) == 0) {
  499.         Serial.println(buffer);
  500.         return 1;
  501.       }
  502.     }
  503.     else {
  504.       retries++;
  505.     }
  506.   }
  507.   Serial.println("Failed to read GPS");
  508.   Logger << F("Failed to read GPS") << ENDLN;
  509.   return 0;
  510. }
  511.  
  512. // Validates the checksum on an NMEA string
  513. // Returns 1 on valid checksum, 0 otherwise
  514. int validateChecksum(void) {
  515.   char gotSum[2];
  516.   gotSum[0] = buffer[strlen(buffer) - 2];
  517.   gotSum[1] = buffer[strlen(buffer) - 1];
  518.   // Check that the checksums match up
  519.   if ((16 * atoh(gotSum[0])) + atoh(gotSum[1]) == getCheckSum(buffer)) return 1;
  520.   else return 0;
  521. }
  522.  
  523. // Calculates the checksum for a given string
  524. // returns as integer
  525. int getCheckSum(char *string) {
  526.   int i;
  527.   int XOR;
  528.   int c;
  529.   // Calculate checksum ignoring any $'s in the string
  530.   for (XOR = 0, i = 0; i < strlen(string); i++) {
  531.     c = (unsigned char)string[i];
  532.     if (c == '*') break;
  533.     if (c != '$') XOR ^= c;
  534.   }
  535.   return XOR;
  536. }
  537.  
  538. // Returns the groundspeed in km/h
  539. int getSpeed(void) {
  540.   char field[10];
  541.   getField(7, field, sizeof(field));
  542.   int speed = atoi(field);
  543.   return speed;
  544. }
  545.  
  546. // Return the fix type from a GGA string
  547. int getFixType(void) {
  548.   char field[5];
  549.   getField(6, field, sizeof(field));
  550.   int fixType = atoi(field);
  551.   return fixType;
  552. }
  553.  
  554. // Return the altitude in meters from a GGA string
  555. long getAlt(void) {
  556.   char field[10];
  557.   getField(9, field, sizeof(field));
  558.   long altitude = atol(field);
  559.   return altitude;
  560. }
  561.  
  562. // Returns the number of satellites being tracked from a GGA string
  563. int getSats(void) {
  564.   char field[3];
  565.   getField(7, field, sizeof(field));
  566.   int numSats = atoi(field);
  567.   return numSats;
  568. }
  569.  
  570. // Read the latitude in decimal format from a GGA string
  571. double getLat(void) {
  572.   char field[12];
  573.   getField(2, field, sizeof(field));			// read the latitude
  574.   double latitude = atof(field);					// convert to a double (precise)
  575.   int deg = (int) latitude / 100;				// extract the number of degrees
  576.   double min = latitude - (100 * deg);			// work out the number of minutes
  577.   latitude = deg + (double) min/60.0;			// convert to decimal format
  578.   getField(3, field, sizeof(field));			// get the hemisphere (N/S)
  579.   if (strcmp(field, "S") == 0) latitude *= -1;	// sign the decimal latitude correctly
  580.   return latitude;
  581. }
  582.  
  583. // Read the longitude in decimal format from a GGA string
  584. double getLong(void) {
  585.   char field[12];
  586.   getField(4, field, sizeof(field));			// read the longitude
  587.   double longitude = atof(field);					// convert to a double
  588.   int deg = (int) longitude / 100;				// extract the number of degrees
  589.   double min = longitude - (100 * deg);			// work out the number of minutes
  590.   longitude = deg + (double) min/60.00;			// convert to decimal format
  591.   getField(5, field, sizeof(field));			// get the E/W status
  592.   if (strcmp(field, "W") == 0) longitude *= -1; // sign decimal latitude correctly
  593.   return longitude;
  594. }
  595.  
  596. // Converts UTC time to the correct timezone
  597. void convertTime(int *time) {
  598.   // How many hours off GMT are we?
  599.   float offset = 2;
  600.   long sectime = ((long)(time[0]) * 3600) + (time[1] * 60) + time[2];
  601.   sectime += (offset * 3600.0);
  602.   // Did we wrap around?
  603.   if (sectime < 0) sectime += 86400;
  604.   if (sectime > 86400) sectime -= 86400;
  605.   // Convert back to time
  606.   time[0] = (int)(sectime / 3600);
  607.   time[1] = (int)((sectime % 3600) / 60);
  608.   time[2] = (int)((sectime % 3600) % 60);
  609. }
  610.  
  611. // Parses a time field from a GGA string
  612. void parseTime(char *field, int *time) {
  613.   char tmp[3];
  614.   tmp[2] = 0; // Init tmp and null terminate
  615.   tmp[0] = field[0];
  616.   tmp[1] = field[1];
  617.   time[0] = atoi(tmp); // Hours
  618.   tmp[0] = field[2];
  619.   tmp[1] = field[3];
  620.   time[1] = atoi(tmp); // Minutes
  621.   tmp[0] = field[4];
  622.   tmp[1] = field[5];
  623.   time[2] = atoi(tmp); // Seconds
  624. }
  625.  
  626. // Gets the hours, minutes and seconds from a GGA string
  627. void getTime(int *time) {
  628.   char field[12];
  629.   getField(1, field, sizeof(field));
  630.   parseTime(field, time);
  631.   convertTime(time);
  632. }
  633.  
  634. // ------ RTTY ----------
  635.  
  636. // Transmit a string, log it to SD & produce debug output
  637. void TxString(char *string) {
  638.   digitalWrite(RTTY_LED, HIGH);
  639.  
  640.   // Checksum
  641.   char txSum[4];
  642.   int checkSum = getCheckSum(string);
  643.   sprintf(txSum, "%02X", checkSum);
  644.  
  645.   Serial << F("RTTY: ") << string << "*" << txSum << ENDLN;
  646.   Logger << string << F("*") << txSum << ENDLN;
  647.   rtty_txstring(string);
  648.   rtty_txstring("*");
  649.   rtty_txstring(txSum);
  650.   rtty_txstring("rn");
  651.   digitalWrite(RTTY_LED, LOW);
  652. }
  653.  
  654. // Transmit a string, one char at a time
  655. void rtty_txstring (char *string) {
  656.   for (int i = 0; i < strlen(string); i++) {
  657.     rtty_txbyte(string[i]);
  658.   }
  659. }
  660.  
  661. // Transmit a byte, bit by bit, LSB first
  662. // ASCII_BIT can be either 7bit or 8bit
  663. void rtty_txbyte (char c) {
  664.   int i;
  665.   // Start bit
  666.   rtty_txbit (0);
  667.   // Send bits for for char LSB first
  668.   for (i=0;i<rtty_ASCII;i++) {
  669.     if (c & 1) rtty_txbit(1);
  670.     else rtty_txbit(0);
  671.     c = c >> 1;
  672.   }
  673.   // Stop bit
  674.   rtty_txbit (1);
  675. }
  676.  
  677. // Transmit a bit as a mark or space
  678. void rtty_txbit (int bit) {
  679.   if (bit) {
  680.     // High - mark
  681.     digitalWrite(RTTY_PIN_1, HIGH);
  682.     digitalWrite(RTTY_PIN_2, LOW);
  683.   }
  684.   else {
  685.     // Low - space
  686.     digitalWrite(RTTY_PIN_2, HIGH);
  687.     digitalWrite(RTTY_PIN_1, LOW);
  688.   }
  689.   // Delay appropriately - tuned to 50 baud.
  690.   delay(19);
  691.   delayMicroseconds(250);
  692. }
  693.  
  694. // ------ MISC ----------
  695.  
  696. // Returns a string with a textual representation of a float
  697. void doubleToString(double val, int precision, char *string){
  698.  
  699.   // Print the int part
  700.   sprintf(string, "%d", (int)(val));
  701.   if(precision > 0) {
  702.     // Print the decimal point
  703.     strcat(string, ".");
  704.     unsigned long frac;
  705.     unsigned long mult = 1;
  706.     int padding = precision -1;
  707.     while (precision--) {
  708.       mult *=10;
  709.     }
  710.     if (val >= 0)
  711.       frac = (val - (int)(val)) * mult;
  712.     else
  713.       frac = ((int)(val)- val ) * mult;
  714.     unsigned long frac1 = frac;
  715.     while (frac1 /= 10) {
  716.       padding--;
  717.     }
  718.     while (padding--) {
  719.       strcat(string, "0");
  720.     }
  721.  
  722.     // Convert and print the fraction part
  723.     sprintf(string+strlen(string), "%d", (int)(frac));
  724.   }
  725. }
  726.  
  727.  
  728. // Converts a HEX string to an int
  729. int atoh(char c) {
  730.   if (c >= 'A' && c <= 'F')
  731.     return c - 55;
  732.   else if (c >= 'a' && c <= 'f')
  733.     return c - 87;
  734.   else
  735.     return c - 48;
  736. }
  737.  
  738.  
  739.  
  740. // ------ T68i GPRS ----------
  741.  
  742. void hexdump_byte(unsigned char byte)
  743. {
  744.   Serial3.print(hexdump_a(byte), BYTE);
  745.   Serial3.print(hexdump_b(byte), BYTE);
  746. }
  747.  
  748. void send_sms(char *data)
  749. {
  750.   size_t data_length, x;
  751.   char c, l;
  752.   long i;
  753.   long n;
  754.  
  755.   data_length = strlen(data);
  756.   i = data_length * 7;
  757.  
  758.   /* Round i up to a multiple of 8 */
  759.   if (i & 0x07) i = (i & ~0x07) + 0x08;
  760.  
  761.   /* Calculate the number of message octets */
  762.   i = i / 8;
  763.  
  764.   Serial3.println("AT+CMGF=0");
  765.   delay(1500);
  766.   Serial3.print("AT+CMGS=");
  767.   delay(1500);
  768.   Serial3.println(i + 14);
  769.   delay(1500);
  770.   Serial3.print("0011000B911356537837F80000AA");
  771.   hexdump_byte(data_length & 0xFF);
  772.  
  773.   /* from sms_example_v2.c ALIEN Project Daniel Richman */
  774.   l = 0;
  775.   n = 0;
  776.  
  777.   for (x = 0; x < data_length; x++)
  778.   {
  779.     if (data[x] == '$')  data[x] = 0x02;
  780.  
  781.     n |= (data[x] & 0x7F) << l;
  782.     l += 7;
  783.  
  784.     if (l >= 8)
  785.     {
  786.       hexdump_byte(n & 0xFF);
  787.       l -= 8;
  788.       n >>= 8;
  789.     }
  790.   }
  791.  
  792.   if (l != 0)
  793.   {
  794.     hexdump_byte(n & 0xFF);
  795.   }
  796.  
  797.   Serial3.println(0x1A, BYTE);
  798. }
  799.  
  800.  
  801. // Sensoren
  802.  
  803. int getTemp(int pin){ //getTemp(<pinnr>)
  804. return (((analogRead(pin) * .004882814)-2.89)*100);  //gecalibreerd op 3.11V=22C
  805. }
  806.  
  807. int getHum(int pin){ //getHum(<pinnr>)
  808. return (((analogRead(pin) * .004882814)-0.9)*33);  //gecalibreerd op start .9V, 33% per volt.
  809. }

Tim Zaman

Engineer from The Netherlands (1988). Living in Delft. MSc degree in Robotics. Is on a PhD research position on development of imaging devices. For contact see 'About' in the above menu.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *


× 7 = fourteen

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">