Strange Serial Responses from Rockblock MK2 Iridium Module.

Hello,

I am currently developing a flight computer to run on a high altitude balloon, all based around the Arduino Nano 328P (using old bootloader). However, after days of debugging, I am still turning up a head-scratching bug that I have zero clue where is originating from.

The principle of the code that is causing problems is sending AT commands to a Rockblock MK2 hooked up over software serial to Dig. pins 8 and 9. Upon sending, the response is put into a method, stripped of any control characters (newline, carriage return, etc.) and only A-Z 0-9 and symbols are returned. However, the function only works part of the time. The problem I am seeing now is 0’s (null characters) being returned whenever I collect everything in the serial buffer and put it into a string. I’ve attached the code that is relevant, as well as the console output I am seeing.

I have suspicions it may be memory problems, faulty serial bus cables, grounding issues, unsteady power source, etc. but I am entirely unsure. The complete program currently uses 56% of program storage space, and only 37% dynamic memory.

Thanks for helping out!

#include <SoftwareSerial.h>

#define IRIDIUM_MODEM_TRANSMIT      8
#define IRIDIUM_MODEM_RECEIVE       9
SoftwareSerial iridium_modem(IRIDIUM_MODEM_RECEIVE,IRIDIUM_MODEM_TRANSMIT);

void setup() {
  Serial.begin(9600);
  iridium_modem.begin(19200);
}

void loop() {
bool success = doTransmitReceiveCycle();
Serial.println("Transmit Cycle finished with status " + String(success));
delay(5000);
}

bool doTransmitReceiveCycle() {
String tempResponseStr;
Serial.println(F("Starting Up & Preflushing..."));
flushIridiumBuffer();
delay(100);

Serial.println(F("Check Connectivity..."));
tempResponseStr = issueATCommand("AT\r", 1000);
if(!tempResponseStr.equals("OK")) {
  return false;
}
delay(2000);

Serial.println(F("Disable Flow Control..."));
tempResponseStr = issueATCommand("AT&K0\r", 1000);
if(!tempResponseStr.equals("OK")) {
  return false;
}

delay(2000);

Serial.println(F("Set Outbound Message..."));
tempResponseStr = issueATCommand("AT+SBDWT=test message\r", 1000);
if(!tempResponseStr.equals("OK")) {
  return false;
}
delay(2000);

Serial.println(F("Initiating Satellite Connection..."));
tempResponseStr = issueATCommand("AT+SBDIX\r", 20000);
Serial.println("Connection Result: " + tempResponseStr);


return true;
}

String issueATCommand(char* command, int response_wait) {
flushIridiumBuffer();
 iridium_modem.write(command);
   delay(response_wait);
  String resp = "";

while(iridium_modem.available()) {
   char inputChar = (char)iridium_modem.read();
   Serial.println((int)inputChar);
     if((int)inputChar >= 32 && (int)inputChar <= 94) {
          
    resp+=inputChar;
   }

}
   return resp; 

}

void flushIridiumBuffer() {
  String flushChars = "";
  while (iridium_modem.available() > 0) {
  flushChars += (char)iridium_modem.read();
}
    Serial.println("Flushed " + flushChars);

}

Console Output attached as image.

Update: The complete INO files are in the zip file attached.

JagSatFlightware.zip (3.46 KB)

Strings are to be avoided on AVR-based Arduinos, as they cause memory problems and program crashes. Crashes are unpredictable, and even if you get your code to work on the bench, by Murphy's Law you can be completely confident that it will fail during a balloon flight.

I suggest to get rid of all the Strings and rewrite the code using C-strings (zero terminated character arrays) and the C-string utilities. If used properly, they are 100% reliable.

As additional insurance, where offered, be sure use the "n" versions of the functions, e.g. strncpy(), strncmp(), snprintf(), etc.

Thanks for your reply. I’ve updated the code segment for communication between the arduino and RockBLOCK using CStrings and it appears to be working now. Just to confirm - is this the correct implementation of them? Software hardness and ensuring crashes related to simple things don’t happen is important :).

#include <SoftwareSerial.h>

#define IRIDIUM_MODEM_TRANSMIT      8
#define IRIDIUM_MODEM_RECEIVE       9
SoftwareSerial iridium_modem(IRIDIUM_MODEM_RECEIVE,IRIDIUM_MODEM_TRANSMIT);

char iridRxData[200];

void setup() {
  Serial.begin(9600);
  iridium_modem.begin(19200);
}

void loop() {

doTransmitReceiveCycle();
 delay(7000);

}

void doTransmitReceiveCycle() {
Serial.println(F("Starting Up..."));
  
 sendATCommand("AT\r", 250);

  Serial.print(F("Connection Check CString is: "));
 Serial.println(iridRxData);

 delay(2000);

 sendATCommand("AT&K0\r", 250);

 Serial.print(F("Flow Control CString is: "));
 Serial.println(iridRxData);

 delay(2000);

 sendATCommand("AT+SBDWT=test message\r", 250);

 Serial.print(F("Message Set CString is: "));
 Serial.println(iridRxData);

  delay(2000);

 sendATCommand("AT+SBDIX\r", 16000);

 Serial.print(F("Message Transmit CString is: "));
 Serial.println(iridRxData);
}


void sendATCommand(char transmission[], int rx_delay_time) {
 flushIridiumBuffer();
 flushCommandReceiveBuffer();
 iridium_modem.write(transmission);
 delay(rx_delay_time);
 int next = 0;
 while(iridium_modem.available()) {
 char inChar = iridium_modem.read();

if((int)inChar >= 32 && (int)inChar <= 94) {
        iridRxData[next++] = inChar;

   }
          Serial.print(F("In char is "));
          Serial.println((int)inChar);  
 }
 iridRxData[next++] = NULL;

}

void flushCommandReceiveBuffer() {
  for(int i = 0; i < 200; i++) {
    iridRxData[i] = NULL;
  }
  Serial.println(F("Command Container Buffer Flushed"));
}

void flushIridiumBuffer() {
  int iters = 0;
  while (iridium_modem.available() > 0) {
  iridium_modem.read();
  iters++;
}
Serial.print(F("Buffer Flush Complete. Removed ="));
Serial.println(iters);
}

Look much better! However I see a couple of issues, two minor and one major:

if((int)inChar >= 32 && (int)inChar <= 94) {
        iridRxData[next++] = inChar;
  1. no reason for the (int) cast

  2. you do NOT check for buffer overflow. You must make absolutely certain that next does not go out of bounds, or you will overwrite memory that you do not own. This is the very best way to crash an Arduino.

  3. Avoid use of delay() if at all possible. The MCU does nothing else while delaying.

Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

...R