1 /**
    2  * Copyright (c) 2008 Bert JW Regeer <xistence@0x58.com>
    3  *
    4  * Permission to use, copy, modify, and distribute this software for any
    5  * purpose with or without fee is hereby granted, provided that the above
    6  * copyright notice and this permission notice appear in all copies.
    7  *
    8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   15  *
   16 **/
   17 
   18 /*
   19    CONNERY-1 Data looks as follows:
   20 
   21         <4 bytes> == last valid packet written
   22         ![adc]<2 bytes>x8+1[/adc]($GPRMC)?#
   23         
   24         start byte: !
   25         stop byte: #
   26         
   27         GPS strings may be absent and still be valid data!
   28         
   29         version: 1
   30 
   31    CONNERY-2 Data looks as follows:
   32         <4 bytes> == last valid packet written
   33         !<0x82>[adc]<2 bytes>x8[/adc]($GPGGA ... $PGRMV)?#<0x83>
   34 
   35         start bytes: !<0x82>
   36         stop bytes: #<0x83>
   37         
   38         GPS strings may be absent and still be valid data!
   39         
   40         version: 2
   41         
   42     CONNERY-x Data looks as follows
   43         <4 bytes> == last valid packet written
   44         <1 byte>  == log file version number
   45         
   46         !<0x82>[adc]<2 bytes>x8[/adc](GPS string)?#<0x83>
   47         
   48         version: x
   49 */
   50 
   51 #include <sys/types.h>
   52 #include <sys/stat.h>
   53 #include <iostream>
   54 #include <fstream>
   55 #include <string>
   56 
   57 enum State { Snone, Sstart, Sadc, Sgps_search, Sgps, Send };
   58 
   59 void read_adc(std::ifstream &input, std::ofstream &output, unsigned short count) {
   60         unsigned int   character = 0;
   61         unsigned short adct = 0;
   62         
   63         while (count > adct) {
   64                 // Clear the character
   65                 character = 0;
   66                 
   67                 input.read(reinterpret_cast<char *>(&character), 1);
   68                 character = character << 8;
   69                 input.read(reinterpret_cast<char *>(&character), 1);
   70                 
   71                 output << character << ",";
   72                 adct++;
   73         }
   74 }
   75 
   76 void parse_version_1(std::ifstream &input, std::ofstream &output, long long lastgood) {
   77         std::cerr << "\tParsing version: 1" << std::endl;
   78         
   79         unsigned int character = 0;
   80         State state = Snone;
   81         
   82         while ((lastgood > input.tellg())) {
   83                 character = 0;
   84                 input.read(reinterpret_cast<char *>(&character), 1);
   85                 
   86                 if (state == Snone) {
   87                         // Check if the character is the start bytes
   88                         if (character == '!') {
   89                                 state = Sadc;
   90                         }
   91                         else {
   92                                 continue;
   93                         }
   94                 }
   95                 if (state == Sadc) {
   96                         // Okay, so we now need to read ADC values (8 ADC channels total)
   97                         read_adc(input, output, 8);
   98                         
   99                         // In the CONNERY-1 data structure there is one extra byte accidently written, we skip over it.
  100                         input.seekg(1, std::ifstream::cur);
  101                         // Next we want to look for GPS data
  102                         state = Sgps_search;
  103                 }
  104                 if (state == Sgps_search) {
  105                         if (character == '#') {
  106                                 input.seekg(-1, std::ifstream::cur);
  107                                 state = Send;
  108                                 continue;
  109                         }
  110                         if (character == '$') {
  111                                 state = Sgps;
  112                         } else {
  113                                 continue;
  114                         }
  115                 }
  116                 if (state == Sgps) {
  117                         if (character == '\n' || character == '\r') {
  118                                 continue;
  119                         }
  120                         
  121                         if (character == '#') {
  122                                 state = Send;
  123                         } else {
  124                                 if (character == '*') {
  125                                         output << ",";
  126                                 }
  127                                 
  128                                 output << static_cast<char>(character);
  129                                 continue;
  130                         }
  131                 }
  132                 if (state == Send ) {
  133                         output << std::endl;
  134                         state = Snone;
  135                         continue;
  136                 }
  137         }
  138 }
  139 
  140 void parse_version_2(std::ifstream &input, std::ofstream &output, long long lastgood) {
  141         std::cerr << "\tParsing version: 2" << std::endl;
  142         
  143         unsigned int character = 0;
  144         State state = Snone;
  145         bool secondGPS = false;
  146         
  147         while ((lastgood > input.tellg())) {
  148                 character = 0;
  149                 input.read(reinterpret_cast<char *>(&character), 1);
  150                 
  151                 if (state == Snone) {
  152                         // Check if the character is the start bytes
  153                         if (character == '!') {
  154                                 state = Sstart;
  155                                 continue;
  156                         }
  157                         else {
  158                                 continue;
  159                         }
  160                 }
  161                 
  162                 if (state == Sstart) {
  163                         if (character == 0x82) {
  164                                 state = Sadc;
  165                         } else {
  166                                 continue;
  167                         }
  168                 }
  169                 
  170                 if (state == Sadc) {
  171                         // Okay, so we now need to read ADC values (8 ADC channels total)
  172                         read_adc(input, output, 8);
  173                         
  174                         // Next we want to look for GPS data
  175                         state = Sgps_search;
  176                 }
  177                 if (state == Sgps_search) {
  178                         if (character == '#') {
  179                                 state = Send;
  180                                 continue;
  181                         }
  182                         if (character == '$') {
  183                                 state = Sgps;
  184                         } else {
  185                                 continue;
  186                         }
  187                 }
  188                 if (state == Sgps) {
  189                         if (character == '\n' || character == '\r') {
  190                                 continue;
  191                         }
  192                         
  193                         if (character == '#') {
  194                                 state = Send;
  195                                 continue;
  196                         } else {
  197                                 if (character == '$' || secondGPS == true) {
  198                                         if (secondGPS && character == '$') {
  199                                                 output << ",";
  200                                         } else {
  201                                                 secondGPS = true;
  202                                         }
  203                                 }
  204                                 
  205                                 if (character == '*') {
  206                                         output << ",";
  207                                 }
  208                                         
  209                                 output << static_cast<char>(character);
  210                                 continue;
  211                         }
  212                 }
  213                 if (state == Send ) {
  214                         if (character == 0x83) {
  215                                 output << std::endl;
  216                                 state = Snone;
  217                                 secondGPS = false;
  218                                 continue;
  219                         } else {
  220                                 continue;
  221                         }
  222                 }
  223         }
  224 }
  225 
  226 // To add more version parsers create the function above, then add another entry to the version_parser array. 0 offset.
  227 // so version 1 is actually at array offset 0. Beware.
  228 struct versions { 
  229         void (* parse)(std::ifstream &input, std::ofstream &output, long long lastgood); 
  230 } version_parser[] = { 
  231         { parse_version_1 }, 
  232         { parse_version_2 }
  233 };
  234 
  235 
  236 int check_version(std::ifstream &input) {
  237         // Scan for version
  238         unsigned int version = 0;
  239         unsigned char character = 0;
  240         
  241         input.read(reinterpret_cast<char *>(&character), 1);
  242         
  243         if (character == '!') {
  244                 version = 1;
  245                 input.read(reinterpret_cast<char *>(&character), 1);
  246                 if (character == 0x82) {
  247                         version = 2;
  248                 }
  249                 
  250                 // We want to seek backwards to make sure that the parser starts parsing at the right location
  251                 input.seekg(-2, std::ifstream::cur);
  252                 
  253         } else {
  254                 version = character;
  255         }
  256         
  257         return version;
  258 }
  259 
  260 int main(int argc, char* argv[]) {
  261 
  262         // Check if we have at least three arguments
  263         if (argc < 3) {
  264                 std::cerr << "Usage: " << std::endl << "\t" << argv[0] << " <input file> <output file>" << std::endl;
  265                 return -1;
  266         }
  267         
  268         std::cerr << "Near Space Flight Computer parser" << std::endl;
  269         
  270         std::ifstream input;
  271         std::ofstream output;
  272         
  273         // Open the input file as a binary stream
  274         input.open(argv[1], std::ifstream::binary);
  275         
  276         // Open the output file as a standard text file, and truncate it
  277         output.open(argv[2], std::ofstream::out | std::ofstream::trunc);
  278         
  279         long long filelength = 0;
  280         
  281         input.seekg(0, std::ifstream::end);
  282         filelength = input.tellg();
  283         input.seekg(0, std::ifstream::beg);
  284         
  285         long long lastgood = 0;
  286         
  287         for (int i = 4; i > 0; i--) {
  288                 lastgood = lastgood << 8;
  289                 input.read(reinterpret_cast<char *>(&lastgood), 1);
  290         }
  291         
  292         std::cerr << "\tFile total length: 0x" << std::hex << filelength << std::endl;
  293         std::cerr << "\tLast good write at: 0x" << std::hex << lastgood << std::endl;
  294         
  295         // Check the file structure
  296         int fileversion = check_version(input);
  297         
  298         std::cerr << "\tFile version: " << fileversion << std::endl;
  299         
  300         version_parser[fileversion - 1].parse(input, output, lastgood);
  301         
  302         std::cerr << "\tProcessed 0x" << std::hex << input.tellg() << " bytes" << std::endl;
  303         std::cerr << "\tUn-processed: 0x" << std::hex << filelength - input.tellg() << " bytes" << std::endl;
  304 }
  305