Hi, i have an issue with the CRC16-CCITT calculation of a telemetry string. I have a string of telemetry that im transmitting to a receiver, that acts as a gateway to an online hub which requires a CRC checksum, the checksum is favourably the CRC16-CCITT algorithm. I have been halted by this final hurdle and would appreciate any help. Please see below the code i have used.... I am not a professional software engineer so apologies for any obvious mistakes.
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <SPI.h>
#include <LoRa.h>
#include <SD.h>
#include <OneWire.h>
#include <util/crc16.h>
static const int RXPin = 7, TXPin = 6;
const int chipSelect = 4;
int sensorPin = 6;
int counter = 0;
String telemetry;
char telemetry_copy[100];
#define GPS_BAUD 9600
#define gpsPort ssGPS
OneWire ds(8);
TinyGPSPlus tinyGPS;
SoftwareSerial ssGPS(RXPin, TXPin);
void setup()
{
pinMode(9, OUTPUT);
Serial.begin(9600);
gpsPort.begin(GPS_BAUD);
// ****** LoRa Module Check ******
if (!LoRa.begin(433.525E6)){
Serial.println("Starting LoRa failed!");}
// ****** SD Card Module Check ******
if (!SD.begin(chipSelect)){
Serial.println("SD Card failed, or not present");}
// ****** LoRa Module Settings ******
// LoRa.setSPIFrequency(6);
LoRa.setTxPower(17); // 2-17
LoRa.setSpreadingFactor(11); //6-12
LoRa.setCodingRate4(8); //5-8
LoRa.setSignalBandwidth(62.5E3); //7.8E3, 10.4E3, 15.6E3, 20.8E3, 31.25E3, 41.7E3, 62.5E3, 125E3, and 250E3.
/// ****** Prepare SD Card File ******
File Data = SD.open("Data.txt", FILE_WRITE);
Data.println("HAB ID, Counter, Time, Lat, Long, Altitude, Sats, Int Temp, Ext Temp");
Data.close();
/// *** Buzzer Confirm Setup ***
delay(200);
tone(9, 2000);
delay(100);
noTone(9);
delay(50);
tone(9, 2000);
delay(100);
noTone(9);
}
// ****** CRC Checksum ******
uint16_t gps_CRC16_checksum (char *string)
{
size_t i;
uint16_t crc;
uint8_t c;
crc = 0xFFFF;
// Calculate checksum ignoring the first two $s
for (i = 2; i < strlen(string); i++)
{
c = string[i];
crc = _crc_xmodem_update (crc, c);
}
return crc;
}
void loop()
{
Main();
SmartDelay(20000);
}
void Main()
{
// ****** Temperature Sensor ****** Bus Upto 50 Sensors ******
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius;
if ( !ds.search(addr)) {
ds.reset_search();
return; }
ds.reset();
ds.select(addr);
delay(1000);
ds.write(0x44, 1);
delay(1000);
present = ds.reset();
ds.select(addr);
ds.write(0xBE);
// ****** Internal Temperaure Data Conversion to Celcius ******
for ( i = 0; i < 9; i++) {
data[i] = ds.read(); }
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3;
if (data[7] == 0x10) {
raw = (raw & 0xFFF0) + 12 - data[6]; } }
else {
byte cfg = (data[4] & 0x60);
if (cfg == 0x00) raw = raw & ~7;
else if (cfg == 0x20) raw = raw & ~3;
else if (cfg == 0x40) raw = raw & ~1; }
celsius = (float)raw / 16.0;
// ****** External Temperature Sensor ******
delay(500);
int reading = analogRead(sensorPin);
float voltage = reading * 5.0; //Reference voltage 5.0 for pefect 5v line
voltage /= 1024.0;
float temperatureC = (voltage - 0.5) * 100;
// ***** String Edit ******
float latt = (tinyGPS.location.lat());
float lngg = (tinyGPS.location.lng());
float alt = (tinyGPS.altitude.meters());
String telemetry = "$CornOnTheBranch,";
telemetry += counter; telemetry += ",";
if (tinyGPS.time.hour() < 10) telemetry += "0";
telemetry += (tinyGPS.time.hour());
telemetry += ":";
if (tinyGPS.time.minute() < 10) telemetry += "0";
telemetry += (tinyGPS.time.minute());
telemetry += ":";
if (tinyGPS.time.second() < 10) telemetry += "0";
telemetry += (tinyGPS.time.second());
telemetry += ",";
telemetry += String(latt, 6); telemetry += ",";
telemetry += String(lngg, 6); telemetry += ",";
telemetry += String(alt, 1); telemetry += ",";
telemetry += (tinyGPS.satellites.value()); telemetry += ",";
telemetry += celsius; telemetry += ",";
telemetry += temperatureC;
telemetry += "*";
telemetry.toCharArray(telemetry_copy, 100);
// *********** Debug **************
Serial.println(telemetry);
Serial.println(telemetry_copy);
Serial.println(gps_CRC16_checksum(telemetry_copy), HEX);
// ****** Transmit Packet ******
LoRa.beginPacket();
LoRa.print(telemetry);
LoRa.println(gps_CRC16_checksum(telemetry_copy), HEX);
LoRa.endPacket();
// ****** Buzzer Confirm ******
tone(9, 2000);
delay(100);
noTone(9);
delay(500);
// ****** Save To SD Card ******
File Data = SD.open("Data.txt", FILE_WRITE);
if (Data) {
Data.println(telemetry);
Data.close(); }
delay(500);
// ****** Plus 1 to Counter ******
counter++;
}
// ****** Timing ******
static void SmartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (gpsPort.available())
tinyGPS.encode(gpsPort.read());
} while (millis() - start < ms);
}
The telemetry is successfully received and uploaded to the online hub, i would like confirmation from someone more experienced that the checksum calculated is correct(or)incorrect and maybe some guidance as to how to rectify this issue. Below is an example of the first loop output via serial monitor of the String, CharArray and calculated checksum in that order. This loop was whilst the tracker was inside a building so im not concerned about the GPS data not being there, I have many hours of successful data logging behind this build already.
$CornOnTheBranch,0,00:00:00,0.000000,0.000000,0.0,0,27.38,25.68*
$CornOnTheBranch,0,00:00:00,0.000000,0.000000,0.0,0,27.38,25.68*
E31E
I have visited...
https://www.scadacore.com/tools/programming-calculators/online-checksum-calculator/
...and inputting the same string results with the following... (I attempted to put this into a code box but wouldnt behave!)
CRC-16-CCITT
Generator Type Big Endian (ABCD) Little Endian (DCBA)
Normal 0x1021 20 19 19 20
Reversed 0x8408 8E 7B 7B 8E
Reversed Reciprocal 0x8810 24 B4 B4 24
FYI the telemetry consists of the following data....
$HAB name,packet count,time,lat,long,altitude,satalites,internal temp,external temp*
I am receiving errors from the Hub as follows,
'Exception in UKHAS main parse: ValueError: Invalid CRC16-CCITT checksum'
I understand this could be a question for the Hub. But i would still appreciate pointers into better understanding what im doing wrong, as im completely stuck!
Guidelines of the required checksum can be found at the following link...
http://habitat.readthedocs.io/en/latest/ukhas_parser.html#checksum-algorithms
Thankyou for any advice in advance,
Best regards, L
P.S Im using an Arduino Nano 328, im not sure if the other hardware is relevant as i have the various modules all working as expected and already spent time range testing and parsing NMEA data all successfully. However further details can be provided if required.