GNSS and Record Audio at the same time?



  • I am using the Arduino Spresense libraries. When I try to do GNSS and record Audio at the same time, it fails. But with the same sketch code, If I disable either the GNSS or Audio code, the remaining GNSS or Audio works fine. Can someone post an arduino example of this working? I get errors like below, once a second, then after 10 times they stop, but no audio is saved.

    16:51:05.971 -> main_setup() initializing logFile logfile.log
    16:51:05.971 -> file_setup() start
    16:51:06.006 -> audio_setup() Initializing the Audio Library...
    16:51:07.382 -> Setting up the Recorder...
    16:51:07.382 -> Writing the WAV File Header...
    16:51:07.382 -> Start Recording
    16:51:07.418 -> audio_setup() done
    16:51:07.418 ->
    16:51:09.029 -> gnss_setup() Initializing GNSS...
    16:51:09.096 -> Attention: module[4][0] attention id[1]/code[6] (objects/media_recorder/audio_recorder_sink.cpp L84)
    16:51:09.132 -> Audio_Attention_CB() info/warn code=0x1
    16:51:12.025 -> SpGnss : begin in
    16:51:12.919 -> SpGnss : begin out
    16:51:12.919 -> SpGnss : start in
    16:51:12.919 -> mode = COLD_START
    16:51:13.328 -> SpGnss : start out
    16:51:13.328 -> Gnss setup OK
    16:51:13.328 -> gnss_setup() done
    16:51:13.328 ->
    16:51:13.328 ->
    16:51:13.328 -> Setup Complete
    16:51:13.328 ->

    16:51:14.326 -> up_assert: Assertion failed at file:components/capture/capture_component.cpp line: 801 task: capture0
    16:51:14.359 -> up_registerdump: R0: 00000001 0d05392c 000000e0 0d055e2c 0d05392c 0d06abb8 0d055fcc 0d061258
    16:51:14.359 -> up_registerdump: R8: 0d03c4fc 00000321 0d06a270 00000000 00000000 0d06abb8 0d01da95 0d01e08c
    16:51:14.359 -> up_registerdump: xPSR: 61000000 BASEPRI: 000000e0 CONTROL: 00000004
    16:51:14.359 -> up_registerdump: EXC_RETURN: ffffffe9
    16:51:14.359 -> up_dumpstate: sp: 0d06abb8
    16:51:14.359 -> up_dumpstate: IRQ stack:
    16:51:14.392 -> up_dumpstate: base: 0d054200
    16:51:14.392 -> up_dumpstate: size: 00000800
    16:51:14.392 -> up_dumpstate: used: 000000f0
    16:51:14.392 -> up_dumpstate: User stack:
    16:51:14.392 -> up_dumpstate: base: 0d06ac18
    16:51:14.392 -> up_dumpstate: size: 000007fc
    16:51:14.392 -> up_dumpstate: used: 00000248
    16:51:14.392 -> up_stackdump: 0d06aba0: 00000000 0d06ac18 0d06abb8 0d055fcc 0d06a41c 0d01dbd9 000000e0 00000004
    16:51:14.392 -> up_stackdump: 0d06abc0: 00000000 00000000 0d06abb8 0d01da95 0d01e08c 00000000 00000000 0d061258
    16:51:14.426 -> up_stackdump: 0d06abe0: 00000000 0d007173 000fd400 000fe880 0d06a270 0d0071dd 0d0071bb 0d016c63
    16:51:14.426 -> up_stackdump: 0d06ac00: 00000000 00000000 00000000 00000000 00000000 00000000 deadbeef fb528c48
    16:51:14.426 -> up_taskdump: Idle Task: PID=0 Stack Used=0 of 0
    16:51:14.426 -> up_taskdump: hpwork: PID=1 Stack Used=576 of 2028
    16:51:14.426 -> up_taskdump: lpwork: PID=2 Stack Used=352 of 2028
    16:51:14.426 -> up_taskdump: lpwork: PID=3 Stack Used=352 of 2028
    16:51:14.426 -> up_taskdump: lpwork: PID=4 Stack Used=352 of 2028
    16:51:14.461 -> up_taskdump: cxd56_pm_task: PID=6 Stack Used=352 of 996
    16:51:14.461 -> up_taskdump: <pthread>: PID=7 Stack Used=736 of 1020
    16:51:14.461 -> up_taskdump: init: PID=8 Stack Used=1112 of 8172
    16:51:14.461 -> up_taskdump: audio_manager: PID=9 Stack Used=704 of 2044
    16:51:14.461 -> up_taskdump: media_player0: PID=10 Stack Used=344 of 3068
    16:51:14.461 -> up_taskdump: media_player1: PID=11 Stack Used=344 of 3068
    16:51:14.461 -> up_taskdump: out_mixer: PID=12 Stack Used=344 of 3068
    16:51:14.497 -> up_taskdump: renderer0: PID=13 Stack Used=344 of 2044
    16:51:14.497 -> up_taskdump: renderer1: PID=14 Stack Used=344 of 2044
    16:51:14.497 -> up_taskdump: front_end: PID=15 Stack Used=568 of 2044
    16:51:14.497 -> up_taskdump: media_recorder: PID=16 Stack Used=792 of 2044
    16:51:14.497 -> up_taskdump: capture0: PID=17 Stack Used=584 of 2044
    16:51:14.497 -> up_taskdump: alarm_daemon: PID=18 Stack Used=328 of 2044


  • DeveloperWorld

    Hi @m-Lewis,

    Below I put the code in which Spresense records Audio and reads positions from GNSS:

    #include <SDHCI.h>
    #include <Audio.h>
    
    #define RECORD_FILE_NAME "Sound.mp3"
    
    SDClass theSD;
    AudioClass *theAudio;
    
    File myFile;
    
    bool ErrEnd = false;
    
    /* include the GNSS library */
    #include <GNSS.h>
    
    #define STRING_BUFFER_SIZE  128       /**< %Buffer size */
    
    #define RESTART_CYCLE       (60 * 5)  /**< positioning test term */
    
    static SpGnss Gnss;                   /**< SpGnss object */
    
    /**
     * @enum ParamSat
     * @brief Satellite system
     */
    enum ParamSat {
      eSatGps,            /**< GPS                     World wide coverage  */
      eSatGlonass,        /**< GLONASS                 World wide coverage  */
      eSatGpsSbas,        /**< GPS+SBAS                North America        */
      eSatGpsGlonass,     /**< GPS+Glonass             World wide coverage  */
      eSatGpsBeidou,      /**< GPS+BeiDou              World wide coverage  */
      eSatGpsGalileo,     /**< GPS+Galileo             World wide coverage  */
      eSatGpsQz1c,        /**< GPS+QZSS_L1CA           East Asia & Oceania  */
      eSatGpsGlonassQz1c, /**< GPS+Glonass+QZSS_L1CA   East Asia & Oceania  */
      eSatGpsBeidouQz1c,  /**< GPS+BeiDou+QZSS_L1CA    East Asia & Oceania  */
      eSatGpsGalileoQz1c, /**< GPS+Galileo+QZSS_L1CA   East Asia & Oceania  */
      eSatGpsQz1cQz1S,    /**< GPS+QZSS_L1CA+QZSS_L1S  Japan                */
    };
    
    /* Set this parameter depending on your current region. */
    static enum ParamSat satType =  eSatGps;
    
    /**
     * @brief Turn on / off the LED0 for CPU active notification.
     */
    static void Led_isActive(void)
    {
      static int state = 1;
      if (state == 1)
      {
        ledOn(PIN_LED0);
        state = 0;
      }
      else
      {
        ledOff(PIN_LED0);
        state = 1;
      }
    }
    
    /**
     * @brief Turn on / off the LED1 for positioning state notification.
     *
     * @param [in] state Positioning state
     */
    static void Led_isPosfix(bool state)
    {
      if (state)
      {
        ledOn(PIN_LED1);
      }
      else
      {
        ledOff(PIN_LED1);
      }
    }
    
    /**
     * @brief Turn on / off the LED3 for error notification.
     *
     * @param [in] state Error state
     */
    static void Led_isError(bool state)
    {
      if (state)
      {
        ledOn(PIN_LED3);
      }
      else
      {
        ledOff(PIN_LED3);
      }
    }
    
    /**
     * @brief %Print position information.
     */
    static void print_pos(SpNavData *pNavData)
    {
      char StringBuffer[STRING_BUFFER_SIZE];
    
      /* print time */
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "%04d/%02d/%02d ", pNavData->time.year, pNavData->time.month, pNavData->time.day);
      Serial.print(StringBuffer);
    
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "%02d:%02d:%02d.%06d, ", pNavData->time.hour, pNavData->time.minute, pNavData->time.sec, pNavData->time.usec);
      Serial.print(StringBuffer);
    
      /* print satellites count */
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSat:%2d, ", pNavData->numSatellites);
      Serial.print(StringBuffer);
    
      /* print position data */
      if (pNavData->posFixMode == FixInvalid)
      {
        Serial.print("No-Fix, ");
      }
      else
      {
        Serial.print("Fix, ");
      }
      if (pNavData->posDataExist == 0)
      {
        Serial.print("No Position");
      }
      else
      {
        Serial.print("Lat=");
        Serial.print(pNavData->latitude, 6);
        Serial.print(", Lon=");
        Serial.print(pNavData->longitude, 6);
      }
    
      Serial.println("");
    }
    
    /**
     * @brief %Print satellite condition.
     */
    static void print_condition(SpNavData *pNavData)
    {
      char StringBuffer[STRING_BUFFER_SIZE];
      unsigned long cnt;
    
      /* Print satellite count. */
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSatellites:%2d\n", pNavData->numSatellites);
      Serial.print(StringBuffer);
    
      for (cnt = 0; cnt < pNavData->numSatellites; cnt++)
      {
        const char *pType = "---";
        SpSatelliteType sattype = pNavData->getSatelliteType(cnt);
    
        /* Get satellite type. */
        /* Keep it to three letters. */
        switch (sattype)
        {
          case GPS:
            pType = "GPS";
            break;
    
          case GLONASS:
            pType = "GLN";
            break;
    
          case QZ_L1CA:
            pType = "QCA";
            break;
    
          case SBAS:
            pType = "SBA";
            break;
    
          case QZ_L1S:
            pType = "Q1S";
            break;
    
          case BEIDOU:
            pType = "BDS";
            break;
    
          case GALILEO:
            pType = "GAL";
            break;
    
          default:
            pType = "UKN";
            break;
        }
    
        /* Get print conditions. */
        unsigned long Id  = pNavData->getSatelliteId(cnt);
        unsigned long Elv = pNavData->getSatelliteElevation(cnt);
        unsigned long Azm = pNavData->getSatelliteAzimuth(cnt);
        float sigLevel = pNavData->getSatelliteSignalLevel(cnt);
    
        /* Print satellite condition. */
        snprintf(StringBuffer, STRING_BUFFER_SIZE, "[%2d] Type:%s, Id:%2d, Elv:%2d, Azm:%3d, CN0:", cnt, pType, Id, Elv, Azm );
        Serial.print(StringBuffer);
        Serial.println(sigLevel, 6);
      }
    }
    
    /**
     * @brief Audio attention callback
     *
     * When audio internal error occurc, this function will be called back.
     */
    
    static void audio_attention_cb(const ErrorAttentionParam *atprm)
    {
      puts("Attention!");
      
      if (atprm->error_code >= AS_ATTENTION_CODE_WARNING)
        {
          ErrEnd = true;
       }
    }
    
    /**
     * @brief Setup recording of mp3 stream to file
     *
     * Select input device as microphone <br>
     * Initialize filetype to stereo mp3 with 48 Kb/s sampling rate <br>
     * Open RECORD_FILE_NAME file in write mode
     */
    
    /* Recording time[second] */
    
    static const int32_t recoding_time = 10;
    
    /* Recording bit rate
     * Set in bps.
     * Note: 96kbps fixed
     */
    
    static const int32_t recoding_bitrate = 96000;
    
    /* Bytes per second */
    
    static const int32_t recoding_byte_per_second = (recoding_bitrate / 8);
    
    /* Total recording size */
    
    static const int32_t recoding_size = recoding_byte_per_second * recoding_time;
    
    /**
     * @brief Activate GNSS device and start positioning.
     */
    void gnss_setup() {
      /* put your setup code here, to run once: */
    
      int error_flag = 0;
    
      /* Set serial baudrate. */
      Serial.begin(115200);
    
      /* Wait HW initialization done. */
      sleep(3);
    
      /* Turn on all LED:Setup start. */
      ledOn(PIN_LED0);
      ledOn(PIN_LED1);
      ledOn(PIN_LED2);
      ledOn(PIN_LED3);
    
      /* Set Debug mode to Info */
      Gnss.setDebugMode(PrintInfo);
    
      int result;
    
      /* Activate GNSS device */
      result = Gnss.begin();
    
      if (result != 0)
      {
        Serial.println("Gnss begin error!!");
        error_flag = 1;
      }
      else
      {
        /* Setup GNSS
         *  It is possible to setup up to two GNSS satellites systems.
         *  Depending on your location you can improve your accuracy by selecting different GNSS system than the GPS system.
         *  See: https://developer.sony.com/develop/spresense/developer-tools/get-started-using-nuttx/nuttx-developer-guide#_gnss
         *  for detailed information.
        */
        switch (satType)
        {
        case eSatGps:
          Gnss.select(GPS);
          break;
    
        case eSatGpsSbas:
          Gnss.select(GPS);
          Gnss.select(SBAS);
          break;
    
        case eSatGlonass:
          Gnss.select(GLONASS);
          break;
    
        case eSatGpsGlonass:
          Gnss.select(GPS);
          Gnss.select(GLONASS);
          break;
    
        case eSatGpsBeidou:
          Gnss.select(GPS);
          Gnss.select(BEIDOU);
          break;
    
        case eSatGpsGalileo:
          Gnss.select(GPS);
          Gnss.select(GALILEO);
          break;
    
        case eSatGpsQz1c:
          Gnss.select(GPS);
          Gnss.select(QZ_L1CA);
          break;
    
        case eSatGpsQz1cQz1S:
          Gnss.select(GPS);
          Gnss.select(QZ_L1CA);
          Gnss.select(QZ_L1S);
          break;
    
        case eSatGpsBeidouQz1c:
          Gnss.select(GPS);
          Gnss.select(BEIDOU);
          Gnss.select(QZ_L1CA);
          break;
    
        case eSatGpsGalileoQz1c:
          Gnss.select(GPS);
          Gnss.select(GALILEO);
          Gnss.select(QZ_L1CA);
          break;
    
        case eSatGpsGlonassQz1c:
        default:
          Gnss.select(GPS);
          Gnss.select(GLONASS);
          Gnss.select(QZ_L1CA);
          break;
        }
    
        /* Start positioning */
        result = Gnss.start(COLD_START);
        if (result != 0)
        {
          Serial.println("Gnss start error!!");
          error_flag = 1;
        }
        else
        {
          Serial.println("Gnss setup OK");
        }
      }
    
      /* Start 1PSS output to PIN_D02 */
      //Gnss.start1PPS();
    
      /* Turn off all LED:Setup done. */
      ledOff(PIN_LED0);
      ledOff(PIN_LED1);
      ledOff(PIN_LED2);
      ledOff(PIN_LED3);
    
      /* Set error LED. */
      if (error_flag == 1)
      {
        Led_isError(true);
        exit(0);
      }
    }
    
    void recorder_setup()
    {
      theAudio = AudioClass::getInstance();
    
      theAudio->begin(audio_attention_cb);
    
      puts("initialization Audio Library");
    
      /* Select input device as microphone */
      theAudio->setRecorderMode(AS_SETRECDR_STS_INPUTDEVICE_MIC);
    
      /*
       * Initialize filetype to stereo mp3 with 48 Kb/s sampling rate
       * Search for MP3 codec in "/mnt/sd0/BIN" directory
       */
      theAudio->initRecorder(AS_CODECTYPE_MP3, "/mnt/sd0/BIN", AS_SAMPLINGRATE_48000, AS_CHANNEL_STEREO);
      puts("Init Recorder!");
    
      /* Open file for data write on SD card */
    
      theSD.begin();
    
      if (theSD.exists(RECORD_FILE_NAME))
        {
          printf("Remove existing file [%s].\n", RECORD_FILE_NAME);
          theSD.remove(RECORD_FILE_NAME);
        }
    
      myFile = theSD.open(RECORD_FILE_NAME, FILE_WRITE);
      /* Verify file open */
      if (!myFile)
        {
          printf("File open error\n");
          exit(1);
        }
    
      printf("Open! [%s]\n", RECORD_FILE_NAME);
    
      theAudio->startRecorder();
      puts("Recording Start!");
    }
    
    void setup() {
      gnss_setup();
      recorder_setup();
    }
    
    /**
     * @brief Record given frame number
     */
    void loop() 
    {
        static int LastPrintMin = 0;
    
      /* Blink LED. */
      Led_isActive();
    
      /* Check update. */
      if (Gnss.waitUpdate(0))
      {
        /* Get NaviData. */
        SpNavData NavData;
        Gnss.getNavData(&NavData);
    
        /* Set posfix LED. */
        bool LedSet = (NavData.posDataExist && (NavData.posFixMode != FixInvalid));
        Led_isPosfix(LedSet);
    
        /* Print satellite information every minute. */
        if (NavData.time.minute != LastPrintMin)
        {
          print_condition(&NavData);
          LastPrintMin = NavData.time.minute;
        }
    
        /* Print position information. */
        print_pos(&NavData);
      }
    
      err_t err;
      /* recording end condition */
      if (theAudio->getRecordingSize() > recoding_size)
        {
          theAudio->stopRecorder();
          sleep(1);
          err = theAudio->readFrames(myFile);
    
          goto exitRecording;
        }
    
      /* Read frames to record in file */
      err = theAudio->readFrames(myFile);
    
      if (err != AUDIOLIB_ECODE_OK)
        {
          printf("File End! =%d\n",err);
          theAudio->stopRecorder();
          goto exitRecording;
        }
    
      if (ErrEnd)
        {
          printf("Error End\n");
          theAudio->stopRecorder();
          goto exitRecording;
        }
    
      /* This sleep is adjusted by the time to write the audio stream file.
         Please adjust in according with the processing contents
         being processed at the same time by Application.
      */
    //  usleep(10000);
    
      return;
    
    exitRecording:
    
      theAudio->closeOutputFile(myFile);
      myFile.close();
      
      theAudio->setReadyMode();
      theAudio->end();
    
      Gnss.stop();
      Gnss.end();
      
      puts("End Recording");
      exit(1);
    }
    

    Please let me know what was wrong with your application or share the code.

    Best Regards,
    Kamil Tomaszewski



  • Kamil,
    Thank you for responding. However, your code did not work for me. I did not get any GNSS or Audio, and all output stopped after about 10 seconds.
    I am attaching my code here. As I said, I am successful with doing either Audio or GNSS, but not at the same time. You can see how this choice is selected in the very first lines of my source file. Much of the code was taken from the SPresense examples. I modified so that I can continue to write data samples to a logfile at 10 Hz while waiting for the next GNSS report at 1 Hz. You can imagine other sensor data being written to the log file at the 10 Hz rate. I use an analog mic and .wav file. To save confusion, I put all my source in a single file here, and both setup() and main() are at the very bottom. Hope its clear.
    M. Lewis

    // GNSS and Audio at the same time example, while writing data to a logfile and output to Serial port
    // M. Lewis
    
    bool doAudio = false; // Record Audio
    bool doGnss = true;   // GNSS/GPS
    bool doLed = true;    // Blink LED
    bool doStream = true; // Stream sampled data lines to Serial output at Sample Rate
    bool doFile = true;   // Stream sampled data lines to logFile at Sample Rate
    
    #include <Arduino.h>
    #include <arch/board/board.h>
    #include <SDHCI.h>
    #include <File.h>
    #include <Storage.h>
    #include <elapsedMillis.h>
    #include <GNSS.h>
    #include <RTC.h> // For setting realtime clock
    #include <Audio.h>
    
    
    SDClass theSD; // This is the SD card class
    File logFile; // File object
    //char* logName = "/mnt/spif/logfile.log";
    char* logName = "logfile.log";
    String logString;
    
    elapsedMillis sinceSample;
    int sampleMillis = 1000/10; // 10 Hz
    
    ////////////// LED Control //////////////
    
    unsigned long blinkStartMS;
    #define BLINK_MS 500 // number of millisecs for on or off
    
    int blinkMillis = 1000/2;  // 2 Hz
    elapsedMillis sinceBlink;
    
    void led_setup() {
      Serial.println("led_setup()");
      pinMode(LED0, OUTPUT); // Init the on-board SPresense LEDs
      pinMode(LED1, OUTPUT);
      pinMode(LED2, OUTPUT);
      pinMode(LED3, OUTPUT);
      blinkStartMS = 0 ;
    }
    
    void led_loop() {
      static bool state = true;
      if (sinceBlink < blinkMillis) {
        return;
      }
      sinceBlink = sinceBlink - blinkMillis;
      state = ! state;
      digitalWrite(PIN_LED0, state==false ? LOW : HIGH);
    }
    
    void led_setAll(bool state)
    {
      digitalWrite(PIN_LED0, state==false ? LOW : HIGH);
      digitalWrite(PIN_LED1, state==false ? LOW : HIGH);
      digitalWrite(PIN_LED2, state==false ? LOW : HIGH);
      digitalWrite(PIN_LED3, state==false ? LOW : HIGH);
    }
    
    static void Led_isPosfix(bool state)
    {
        digitalWrite(PIN_LED1, state==false ? LOW : HIGH);
    }
    
    static void Led_isError(bool state)
    {
        digitalWrite(PIN_LED3, state==false ? LOW : HIGH);
    }
    
    
    ////////////// Log File Control //////////////
    
    void file_setup()
    {
      Serial.println("file_setup() start");
    
      //logFile = Storage.open(logName, FILE_WRITE); // Open the file. Note: only one file can be open at a time
      if (! theSD.begin()) {
        Serial.print("uSD card is not present!!");
        while(1){;}
      }
        
      logString = String("MSec");
      if (doGnss) {
        logString += ",";
        logString += gnss_get_columns();
      }
      
      logString += "\r\n";
      Serial.print(logString.c_str());
    
      logFile = theSD.open(logName, FILE_WRITE); // Open the file. Note: only one file can be open at a time
      if (!logFile) {
        Serial.print("Could not open logFile");
        return;
      }
    
      if (logFile.size() < 1) { // Empty or non-existant file. Add header line
        logFile.write(logString.c_str(), strlen(logString.c_str()));
        logFile.close(); /* Close the file */
        //logFile.flush();
      }
    }
    
    ////////////// GNSS File Control //////////////
    
    #define STRING_BUFFER_SIZE  128       /**< %Buffer size */
    #define RESTART_CYCLE       (60 * 5)  /**< positioning test term */
    
    static SpGnss Gnss;                   /**< SpGnss object */
    SpNavData NavData;
    uint32_t recordCount;
    String gnssLatestString;
    void gnss_update_latestString();
    
    const uint16_t FAULT_GPS_TIME = 0x2; // NO GPS Time and Date
    const uint16_t FAULT_GPS_FIX = 0x4; // NO GPS Location
    uint16_t gps_fault = 0;
    
    /**
     * @enum ParamSat
     * @brief Satellite system
     */
    enum ParamSat {
      eSatGps,            /**< GPS                     World wide coverage  */
      eSatGlonass,        /**< GLONASS                 World wide coverage  */
      eSatGpsSbas,        /**< GPS+SBAS                North America        */
      eSatGpsGlonass,     /**< GPS+Glonass             World wide coverage  */
      eSatGpsBeidou,      /**< GPS+BeiDou              World wide coverage  */
      eSatGpsGalileo,     /**< GPS+Galileo             World wide coverage  */
      eSatGpsQz1c,        /**< GPS+QZSS_L1CA           East Asia & Oceania  */
      eSatGpsGlonassQz1c, /**< GPS+Glonass+QZSS_L1CA   East Asia & Oceania  */
      eSatGpsBeidouQz1c,  /**< GPS+BeiDou+QZSS_L1CA    East Asia & Oceania  */
      eSatGpsGalileoQz1c, /**< GPS+Galileo+QZSS_L1CA   East Asia & Oceania  */
      eSatGpsQz1cQz1S,    /**< GPS+QZSS_L1CA+QZSS_L1S  Japan                */
    };
    
    static enum ParamSat satType =  eSatGps; /* Set this parameter depending on your current region. */
    
    void gnss_setSatType()
    {
        /* Setup GNSS
         *  It is possible to setup up to two GNSS satellites systems.
         *  Depending on your location you can improve your accuracy by selecting different GNSS system than the GPS system.
         *  See: https://developer.sony.com/develop/spresense/developer-tools/get-started-using-nuttx/nuttx-developer-guide#_gnss
         *  for detailed information.
        */
        switch (satType)
        {
        case eSatGps:
          Gnss.select(GPS);
          break;
    
        case eSatGpsSbas:
          Gnss.select(GPS);
          Gnss.select(SBAS);
          break;
    
        case eSatGlonass:
          Gnss.select(GLONASS);
          break;
    
        case eSatGpsGlonass:
          Gnss.select(GPS);
          Gnss.select(GLONASS);
          break;
    
        case eSatGpsBeidou:
          Gnss.select(GPS);
          Gnss.select(BEIDOU);
          break;
    
        case eSatGpsGalileo:
          Gnss.select(GPS);
          Gnss.select(GALILEO);
          break;
    
        case eSatGpsQz1c:
          Gnss.select(GPS);
          Gnss.select(QZ_L1CA);
          break;
    
        case eSatGpsQz1cQz1S:
          Gnss.select(GPS);
          Gnss.select(QZ_L1CA);
          Gnss.select(QZ_L1S);
          break;
    
        case eSatGpsBeidouQz1c:
          Gnss.select(GPS);
          Gnss.select(BEIDOU);
          Gnss.select(QZ_L1CA);
          break;
    
        case eSatGpsGalileoQz1c:
          Gnss.select(GPS);
          Gnss.select(GALILEO);
          Gnss.select(QZ_L1CA);
          break;
    
        case eSatGpsGlonassQz1c:
        default:
          Gnss.select(GPS);
          Gnss.select(GLONASS);
          Gnss.select(QZ_L1CA);
          break;
        }
    }
    
    /**
     * @brief Activate GNSS device and start positioning.
     */
    void gnss_setup() {
      int error_flag = 0;
      recordCount = 0;
      
      puts("gnss_setup() Initializing GNSS...");
      RTC.begin(); // Initialize RTC at first
    
      gps_fault = FAULT_GPS_FIX | FAULT_GPS_TIME; // assume no GPS time or fix, show a fault
    
      sleep(3); // Wait HW initialization done
      led_setAll(true); //  Turn on all LEDs
    
      Gnss.setDebugMode(PrintInfo);
      if (Gnss.begin() != 0)
      {
        Serial.println("Gnss begin error!!");
        error_flag = 1;
      }
      else
      {
        gnss_setSatType(); // Select International Sat Systems to use
        if (Gnss.start(COLD_START) != 0) // Start positioning
        {
          Serial.println("Gnss COLD_START error!!");
          error_flag = 1;
        }
        else
        {
          Serial.println("Gnss setup OK");
        }
      }
    
      //Gnss.start1PPS(); /* Start 1PSS output to PIN_D02 */
    
      led_setAll(false); //  Turn off all LEDs
    
      if (error_flag == 1)
      {
        Led_isError(true); // Set error LED3
        exit(0);
      }
      puts("gnss_setup() done\n");
    }
    
    /**
     * @brief %Print satellite condition.
     */
    static void print_condition(SpNavData *pNavData)
    {
      char StringBuffer[STRING_BUFFER_SIZE];
      unsigned long cnt;
    
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSatellites:%2d\n", pNavData->numSatellites); // Print satellite count
      Serial.print(StringBuffer);
    
      for (cnt = 0; cnt < pNavData->numSatellites; cnt++)
      {
        const char *pType = "---";
        SpSatelliteType sattype = pNavData->getSatelliteType(cnt);
        switch (sattype) // Get satellite 3 letter string
        {
          case GPS:        pType = "GPS";        break;
          case GLONASS:    pType = "GLN";        break;
          case QZ_L1CA:    pType = "QCA";        break;
          case SBAS:       pType = "SBA";        break;
          case QZ_L1S:     pType = "Q1S";        break;
          case BEIDOU:     pType = "BDS";        break;
          case GALILEO:    pType = "GAL";        break;
          default:         pType = "UKN";        break;
        }
    
        unsigned long Id  = pNavData->getSatelliteId(cnt);
        unsigned long Elv = pNavData->getSatelliteElevation(cnt);
        unsigned long Azm = pNavData->getSatelliteAzimuth(cnt);
        float sigLevel = pNavData->getSatelliteSignalLevel(cnt);
    
        snprintf(StringBuffer, STRING_BUFFER_SIZE, "[%2d] Type:%s, Id:%2d, Elv:%2d, Azm:%3d, CN0:", cnt, pType, Id, Elv, Azm );
        Serial.print(StringBuffer);
        Serial.println(sigLevel, 6);
      }
    }
    
    /**
     * @brief %Print position information.
     */
    static void print_pos(SpNavData *pNavData)
    {
      static int LastPrintMin = 0;
      char StringBuffer[STRING_BUFFER_SIZE];
    
      /* print time */
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "%04d/%02d/%02d ", pNavData->time.year, pNavData->time.month, pNavData->time.day);
      Serial.print(StringBuffer);
    
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "%02d:%02d:%02d.%06d, ", pNavData->time.hour, pNavData->time.minute, pNavData->time.sec, pNavData->time.usec);
      Serial.print(StringBuffer);
    
      /* print satellites count */
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSat:%2d, ", pNavData->numSatellites);
      Serial.print(StringBuffer);
    
      /* print position data */
      unsigned char fixMode = pNavData->posFixMode;
      switch (fixMode)
      {
        case 2:   Serial.print("2D"); break;
        case 3:   Serial.print("3D"); break;
        case 0:   // FixInvalid: //Serial.print("No-Fix, "); break;  // FixInvalid:
        default:  Serial.print("No"); break;
      }
      Serial.print("-Fix(");
      Serial.print(fixMode);
      Serial.print("), ");
      
      if (pNavData->posDataExist == 0)
      {
        Serial.print("No Position");
      }
      else
      {
        Serial.print("Lat=");
        Serial.print(pNavData->latitude, 6);
        Serial.print(", Lon=");
        Serial.print(pNavData->longitude, 6);
      }
    
      Serial.println("");
    
      if (NavData.time.minute != LastPrintMin) // Print satellite information every minute
      {
        print_condition(&NavData);
        LastPrintMin = NavData.time.minute;
      }
    }
    
    void gnss_restart()
    {
      int error_flag = 0;
    
      ledOff(PIN_LED0); // Turn off LED0
      Led_isPosfix(false); // Turn off posFix LED1
     
      if (Gnss.stop() != 0)
      {
        Serial.println("Gnss stop error!!");
        error_flag = 1;
      }
      else if (Gnss.end() != 0)
      {
        Serial.println("Gnss end error!!");
        error_flag = 1;
      }
      else
      {
        Serial.println("Gnss stop OK.");
      }
    
      if (Gnss.begin() != 0)
      {
        Serial.println("Gnss begin error!!");
        error_flag = 1;
      }
      else if (Gnss.start(HOT_START) != 0)
      {
        Serial.println("Gnss hot start error!!");
        error_flag = 1;
      }
      else
      {
        Serial.println("Gnss restart OK.");
      }
    
      if (error_flag == 1)
      {
        Led_isError(true); // Set error LED3
        exit(0);
      }
    }
    
    void gnss_update_latestString() {
    
      // Following code block was in loop()
      bool goodFix;
      int upd=Gnss.waitUpdate(0); //-1);
      if (upd) // Check update
      {
        if (upd) { recordCount++; } // New GNSS data has come in
        Gnss.getNavData(&NavData); // Get NaviData
        goodFix = NavData.posDataExist && (NavData.posFixMode != FixInvalid);
        Led_isPosfix( goodFix ); // Set posFix LED1 if there is a Fix
        print_pos(&NavData); // Print position information
      }
    
      if (!upd) {
        return;
      }
    
      //Serial.printf("secondsSinceTime()=%.3f\n", GPS.secondsSinceTime());
      gnssLatestString = "GPS,";
      if (NavData.time.hour < 10) { gnssLatestString += '0'; }
      gnssLatestString += NavData.time.hour; gnssLatestString += ':';
      if (NavData.time.minute < 10) { gnssLatestString += '0'; }
      gnssLatestString += NavData.time.minute; gnssLatestString += ':';
      if (NavData.time.sec < 10) { gnssLatestString += '0'; }
      gnssLatestString += NavData.time.sec;
    
      // handle millisecs - GPS.milliseconds can fail prior to a fix, then returns a random string
      uint16_t millisecs = NavData.time.usec / 1000;
      //Serial.printf("Millisec=%u\n", millisecs);
      if (millisecs > 1000) {millisecs = 0;}
      gnssLatestString += '.';
      if (millisecs < 10) {
        gnssLatestString += "00";
      } else if (millisecs > 9 && millisecs < 100) {
        gnssLatestString += "0";
      }
      gnssLatestString += millisecs;
      
      gnssLatestString += ",";
      gnssLatestString += NavData.time.year; gnssLatestString += '/';
      gnssLatestString += NavData.time.month;  gnssLatestString += '/';
      gnssLatestString += NavData.time.day;
    
      char fixBuf[300];
      char lat, lon;
      //lat = (!NavData.latitude) ? 'n' : NavData.latitude; // needed when never had fix since GPS.lat initialized to 0
      //lon = (!NavData.longitude) ? 'w' : NavData.longitude;
      lat = 'n';
      lon = 'w';
      
      sprintf(fixBuf, ",%.6f,%c,%.6f,%c,%.1f,%.1f,%d,%d,%lu",
        NavData.latitude, lat, NavData.longitude, lon, NavData.altitude, NavData.velocity, (int)NavData.numSatellites, NavData.posFixMode, recordCount);
      gnssLatestString += fixBuf;
    }
    
    char* gnss_get_columns() { // return the column headers
      static char buf[200] = "GPS,Time,Date,Lat_deg,N/S,Lon_deg,E/W,Alt_m,Knots,Track_deg,Sats,Fix,Rcvd";
      char* s = buf;
      return s;
    }
    
    char* gnss_get_latest() // return pointer to CSV IMU data string
    {
      gnss_update_latestString();
      gps_fault = 0;
      int status = (NavData.posDataExist && (NavData.posFixMode != FixInvalid));
      if (! NavData.posDataExist) {
        gps_fault |= FAULT_GPS_FIX;
      } else {
        //gnss_upd_rtc(); // SPresense version of RTC
      }
      return (char*)gnssLatestString.c_str();
    }
    
    bool gnss_waitUpdate(int milliSecs) { // milliSecs to wait, or -1 to not wait. Assumes setup() was already called
      bool upd = false;
      upd=Gnss.waitUpdate(milliSecs); // Check update
      return upd;
    }
    
    void gnss_loop() {} // Nothing here, GNSS is run at the much slower Sample rate. See gnss_get_latest() above
    
    ////////////// AUDIO RECORDING CONTROL //////////////
    extern SDClass theSD; // Declared in sp_main.cpp
    AudioClass *theAudio;
    File wavFile;
    int file_count = 0;
    bool ErrEnd = false;
    
    static const uint32_t recording_time = 10; // Recording Time (Seconds) per wav file
    static const uint32_t recording_sampling_rate = 48000; // Sample Rate (16000 or 48000)
    static const uint8_t  recording_channel_number = 1; // Number of Input Mic Channels (1, 2, or 4)
    static const uint8_t  recording_bit_length = 16; // Audio Sample Bit Length (16 or 24)
    static const int32_t recording_byte_per_second = recording_sampling_rate * recording_channel_number * recording_bit_length / 8; // Bytes per Second
    static const int32_t recording_size = recording_byte_per_second * recording_time; // Total WAV File Size
    
    static void audio_attention_cb(const ErrorAttentionParam *atprm) // Called when audio internal error occurs
    {
      switch (atprm->error_code) {
        case AS_ATTENTION_CODE_INFORMATION:
        case AS_ATTENTION_CODE_WARNING:
          ErrEnd = false;
          printf("Audio_Attention_CB() info/warn code=0x%x\n", atprm->error_code);
          break;
        case AS_ATTENTION_CODE_ERROR:
        case AS_ATTENTION_CODE_FATAL:
        default:
          ErrEnd = true;
          printf("Audio_Attention_CB() error/fatal code=0x%x\n", atprm->error_code);
      }
    }
    
    void audio_setup()
    { 
      puts("audio_setup() Initializing the Audio Library...");
      theAudio = AudioClass::getInstance();
      theAudio->begin(audio_attention_cb);
    
      // Select microphone input device
      theAudio->setRecorderMode(AS_SETRECDR_STS_INPUTDEVICE_MIC_A, 210); //210 = 21.0 dB Mic Gain
      theAudio->initRecorder(AS_CODECTYPE_WAV,"/mnt/spif/BIN",recording_sampling_rate,recording_bit_length,recording_channel_number);
      puts("Setting up the Recorder...");
    
      // Open file for data write on SD card
      //wavFile = theSD.open("Sound.wav", FILE_WRITE);
      wavFile = theSD.open(String(file_count)+".wav", FILE_WRITE);
    
      /* Verify file open */
      if (!wavFile)
        {
          printf("Error opening the WAV file...");
          exit(1);
        }
    
      puts("Writing the WAV File Header...");
      theAudio->writeWavHeader(wavFile);
      puts("Start Recording");
      theAudio->startRecorder();
      puts("audio_setup() done\n");
    }
    
    void audio_loop() 
    {
      err_t errStatus; // recording end condition
      if (theAudio->getRecordingSize() > recording_size)
        {
          theAudio->stopRecorder();
          sleep(0.1);
          errStatus = theAudio->readFrames(wavFile);
          theAudio->closeOutputFile(wavFile);
          wavFile.close();
          file_count++;
          goto restartRecording;
        }
    
        errStatus = theAudio->readFrames(wavFile);  /* Read frames to record in file */
    
      if (errStatus != AUDIOLIB_ECODE_OK)
        {
          printf("File Ended! =%d\n", errStatus);
          theAudio->stopRecorder();
          goto restartRecording;
        }
    
      if (ErrEnd)
        {
          printf("Error End\n");
          theAudio->stopRecorder();
          goto exitSketch;
        }
    
      if (file_count > 10)
        {
          goto exitSketch;
        }
      return;
    
      restartRecording:
        wavFile = theSD.open(String(file_count)+".wav", FILE_WRITE);
        puts("Writing the WAV File Header...\n");
        theAudio->writeWavHeader(wavFile);
        puts("Starting the Recorder...\n");
        theAudio->startRecorder();
        puts("Next Recording Started...\n");
        return;
    
      exitSketch:
        puts("Exiting Sketch!\n");
        exit(1);
    }
    
    ////////////// MAIN SETUP() and LOOP() //////////////
    
    void main_setup() {  // put your setup code here, to run once:
      Serial.begin(115200);
      //while (!Serial) { ; } // wait for serial port to connect. Needed for native USB port only
    
      printf("main_setup() initializing logFile %s\n", logName);
    
      if (doFile)   { file_setup(); }
      if (doAudio)  { audio_setup(); }
      if (doLed)    { led_setup(); }
      if (doGnss)   { gnss_setup(); }
    
      Serial.println("\nSetup Complete\n");
    }
    
    char* time_getstring() // return pointer to date/time string
    {
      static String datetime;
      datetime = String((int)millis(), (unsigned char)DEC);
      return (char*)datetime.c_str();
    }
    
    void sampleData() {
      if (sinceSample < sampleMillis) { // check if the Sample timer has passed its interval
        return;
      }
      sinceSample = sinceSample - sampleMillis;
    
      // Sampling time has been reached, Sample the Data
      char* dataStr;
      logString = time_getstring(); // get the time string for the beginning of each line in the file
    
      if (doGnss) {
        dataStr = gnss_get_latest();
        logString += String(",") + dataStr;
      }
      
      if (doStream) {
        Serial.println(logString);
      }
      
      if (doFile) { // whether to do the data log file
        logFile = theSD.open(logName, FILE_WRITE);
        logFile.write(logString.c_str(), strlen(logString.c_str()));
        logFile.write("\r\n", 2);
        logFile.flush();
        logFile.close();
      }
    }
    
    void main_loop()
    {
      if (doAudio)  { audio_loop(); }
      if (doGnss)   { gnss_loop(); }
      if (doLed)    { led_loop(); } // Blink SPresense On-board LED
    
      sampleData();
    }
    
    void setup() { main_setup(); }
    void loop() { main_loop(); }
    
    

  • DeveloperWorld

    @m-Lewis The code that I sent you records in mp3 format for 10 seconds and then ends. That's why you don't get logs after that.

    I noticed that WAV recording and GNSS usage doesn't work on SDK 2.0 together. There is a bug. I'll try to investigate it.

    I have two solutions for now:

    1. You can use MP3 instead of WAV format. It works with SDK2.0
    2. If you want to use WAV format you can use SDK1.5.1

    Below is the code for the second solution:

    // GNSS and Audio at the same time example, while writing data to a logfile and output to Serial port
    // M. Lewis
    
    bool doAudio = true; // Record Audio
    bool doGnss = true;   // GNSS/GPS
    bool doLed = true;    // Blink LED
    bool doStream = true; // Stream sampled data lines to Serial output at Sample Rate
    bool doFile = true;   // Stream sampled data lines to logFile at Sample Rate
    
    #include <Arduino.h>
    #include <arch/board/board.h>
    #include <SDHCI.h>
    #include <File.h>
    #include <Storage.h>
    #include <elapsedMillis.h>
    #include <GNSS.h>
    #include <RTC.h> // For setting realtime clock
    #include <Audio.h>
    
    
    SDClass theSD; // This is the SD card class
    File logFile; // File object
    //char* logName = "/mnt/spif/logfile.log";
    char* logName = "logfile.log";
    String logString;
    
    elapsedMillis sinceSample;
    int sampleMillis = 1000/10; // 10 Hz
    
    ////////////// LED Control //////////////
    
    unsigned long blinkStartMS;
    #define BLINK_MS 500 // number of millisecs for on or off
    
    int blinkMillis = 1000/2;  // 2 Hz
    elapsedMillis sinceBlink;
    
    void led_setup() {
      Serial.println("led_setup()");
      pinMode(LED0, OUTPUT); // Init the on-board SPresense LEDs
      pinMode(LED1, OUTPUT);
      pinMode(LED2, OUTPUT);
      pinMode(LED3, OUTPUT);
      blinkStartMS = 0 ;
    }
    
    void led_loop() {
      static bool state = true;
      if (sinceBlink < blinkMillis) {
        return;
      }
      sinceBlink = sinceBlink - blinkMillis;
      state = ! state;
      digitalWrite(PIN_LED0, state==false ? LOW : HIGH);
    }
    
    void led_setAll(bool state)
    {
      digitalWrite(PIN_LED0, state==false ? LOW : HIGH);
      digitalWrite(PIN_LED1, state==false ? LOW : HIGH);
      digitalWrite(PIN_LED2, state==false ? LOW : HIGH);
      digitalWrite(PIN_LED3, state==false ? LOW : HIGH);
    }
    
    static void Led_isPosfix(bool state)
    {
        digitalWrite(PIN_LED1, state==false ? LOW : HIGH);
    }
    
    static void Led_isError(bool state)
    {
        digitalWrite(PIN_LED3, state==false ? LOW : HIGH);
    }
    
    
    ////////////// Log File Control //////////////
    
    void file_setup()
    {
      Serial.println("file_setup() start");
    
      //logFile = Storage.open(logName, FILE_WRITE); // Open the file. Note: only one file can be open at a time
      if (! theSD.begin()) {
        Serial.print("uSD card is not present!!");
        while(1){;}
      }
        
      logString = String("MSec");
      if (doGnss) {
        logString += ",";
        logString += gnss_get_columns();
      }
      
      logString += "\r\n";
      Serial.print(logString.c_str());
    
      logFile = theSD.open(logName, FILE_WRITE); // Open the file. Note: only one file can be open at a time
      if (!logFile) {
        Serial.print("Could not open logFile");
        return;
      }
    
      if (logFile.size() < 1) { // Empty or non-existant file. Add header line
        logFile.write(logString.c_str(), strlen(logString.c_str()));
        logFile.close(); /* Close the file */
        //logFile.flush();
      }
    }
    
    ////////////// GNSS File Control //////////////
    
    #define STRING_BUFFER_SIZE  128       /**< %Buffer size */
    #define RESTART_CYCLE       (60 * 5)  /**< positioning test term */
    
    static SpGnss Gnss;                   /**< SpGnss object */
    SpNavData NavData;
    uint32_t recordCount;
    String gnssLatestString;
    void gnss_update_latestString();
    
    const uint16_t FAULT_GPS_TIME = 0x2; // NO GPS Time and Date
    const uint16_t FAULT_GPS_FIX = 0x4; // NO GPS Location
    uint16_t gps_fault = 0;
    
    /**
     * @enum ParamSat
     * @brief Satellite system
     */
    enum ParamSat {
      eSatGps,            /**< GPS                     World wide coverage  */
      eSatGlonass,        /**< GLONASS                 World wide coverage  */
      eSatGpsSbas,        /**< GPS+SBAS                North America        */
      eSatGpsGlonass,     /**< GPS+Glonass             World wide coverage  */
      eSatGpsQz1c,        /**< GPS+QZSS_L1CA           East Asia & Oceania  */
      eSatGpsGlonassQz1c, /**< GPS+Glonass+QZSS_L1CA   East Asia & Oceania  */
      eSatGpsQz1cQz1S,    /**< GPS+QZSS_L1CA+QZSS_L1S  Japan                */
    };
    
    static enum ParamSat satType =  eSatGps; /* Set this parameter depending on your current region. */
    
    void gnss_setSatType()
    {
        /* Setup GNSS
         *  It is possible to setup up to two GNSS satellites systems.
         *  Depending on your location you can improve your accuracy by selecting different GNSS system than the GPS system.
         *  See: https://developer.sony.com/develop/spresense/developer-tools/get-started-using-nuttx/nuttx-developer-guide#_gnss
         *  for detailed information.
        */
        switch (satType)
        {
        case eSatGps:
          Gnss.select(GPS);
          break;
    
        case eSatGpsSbas:
          Gnss.select(GPS);
          Gnss.select(SBAS);
          break;
    
        case eSatGlonass:
          Gnss.select(GLONASS);
          break;
    
        case eSatGpsGlonass:
          Gnss.select(GPS);
          Gnss.select(GLONASS);
          break;
    
        case eSatGpsQz1c:
          Gnss.select(GPS);
          Gnss.select(QZ_L1CA);
          break;
    
        case eSatGpsQz1cQz1S:
          Gnss.select(GPS);
          Gnss.select(QZ_L1CA);
          Gnss.select(QZ_L1S);
          break;
    
        case eSatGpsGlonassQz1c:
        default:
          Gnss.select(GPS);
          Gnss.select(GLONASS);
          Gnss.select(QZ_L1CA);
          break;
        }
    }
    
    /**
     * @brief Activate GNSS device and start positioning.
     */
    void gnss_setup() {
      int error_flag = 0;
      recordCount = 0;
      
      puts("gnss_setup() Initializing GNSS...");
      RTC.begin(); // Initialize RTC at first
    
      gps_fault = FAULT_GPS_FIX | FAULT_GPS_TIME; // assume no GPS time or fix, show a fault
    
      sleep(3); // Wait HW initialization done
      led_setAll(true); //  Turn on all LEDs
    
      Gnss.setDebugMode(PrintInfo);
      if (Gnss.begin() != 0)
      {
        Serial.println("Gnss begin error!!");
        error_flag = 1;
      }
      else
      {
        gnss_setSatType(); // Select International Sat Systems to use
        if (Gnss.start(COLD_START) != 0) // Start positioning
        {
          Serial.println("Gnss COLD_START error!!");
          error_flag = 1;
        }
        else
        {
          Serial.println("Gnss setup OK");
        }
      }
    
      //Gnss.start1PPS(); /* Start 1PSS output to PIN_D02 */
    
      led_setAll(false); //  Turn off all LEDs
    
      if (error_flag == 1)
      {
        Led_isError(true); // Set error LED3
        exit(0);
      }
      puts("gnss_setup() done\n");
    }
    
    /**
     * @brief %Print satellite condition.
     */
    static void print_condition(SpNavData *pNavData)
    {
      char StringBuffer[STRING_BUFFER_SIZE];
      unsigned long cnt;
    
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSatellites:%2d\n", pNavData->numSatellites); // Print satellite count
      Serial.print(StringBuffer);
    
      for (cnt = 0; cnt < pNavData->numSatellites; cnt++)
      {
        const char *pType = "---";
        SpSatelliteType sattype = pNavData->getSatelliteType(cnt);
        switch (sattype) // Get satellite 3 letter string
        {
          case GPS:        pType = "GPS";        break;
          case GLONASS:    pType = "GLN";        break;
          case QZ_L1CA:    pType = "QCA";        break;
          case SBAS:       pType = "SBA";        break;
          case QZ_L1S:     pType = "Q1S";        break;
          default:         pType = "UKN";        break;
        }
    
        unsigned long Id  = pNavData->getSatelliteId(cnt);
        unsigned long Elv = pNavData->getSatelliteElevation(cnt);
        unsigned long Azm = pNavData->getSatelliteAzimuth(cnt);
        float sigLevel = pNavData->getSatelliteSignalLevel(cnt);
    
        snprintf(StringBuffer, STRING_BUFFER_SIZE, "[%2d] Type:%s, Id:%2d, Elv:%2d, Azm:%3d, CN0:", cnt, pType, Id, Elv, Azm );
        Serial.print(StringBuffer);
        Serial.println(sigLevel, 6);
      }
    }
    
    /**
     * @brief %Print position information.
     */
    static void print_pos(SpNavData *pNavData)
    {
      static int LastPrintMin = 0;
      char StringBuffer[STRING_BUFFER_SIZE];
    
      /* print time */
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "%04d/%02d/%02d ", pNavData->time.year, pNavData->time.month, pNavData->time.day);
      Serial.print(StringBuffer);
    
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "%02d:%02d:%02d.%06d, ", pNavData->time.hour, pNavData->time.minute, pNavData->time.sec, pNavData->time.usec);
      Serial.print(StringBuffer);
    
      /* print satellites count */
      snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSat:%2d, ", pNavData->numSatellites);
      Serial.print(StringBuffer);
    
      /* print position data */
      unsigned char fixMode = pNavData->posFixMode;
      switch (fixMode)
      {
        case 2:   Serial.print("2D"); break;
        case 3:   Serial.print("3D"); break;
        case 0:   // FixInvalid: //Serial.print("No-Fix, "); break;  // FixInvalid:
        default:  Serial.print("No"); break;
      }
      Serial.print("-Fix(");
      Serial.print(fixMode);
      Serial.print("), ");
      
      if (pNavData->posDataExist == 0)
      {
        Serial.print("No Position");
      }
      else
      {
        Serial.print("Lat=");
        Serial.print(pNavData->latitude, 6);
        Serial.print(", Lon=");
        Serial.print(pNavData->longitude, 6);
      }
    
      Serial.println("");
    
      if (NavData.time.minute != LastPrintMin) // Print satellite information every minute
      {
        print_condition(&NavData);
        LastPrintMin = NavData.time.minute;
      }
    }
    
    void gnss_restart()
    {
      int error_flag = 0;
    
      ledOff(PIN_LED0); // Turn off LED0
      Led_isPosfix(false); // Turn off posFix LED1
     
      if (Gnss.stop() != 0)
      {
        Serial.println("Gnss stop error!!");
        error_flag = 1;
      }
      else if (Gnss.end() != 0)
      {
        Serial.println("Gnss end error!!");
        error_flag = 1;
      }
      else
      {
        Serial.println("Gnss stop OK.");
      }
    
      if (Gnss.begin() != 0)
      {
        Serial.println("Gnss begin error!!");
        error_flag = 1;
      }
      else if (Gnss.start(HOT_START) != 0)
      {
        Serial.println("Gnss hot start error!!");
        error_flag = 1;
      }
      else
      {
        Serial.println("Gnss restart OK.");
      }
    
      if (error_flag == 1)
      {
        Led_isError(true); // Set error LED3
        exit(0);
      }
    }
    
    void gnss_update_latestString() {
    
      // Following code block was in loop()
      bool goodFix;
      int upd=Gnss.waitUpdate(0); //-1);
      if (upd) // Check update
      {
        if (upd) { recordCount++; } // New GNSS data has come in
        Gnss.getNavData(&NavData); // Get NaviData
        goodFix = NavData.posDataExist && (NavData.posFixMode != FixInvalid);
        Led_isPosfix( goodFix ); // Set posFix LED1 if there is a Fix
        print_pos(&NavData); // Print position information
      }
    
      if (!upd) {
        return;
      }
    
      //Serial.printf("secondsSinceTime()=%.3f\n", GPS.secondsSinceTime());
      gnssLatestString = "GPS,";
      if (NavData.time.hour < 10) { gnssLatestString += '0'; }
      gnssLatestString += NavData.time.hour; gnssLatestString += ':';
      if (NavData.time.minute < 10) { gnssLatestString += '0'; }
      gnssLatestString += NavData.time.minute; gnssLatestString += ':';
      if (NavData.time.sec < 10) { gnssLatestString += '0'; }
      gnssLatestString += NavData.time.sec;
    
      // handle millisecs - GPS.milliseconds can fail prior to a fix, then returns a random string
      uint16_t millisecs = NavData.time.usec / 1000;
      //Serial.printf("Millisec=%u\n", millisecs);
      if (millisecs > 1000) {millisecs = 0;}
      gnssLatestString += '.';
      if (millisecs < 10) {
        gnssLatestString += "00";
      } else if (millisecs > 9 && millisecs < 100) {
        gnssLatestString += "0";
      }
      gnssLatestString += millisecs;
      
      gnssLatestString += ",";
      gnssLatestString += NavData.time.year; gnssLatestString += '/';
      gnssLatestString += NavData.time.month;  gnssLatestString += '/';
      gnssLatestString += NavData.time.day;
    
      char fixBuf[300];
      char lat, lon;
      //lat = (!NavData.latitude) ? 'n' : NavData.latitude; // needed when never had fix since GPS.lat initialized to 0
      //lon = (!NavData.longitude) ? 'w' : NavData.longitude;
      lat = 'n';
      lon = 'w';
      
      sprintf(fixBuf, ",%.6f,%c,%.6f,%c,%.1f,%.1f,%d,%d,%lu",
        NavData.latitude, lat, NavData.longitude, lon, NavData.altitude, NavData.velocity, (int)NavData.numSatellites, NavData.posFixMode, recordCount);
      gnssLatestString += fixBuf;
    }
    
    char* gnss_get_columns() { // return the column headers
      static char buf[200] = "GPS,Time,Date,Lat_deg,N/S,Lon_deg,E/W,Alt_m,Knots,Track_deg,Sats,Fix,Rcvd";
      char* s = buf;
      return s;
    }
    
    char* gnss_get_latest() // return pointer to CSV IMU data string
    {
      gnss_update_latestString();
      gps_fault = 0;
      int status = (NavData.posDataExist && (NavData.posFixMode != FixInvalid));
      if (! NavData.posDataExist) {
        gps_fault |= FAULT_GPS_FIX;
      } else {
        //gnss_upd_rtc(); // SPresense version of RTC
      }
      return (char*)gnssLatestString.c_str();
    }
    
    bool gnss_waitUpdate(int milliSecs) { // milliSecs to wait, or -1 to not wait. Assumes setup() was already called
      bool upd = false;
      upd=Gnss.waitUpdate(milliSecs); // Check update
      return upd;
    }
    
    void gnss_loop() {} // Nothing here, GNSS is run at the much slower Sample rate. See gnss_get_latest() above
    
    ////////////// AUDIO RECORDING CONTROL //////////////
    extern SDClass theSD; // Declared in sp_main.cpp
    AudioClass *theAudio;
    File wavFile;
    int file_count = 0;
    bool ErrEnd = false;
    
    static const uint32_t recording_time = 10; // Recording Time (Seconds) per wav file
    static const uint32_t recording_sampling_rate = 48000; // Sample Rate (16000 or 48000)
    static const uint8_t  recording_channel_number = 1; // Number of Input Mic Channels (1, 2, or 4)
    static const uint8_t  recording_bit_length = 16; // Audio Sample Bit Length (16 or 24)
    static const int32_t recording_byte_per_second = recording_sampling_rate * recording_channel_number * recording_bit_length / 8; // Bytes per Second
    static const int32_t recording_size = recording_byte_per_second * recording_time; // Total WAV File Size
    
    static void audio_attention_cb(const ErrorAttentionParam *atprm) // Called when audio internal error occurs
    {
      switch (atprm->error_code) {
        case AS_ATTENTION_CODE_INFORMATION:
        case AS_ATTENTION_CODE_WARNING:
          ErrEnd = false;
          printf("Audio_Attention_CB() info/warn code=0x%x\n", atprm->error_code);
          break;
        case AS_ATTENTION_CODE_ERROR:
        case AS_ATTENTION_CODE_FATAL:
        default:
          ErrEnd = true;
          printf("Audio_Attention_CB() error/fatal code=0x%x\n", atprm->error_code);
      }
    }
    
    void audio_setup()
    { 
      puts("audio_setup() Initializing the Audio Library...");
      theAudio = AudioClass::getInstance();
      theAudio->begin(audio_attention_cb);
    
      // Select microphone input device
      theAudio->setRecorderMode(AS_SETRECDR_STS_INPUTDEVICE_MIC_A, 210); //210 = 21.0 dB Mic Gain
      theAudio->initRecorder(AS_CODECTYPE_WAV,"/mnt/spif/BIN",recording_sampling_rate,recording_bit_length,recording_channel_number);
      puts("Setting up the Recorder...");
    
      // Open file for data write on SD card
      //wavFile = theSD.open("Sound.wav", FILE_WRITE);
      wavFile = theSD.open(String(file_count)+".wav", FILE_WRITE);
    
      /* Verify file open */
      if (!wavFile)
        {
          printf("Error opening the WAV file...");
          exit(1);
        }
    
      puts("Writing the WAV File Header...");
      theAudio->writeWavHeader(wavFile);
    
      puts("audio_setup() done\n");
    }
    
    void audio_loop() 
    {
      err_t errStatus; // recording end condition
      if (theAudio->getRecordingSize() > recording_size)
        {
          theAudio->stopRecorder();
          sleep(0.1);
          errStatus = theAudio->readFrames(wavFile);
          theAudio->closeOutputFile(wavFile);
          wavFile.close();
          file_count++;
          goto restartRecording;
        }
    
        errStatus = theAudio->readFrames(wavFile);  /* Read frames to record in file */
    
      if (errStatus != AUDIOLIB_ECODE_OK)
        {
          printf("File Ended! =%d\n", errStatus);
          theAudio->stopRecorder();
          goto restartRecording;
        }
    
      if (ErrEnd)
        {
          printf("Error End\n");
          theAudio->stopRecorder();
          goto exitSketch;
        }
    
      if (file_count > 10)
        {
          goto exitSketch;
        }
      return;
    
      restartRecording:
        wavFile = theSD.open(String(file_count)+".wav", FILE_WRITE);
        puts("Writing the WAV File Header...\n");
        theAudio->writeWavHeader(wavFile);
        puts("Starting the Recorder...\n");
        theAudio->startRecorder();
        puts("Next Recording Started...\n");
        return;
    
      exitSketch:
        puts("Exiting Sketch!\n");
        exit(1);
    }
    
    ////////////// MAIN SETUP() and LOOP() //////////////
    
    void main_setup() {  // put your setup code here, to run once:
      Serial.begin(115200);
      //while (!Serial) { ; } // wait for serial port to connect. Needed for native USB port only
    
      printf("main_setup() initializing logFile %s\n", logName);
    
      if (doFile)   { file_setup(); }
      if (doAudio)  { audio_setup(); }
      if (doLed)    { led_setup(); }
      if (doGnss)   { gnss_setup(); }
    
      puts("Start Recording");
      theAudio->startRecorder();
    
      Serial.println("\nSetup Complete\n");
    }
    
    char* time_getstring() // return pointer to date/time string
    {
      static String datetime;
      datetime = String((int)millis(), (unsigned char)DEC);
      return (char*)datetime.c_str();
    }
    
    void sampleData() {
      if (sinceSample < sampleMillis) { // check if the Sample timer has passed its interval
        return;
      }
      sinceSample = sinceSample - sampleMillis;
    
      // Sampling time has been reached, Sample the Data
      char* dataStr;
      logString = time_getstring(); // get the time string for the beginning of each line in the file
    
      if (doGnss) {
        dataStr = gnss_get_latest();
        logString += String(",") + dataStr;
      }
      
      if (doStream) {
        Serial.println(logString);
      }
      
      if (doFile) { // whether to do the data log file
        logFile = theSD.open(logName, FILE_WRITE);
        logFile.write(logString.c_str(), strlen(logString.c_str()));
        logFile.write("\r\n", 2);
        logFile.flush();
        logFile.close();
      }
    }
    
    void main_loop()
    {
      if (doAudio)  { audio_loop(); }
      if (doGnss)   { gnss_loop(); }
      if (doLed)    { led_loop(); } // Blink SPresense On-board LED
    
      sampleData();
    }
    
    void setup() { main_setup(); }
    void loop() { main_loop(); }
    

    Let me know if it works.

    Best Regards,
    Kamil Tomaszewski



  • Kamil,
    I used the difference in your source in SDK 2.0:

    • Move 'theAudio->startRecorder(); to the end of the main setup(), after everything else is setup.
    • Use MP3 instead of WAV.

    It works. Thank you!
    I still prefer to record .WAV files. Will you continue to look for the bugFix, and could you please let me know when it works.
    Thank you again
    M.Lewis


Log in to reply