How to integrate SODAQ Universal Tracker v2 with Rockblock?

I am trying to use this universal tracker with the Iridium Rockblock. I have tried the the BasicSend and SendReceive examples with the SODAQ One v2 device, and they work perfectly. However, when I try to insert this same functionality into the transmit() function in the Universal Tracker, it hangs at the isbd.sendReceiveSBDBinary function.

I added the global variables:
int sleep_pin = 10;
IridiumSBD isbd(Serial, sleep_pin);

In the setup loop I added:

Serial.begin(19200);

if (DEBUG)
{
    isbd.attachConsole(SerialUSB);
    isbd.attachDiags(SerialUSB);
}
In the transmit function I added:
if (SENDRECEIVE) {

    debugPrintln("SENDRECEIVE");
    debugPrintln("Will wake up Rockblock");
    isbd.begin();
    debugPrintln("Done waking up Rockblock");

    isbd.useMSSTMWorkaround(false);
    isbd.setPowerProfile(1);
    isbd.setMinimumSignalQuality(1);
    int signalQuality = -1; //placeholder for signalQuality
    
    

    isbd.setPowerProfile(1); //low power application

    int err = isbd.getSignalQuality(signalQuality);
    
    if (err != 0)
    {
        debugPrint("SignalQuality failed: error ");
        debugPrintln(err);
        return;
    }

    debugPrint("Signal quality is ");
    debugPrintln(signalQuality);
    
    // uint8_t buffer[200] = 
    // { latitude, longitude, altitude };

    uint8_t buffer[200];

    size_t bufferSize = sizeof(sendBuffer);
    err = isbd.sendReceiveSBDBinary(buffer, 20, sendBuffer, bufferSize);

    if (err != 0)
    {
        debugPrint("sendReceiveSBDText failed: error ");
        debugPrintln(err);
        return;
    }

    debugPrint("Inbound buffer size is ");
    debugPrintln(bufferSize);
    for (int i=0; i<bufferSize; ++i)
    {
        SerialUSB.write(buffer[i]);
        debugPrint("(");
        SerialUSB.print(buffer[i], HEX);
        debugPrint(") ");
    }
    debugPrint("Messages left: ");
    debugPrintln(isbd.getWaitingMessageCount());

    isbd.sleep();
}

I have attached a file that shows the output log of when I run this on my SODAQ. Even though in this case the signal quality is 0, I had these same issues when the signal quality was higher.

I have also opened up a github issue for this: https://github.com/SodaqMoja/SodaqOne-UniversalTracker-v2/issues/6

I would really appreciate some assistance! I do not know what is going wrong.

Can you try to get a CSQ of atleast 10 before sending?

Value	RSSI dBm	Condition
2	-109	Marginal
3	-107	Marginal
4	-105	Marginal
5	-103	Marginal
6	-101	Marginal
7	-99	Marginal
8	-97	Marginal
9	-95	Marginal
10	-93	OK
11	-91	OK
12	-89	OK
13	-87	OK
14	-85	OK
15	-83	Good
16	-81	Good
17	-79	Good
18	-77	Good
19	-75	Good
20	-73	Excellent
21	-71	Excellent
22	-69	Excellent
23	-67	Excellent
24	-65	Excellent
25	-63	Excellent
26	-61	Excellent
27	-59	Excellent
28	-57	Excellent
29	-55	Excellent
30	-53	Excellent

Hi Jan,

The thing is , when I try the Basic SendReceive test, everything works with a CSQ of 5. Is it possible that the SODAQ Universal Tracker disables some pins such as the RX/TX pins? In addition, waking up the Rockblock requires the use of a sleep pin (I am using D10). The Rockblock seems to work fine with the SODAQ when I use other code.

Thanks!

I also tried to change the buffer I am sending to:
uint8_t buffer[200] =
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };

I then ended up getting these error messages:

Will wake up Rockblock
Calling internalBegin
Powering on RockBLOCK...!
>> AT

Waiting for response OK

<< AT

OK
>> ATE1

Waiting for response OK

<< ATE1

OK
>> AT&D0

Waiting for response OK

<< AT&D0

OK
>> AT&K0

Waiting for response OK

<< AT&K0

OK
InternalBegin: success!
Done waking up Rockblock
>> AT+CSQ

Waiting for response OK

<< AT+CSQ

+CSQ:5

OK
Signal quality is 5
internalSendReceive
>> AT+SBDWB=20

Waiting for response READY

<< AT+SBDWB=20

READY
[ bytes]Checksum:210
Waiting for response 0

OK

<< 
0

OK
>> AT+CSQ

Waiting for response OK

<< AT+CSQ

+CSQ:5

OK
>> AT+SBDIX

Waiting for response OK

<< AT+SBDIX

This time it gets stuck at AT+SBDIX ^.

Hi,

I see that sparkfun has a lot of documentation about the rockblock module. Maybe you can solve the issue with any of these documents.

And in the AT commandsheet I see that not all modules support AT+SBDIX.
What module do you use?

Regards,
Jan

Hi Jan,

I do not believe there is an issue with the Rockblock, as I was able to send messages successfully using it with the SODAQ.

However, after doing some further digging, I found that the places the Iridium library failed were where it used millis(). This is why the code hangs at certain points. I believe it has to do with the watchdog timer that the Universal Tracker has implemented.

I tried to mitigate the issue by changing one function:

bool IridiumSBD::smartWait(int seconds)
{
   // for (unsigned long start=millis(); millis() - start < 1000UL * seconds;)
   //    if (cancelled())
   //       return false;
   sodaq_wdt_safe_delay(1000UL*seconds);
   return true;
}

This helped stop hanging in one spot, but because the use of millis() is present throughout IridiumSBD.cpp, the code now starts hanging in other places. Do you have any ideas on how I could mitigate these errors?

Thanks

Hi,

It is correct when you enable a watchdog and you don’t reset it in time, the watchdog will reset the board.
You can safely change all delay(x) by sodaq_wdt_safe_delay(x).

To use the for loop and have a watchdog enabled you need to reset the watchdogtimer
sodaq_wdt_reset(); or sodaq_wdt_safe_delay(x);

for (unsigned long start=millis(); millis() - start < 1000UL * seconds;)
sodaq_wdt_reset();
if (cancelled())
return false;

If this doen’t solve your problem can you send me your Github link or upload your code and used libraries in a zip here?
Then I can have a quick look to see if I have a solution for you.

Regards,
Jan

I have had a look at the IridiumSBD library, and there are multiple points which could trigger the watch dog timer (WDT). These are mainly a sort of wait for response loop.

Since you are using the SerialUSB for the debug output, it is likely that the reset is appearing as a freeze. This is due to the SerialUSB connection being reset when the board is reset (by the WDT).

When the tracker starts up it should show the cause of the most recent reset. However, if you are using SerialUSB for the output, this is usually missed as the connection is closed when the board is reset.

I would normally recommend using another UART for debug. However, this might be difficult as the Roadblock device is using the only externally available UART one the SodaqOne. (It is possible to add another UART mapping if required, but this will take some modification of the board description files.)

If you can find a terminal emulator which will automatically attempt to reopen a closed connection (if such exists), you should be able to catch the cause of the reset and confirm that it is the WDT.

I am going to create a WDT compliant version of the Roadblock library. However, at least initially, I won’t be able to test it directly myself. I may need your help in testing out the changes.

Is this the library you are using: https://github.com/mikalhart/IridiumSBD

Hi Gabriel!

I understand. I can look for this terminal emulator, but I would definitely appreciate if you could help with the library refactoring process.

I will definitely be able to test any code that you post! How long do you think it will take you to create a WDT compliant version of the Roadblock library?

If you would like, once we start testing the compliant version of the library, we can talk on the phone or google hangouts to sort out any issues. Feel free to reach out to me at divyab@veerum.com.

Yes that is the library I am using. I really appreciate your support!

Thank you for the input! In a similar sense, I was able to solve the problem by adding sodaq_wdt_reset() to the Iridium callback function in the ino file.

bool ISBDCallback()
{
    sodaq_wdt_reset();
    return true;
}

Thanks!

Yeah that should work perfectly.

My only concern is with the power(…) method where it calls up to a two second delay. This could in theory trigger a WDT on a shorter period (the tracker uses an 8s period).

Which power method are you referring to?

in IridiumSBD.cpp the function IridiumSBD::power(bool on), specifically line 629.

Probably best to swap delay(x) for smartWait(x) as this uses the same call back functionality. The call back functionality is designed to give you the opportunity to cancel any of the sequences, if required.

If you swap those methods directly, then there is no issue with the cancellation functionality as the result of smartWait(x), here, will be ignored.

1 Like

Hi Gabriel!

Thank you for pointing this out. I implemented this change, but I am still seeing an issue where the Rockblock fails to wake up every 2nd time the transmit function is called. I have mitigated this issue by implementing a simple retry, but I would love if you could help me get to the root of this issue.

Thanks!

What is the sequence of commands that you use to wake the device and then transmit?

This is the sequence of commands I use to wake the device and transmit for the Rockblock:

bool sendReceiveSBDBinary()
{

	debugPrintln("SENDRECEIVE");
	debugPrintln("Will wake up Rockblock");
	isbd.begin();
	debugPrintln("Done waking up Rockblock");

	isbd.useMSSTMWorkaround(false);
	isbd.setPowerProfile(1);
	isbd.setMinimumSignalQuality(1);
	int signalQuality = -1; //placeholder for signalQuality

	int err = isbd.getSignalQuality(signalQuality);
	if (err != 0)
	{
		debugPrint("SignalQuality failed: error ");
		debugPrintln(err);
		// if (err == 10)
		//     rockblock_wake = false;
		return false;
	}
	debugPrint("Signal quality is ");
	debugPrintln(signalQuality);

	//uint8_t rx_Buffer[200]; //buffer for receive

	//TODO: Add rx_Buffer if it is going to be different than lora receiveBuffer
	size_t rx_BufferSize = sizeof(receiveBuffer);

	//TODO: Add tx_Buffer if it is going to be different than lora sendBuffer
	size_t tx_BufferSize = sizeof(sendBuffer);

	err = isbd.sendReceiveSBDBinary(sendBuffer, tx_BufferSize, receiveBuffer, rx_BufferSize);

	if (err != 0)
	{
		debugPrint("sendReceiveSBDText failed: error ");
		debugPrintln(err);
		return true;
	}

	debugPrint("Inbound buffer size is ");
	debugPrintln(rx_BufferSize);
	for (int i = 0; i < rx_BufferSize; ++i)
	{
		SerialUSB.write(receiveBuffer[i]);
		debugPrint("(");
		SerialUSB.print(receiveBuffer[i], HEX);
		debugPrint(") ");
	}
	debugPrint("Messages left: ");
	debugPrintln(isbd.getWaitingMessageCount());
	//rockblock_wake = true;
	isbd.sleep();
	return true;
}

Thanks!

What debug messages do you see when it fails to wake up?

The internalBegin() function will either output “No modem detected.” or “InternalBegin: success!”.

If you are seeing the success message, and reordering some of the instructions seemed to help, it may be that the device requires a longer delay to wake up.

These are the debug messages I get when it fails every 2nd time:

SENDRECEIVE
Will wake up Rockblock
Calling internalBegin
Powering off RockBLOCK...!
Done waking up Rockblock
SignalQuality failed: error 10

Hi Gabriel,

It actually seems like the problem was that I wasn’t calling isbd.sleep() before all returns. It works now.

Thanks!