Decoding raw data to display in serial monitor? How to incorporate calculations?

Hello All,

I am new to arduino and coding and I have had some help from people on this forum already and i am very grateful, so here is an outline of my project so far:

I have a geiger counter that has a port on the side that outputs RS232-esque data (not true RS232) giving information about device name, dose rate and units of measurement. I am attempting to make a data logger that will take this data, convert it into a readable format, add GPS and log it to an SD card as a CSV for later review on a laptop and mapping software.

My plan is to

  • get the meter communicating with the arduino correctly and displaying in the serial monitor (achieved with software serial)

  • get the data from the meter decoding correctly into human readable format in the serial monitor (not achieved!)

  • get a GPS module and attaching the GPS data to the data received from the geiger counter (no where near achieved!)

  • get the whole lot logging to an SD card as a CSV comma file that can be opened in excel, or google maps etc

The manufacturer has been helpful and given me data and details on the device. So far i have been helped to get the data displaying on the serial monitor correctly, as raw data. The thread is here Serial Data received from Commercial Geiger Counter - feasible arduino logger? - Project Guidance - Arduino Forum

The code used to do this is below

#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3, true); // RX, TX, invert signal //connect Automess GND and TERM to GND and Pin 2 - RS232 - TTL Converter not needed

const unsigned long delayBetweenPackets = 1000u; //packet spacing in milliSeconds
const byte bytesInPacket = 5;
byte receivedBytes[bytesInPacket]; //changed data type to byte from char as byte is unsigned integer

boolean newData = false;

void setup() {
  Serial.begin(9600); //arduino to IDE monitor can be different baud rate than automess to arduino
  mySerial.begin(4800);
  Serial.println("<Automess Ready>");
}

void loop() {
  recvWithStartMarker();
  showNewData();
}

void recvWithStartMarker() {
  static unsigned long lastByteReceived = 0;
  unsigned long currentByteReceived;
  static boolean recvInProgress = false;
  static byte ndx = 0;
  byte startMarker = 0x02;// ASCII STX Start of Text
  byte rb;

  while (mySerial.available() > 0 && newData == false) {
    rb = mySerial.read();
    currentByteReceived = millis();
    if ((currentByteReceived - lastByteReceived) > (delayBetweenPackets / 2)) {
      //resync input if packet is not completed within allotted time
      recvInProgress = false;
      ndx = 0;
    }
    if (recvInProgress == true) {
      receivedBytes[ndx] = rb;
      ndx++;
      if (ndx == bytesInPacket) {
        recvInProgress = false;
        ndx = 0;
        byte checksum = 0;
        for (byte i = 0; i < bytesInPacket; i++) {
          checksum ^= receivedBytes[i];
        }
        if (checksum == 0) {
          newData = true;
          Serial.println(F("Receiving"));
        } else {
          Serial.println(F("Checksum Error"));
        }
      }
    } else {
      if (rb == startMarker) {
        recvInProgress = true;
      }
    }
    lastByteReceived = currentByteReceived;
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print(F("Data Received:"));
    for (byte i = 0; i < bytesInPacket; i++) {
      Serial.print(' ');
      Serial.print((receivedBytes[i] >> 4) & 0x0F, HEX);
      Serial.print(receivedBytes[i] & 0x0F, HEX);
    }
    Serial.println();
    newData = false;
  }
}

which works really well for displaying the correct format of data, in terms of raw data, in the serial monitor.

I sent screen grabs to the manufacturer who confirmed that the data is being received correctly, and they sent me some QBASIC code so that the data could be decoded, this is the QBASIC code below

' Variable Types 
DEFINT A-W
DEFSNG X-Z
' Constant Expressions 
CONST STX = 2 
CONST DEVERR = 57 
'--------------------------------------------------------------------- 
'Main Program '--------------------------------------------------------------------- 
' Open COM: 4800 Bd, no parity, 8 data bits, 1 stop, no handshake ' OPEN "com1:4800,n,8,1,rs,cs,ds,cd" FOR INPUT AS #1
ON ERROR GOTO RecvErr
' Main Loop: read and decode string (6 characters including STX), 
'  display result, exit on any key. 
MainLoop:
DO
WHILE ASC(INPUT$(1, #1)) <> STX: WEND 'wait for STX
sonde = ASC(INPUT$(1, #1)) 'type of detector/6150AD
bc = sonde
mantlo = ASC(INPUT$(1, #1)) 'low order mantissa
bc = bc XOR mantlo
manthi = ASC(INPUT$(1, #1)) 'high order mantissa
bc = bc XOR manthi
expon = ASC(INPUT$(1, #1)) 'exponent
bc = bc XOR expon
IF expon > 127 THEN expon = expon - 256 
bc = bc XOR ASC(INPUT$(1, #1)) 'block check
IF bc <> 0 THEN ERROR DEVERR 'block check error
mant = manthi * 256 + mantlo '16 bit mantissa
xdl=mant*2 ^ (expon - 15) 'dose rate as floating point number
GOSUB GetProbe 'set ger$, det$ and unit$
PRINT TIME$; " Device: 6150"; ger$; " Detector: "; det$;
PRINT USING " Reading=########.### "; xdl;
PRINT unit$ 
LOOP WHILE LEN(INKEY$) = 0 'exit on any key
PRINT "End."
END 
'--------------------------------------------------------------------- 
'set ger$ / det$ / unit$ according to 'sonde' '--------------------------------------------------------------------- 
GetProbe:
flag$ = ""
IF sonde >= 128 THEN flag$ = "/E": sonde = sonde - 128
ger$ = "AD2/4/6" + flag$
IF sonde >= 64 THEN ger$ = "AD1/3/5" + flag$: sonde = sonde - 64 
det$ = "unknown"
unit$ = "μSv/h"
SELECT CASE sonde 
CASE 0
det$ = "Probe AD-0"
unit$ = "cps" 
CASE 7
det$ = "Probe AD-b"
CASE 15
det$ = "Probe AD-15"
CASE 17 
det$ = "Probe AD-17"
unit$ = "cps" 
CASE 18 
det$ = "Probe AD-18"
CASE 19 
det$ = "Probe AD-19" 
unit$ = "cps" 
CASE 20 
det$ = "internal GM"
CASE 21
det$ = "AD-t low DR"
CASE 22 
det$ = "AD-t high DR"
END SELECT 
RETURN
' --------------------------------------------------------------------- 
' Handler for transmission errors
' --------------------------------------------------------------------- 
RecvErr:
IF ERR = DEVERR THEN PRINT TIME$; " Transmission Error": RESUME MainLoop 
ON ERROR GOTO 0

A friend re-wrote it for me in C (as thats beyond me), see below

void AutomessHandler(char* AMSTRING){
         int MHI, MLO;
         double MANT,DL, EXP1;
         //float     EXP1 ;

             // Data From Automess.
           MLO = AMSTRING[2] ;
           MHI = AMstring[3] ;
           EXP1 = AMstring[4];
           DL = 0;
           MANT = 0;
           Check = 0;
           ChecksumGood = 0;

           if(EXP1 > 127){
            EXP1 = EXP1 - 256;
           }
           MANT = (MHI * 256) + MLO;

           EXP1 = EXP1 - 15;

           DL = MANT * pow(2.0,EXP1);
       
           AUTOMESSUSV = DL;

           for(i=0;i<4;i++){
            Check = Check ^ AMSTRING[1+i];   //EXOR up all bytes
           }
           if(check == AMSTRING[5]){         //Compare to Checksum
            Checksumgood = 1;
           }



}

So my issue is i have no idea how to incorporate the code to decode the raw data from the geiger counter into the sketch that displays the raw data on the serial monitor so that i can read in clear text the output from the geiger counter. I would really appreciate any help. I have tried following guides on designing sketches, writing C and so on but am unsure how to proceed....

I have also attached a file that lists the manufacturers communication protocols, in case thats of use.

thank you for reading

Ed

ADBUCHSE.pdf (132 KB)

So my issue is i have no idea how to incorporate the code to decode the raw data from the geiger counter into the sketch that displays the raw data on the serial monitor so that i can read in clear text the output from the geiger counter.

perhaps the only thing missing from AutomessHandler() you posted is that it returns a value. The code below shows how the calculations were made and avoids using pow(). remove the printf s on the Arduino (you can add code to test the checksum)

#define LSB 2
#define MSB 3
#define EXP 4

float
geigerDecode (
    uint8_t *buf,
    int      nByte )
{
    printf ("   %s:", __func__);

    for (int i = 0; i < nByte; i++)
        printf (" %02x", buf [i]);

    int8_t exp  = buf [EXP];
    float  val  = ((buf [MSB] << 8) | buf [LSB]);

    printf (" %6.0f", val);
    printf (" %4d",   exp);

    if (exp < 0)
        val /= 1 << -exp;
    else
        val *= 1 << exp;

    printf (" %8.2f", val);
    printf ("\n");

    return val;
}

the above code produced the following from the measurements in the other thread

geigerDecode: 02 14 e2 55 fe 5d  21986   -2  5496.50
geigerDecode: 02 14 32 53 fe 8b  21298   -2  5324.50
geigerDecode: 02 14 98 50 fe 22  20632   -2  5158.00
geigerDecode: 02 14 13 4e fe b7  19987   -2  4996.75
geigerDecode: 02 14 a2 4b fe 03  19362   -2  4840.50
geigerDecode: 02 14 44 49 fe e7  18756   -2  4689.00
geigerDecode: 02 14 f9 46 fe 55  18169   -2  4542.25
geigerDecode: 02 14 c1 44 fe 6f  17601   -2  4400.25
geigerDecode: 02 14 9b 42 fe 33  17051   -2  4262.75
geigerDecode: 02 14 85 40 fe 2f  16517   -2  4129.25
geigerDecode: 02 14 02 7d fd 96  32002   -3  4000.25
geigerDecode: 02 14 19 79 fd 89  31001   -3  3875.12
geigerDecode: 02 14 20 44 fe 8e  17440   -2  4360.00
geigerDecode: 02 14 ff 41 fe 54  16895   -2  4223.75
geigerDecode: 02 14 de 7f fd 48  32734   -3  4091.75
geigerDecode: 02 14 de 7b fd 4c  31710   -3  3963.75

but i think your function to receive a message can be simpler. it should simply append a byte to a buffer. When a buffer of sufficient length has been received it should be processed. receiving an STX character should clear the buffer. An incomplete buffer would simply be flushed (buf index reset to 0) when the STX for the next message is received.

processing should be preceded by a checksum test. A received message with an incorrect checksum can be ignored. A correct message is processed with the code above, resulting in a value that can be displayed

Hi gcjr

Great, thanks for your reply - one thing I am confused about is where the final row of figures come from in your sketch?

For example, this is how to calculate the dose rate manually (using the first line of text in your second code window)

02 14 E2 55 FE FD

02 - 00 - STX (never changes)

14 - 20 in decimal - type of meter (won’t change)

E2 - 226 in decimal (low byte of mantissa - variable)

55 - 85 in decimal (high byte of mantissa - variable)

FE - 254 in decimal (dose rate exponent - variable)

FD - 253 - XOR block check

Calculated manually is:

85 * 256 + 226 = 21986 (agrees with your code)

254 (Exponent) - 256 (fixed value) = -2 (agrees with your code)

-2 (exponent) + -15 (fixed value) = -17

21986 x 2^-17 = 21986 x 0.0000076 = 0.16uSv/h dose rate

2^-17 = 0.0000076

I am confused with where 5496.50 has come from or what it refers to?

Thanks so much for your reply and help though, your bit of code is one step closer - thanks for that, appreciate the time you took to reply

Ed

my interpretation of the EXP byte is that it is simply a binary shift, 2EXP. and EXP of 0xfe is -2 and i believe that mean 1/4. 21986/4 = 5496.5. is that not correct?

I don’t think, so the manufacturer laid out the calculation for me and 2^-17 (2 EXP -17) = 0.0000076

Which 21985 * 0.0000076 = 0.16 (or in other words the radiation level the meter detected)

It confused the hell out of me for a bit as I thought 2^ was ‘to the power of’ and I couldn’t make the calculation work manually with a calculator.

I have calculated about 5 or 6 the same way and the all work out the same, my ‘checks and balances’ was comparing against the calculation the manufacturer did when the verified my data originally, I calculated that then applied the same calculation to the other readings and it worked (manually, on paper - not as a sketch or anything)

Thanks for the reply, and number crunching for me :slight_smile:

Ed

I googled it, here is what google calculator says (see attachment - sorry am on my phone so can’t upload to them hotline)

Ed

Flat4:
I don’t think, so the manufacturer laid out the calculation for me and 2^-17 (2 EXP -17) = 0.0000076

the doc you posted says " byte 5 is the signed (-128...+127) 2-based exponent, The unit is µSv/h". so 5496.50 uSv/H, or do you believe it is 0.0000076 uSv/h

i don't understand the BASIC code

xdl = mant * 2 ^ (expon - 15) 'dose rate as floating point number

The dose rate (uSv/hr) = mantissa (i.e the 21986 figure) multiplied by 0.0000076 which equals 0.16 (0.16uSv/h) which is broadly normal for natural background radiation and corresponds with the meter readings taken a total the time from the actual meter face (digital screen)

This was what the manufacturer confirmed for me was the way their code works.

So the code you wrote works up to the 21986 (etcetera) figure then the maths goes awry, Somewhere that 21986 needs to be multiplied 0.0000076 so that 0.16 is displayed where 5496.50 is currently displayed. (Obviously 21986 and 0.0000076 are variables that will change for each reading - the other 5 digit numbers in your code under 21986 look right but I haven’t calculated them out on paper - although I am happy to if it will help?)

And yeah, I don’t understand the BASIC code either :confused:

Thanks for your patience with this, it’s been taxing my brain so thanks for the sense check and making me double check my maths :slight_smile:

Ed

Put the following directly into google search box

21986 x 2^(-17)

and it will return a calculated 0.16773985816 (0.16)

It’s worth mentioning that the negative figure after the 5 digit number in your results is always added to -15 - I queried this with the manufacturer aswell and they confirmed -15 is constant and doesn’t change.

Ed

byte 5 is the signed (-128...+127) 2-based exponent. The unit is µSv/h (pulses per second for pulse rate indicating probes like 6150AD-k, AD-17, AD-19).

i agree. your docs says the above. while the EXP is -128 ... 127, there appears to be an offset of -15 which is consistent with the BASIC code. I can't find where this is spelled out in the doc

so when the EXP is 0xfe = -2, the value applied to the manissa 2-2-15 = 2-17

Yep :slight_smile:

Phew, thanks for sticking with me on that! The document doesn’t fully explain the BASIC code and it made it harder to be honest.

Now, how does that go into code?

I understand the maths that’s occuring - but not how to get a sketch doing the same thing. I am a programming idiot, so be gentle :wink:

Your sketch (thanks btw) is producing almost the end result, apart from that maths we have just thrashed out - how do I include that formula in the sketch?

Also, all the variables in the BASIC code I don’t really need to code for as the manufacturer has to cover every variant of every device they make with the same code where as I only have 1 device - so a lot of the different devices or probe types variables can be culled out of the BASIC code I think

Thanks
Ed

i tested this code on my laptop. I'm leaving the code to do the prints inside an ifdef which you can remove. assume you know how to incorporate this into your sketch

// --------------------------------------------------------------------
#define LSB 2
#define MSB 3
#define EXP 4

int
geigerChksum (
    uint8_t *buf,
    int      nByte )
{
    uint8_t  sum = 0;
    for (int i = 1; i < nByte; i++)
        sum ^= buf [i];
    return sum;
}

// ----------------------------------------

float
geigerDecode (
    uint8_t *buf,
    int      nByte )
{
#define EXP_OFF     -15
    float   val;
    int8_t  exp  = buf [EXP] + EXP_OFF;
    int16_t mant = ((buf [MSB] << 8) | buf [LSB]);

    if (exp < 0)
        val = 1. * mant / (1 << -exp);
    else
        val = 1. * mant * (1 << exp);

#define PR
#ifdef PR
    printf ("   %s:", __func__);

    uint8_t  chksm = buf [0];
    for (int i = 0; i < nByte; i++)  {
        printf (" %02x", buf [i]);
        chksm ^= buf [i];
    }
    printf ("  %02x", chksm);

    printf (" %8d", mant);
    printf (" %2d",   exp);

    printf (" %8.4f", val);
    printf ("\n");
#endif

    return val;
}
   geigerDecode: 02 14 e2 55 fe 5d  00    21986 -17   0.1677
   geigerDecode: 02 14 32 53 fe 8b  00    21298 -17   0.1625
   geigerDecode: 02 14 98 50 fe 22  00    20632 -17   0.1574
   geigerDecode: 02 14 13 4e fe b7  00    19987 -17   0.1525
   geigerDecode: 02 14 a2 4b fe 03  00    19362 -17   0.1477
   geigerDecode: 02 14 44 49 fe e7  00    18756 -17   0.1431
   geigerDecode: 02 14 f9 46 fe 55  00    18169 -17   0.1386
   geigerDecode: 02 14 c1 44 fe 6f  00    17601 -17   0.1343
   geigerDecode: 02 14 9b 42 fe 33  00    17051 -17   0.1301
   geigerDecode: 02 14 85 40 fe 2f  00    16517 -17   0.1260
   geigerDecode: 02 14 02 7d fd 96  00    32002 -18   0.1221
   geigerDecode: 02 14 19 79 fd 89  00    31001 -18   0.1183
   geigerDecode: 02 14 20 44 fe 8e  00    17440 -17   0.1331
   geigerDecode: 02 14 ff 41 fe 54  00    16895 -17   0.1289
   geigerDecode: 02 14 de 7f fd 48  00    32734 -18   0.1249
   geigerDecode: 02 14 de 7b fd 4c  00    31710 -18   0.1210

after receiving a string you do something like the following

        if (! geigerChksum (b, n))
#ifndef PR
            printf ("  %6.2f\n", geigerDecode (b, n));
#else
            geigerDecode (b, n);
#endif

you good?

thanks. i learned something

gcjr:
i tested this code on my laptop. I'm leaving the code to do the prints inside an ifdef which you can remove. assume you know how to incorporate this into your sketch

// --------------------------------------------------------------------

#define LSB 2
#define MSB 3
#define EXP 4

int
geigerChksum (
   uint8_t *buf,
   int      nByte )
{
   uint8_t  sum = 0;
   for (int i = 1; i < nByte; i++)
       sum ^= buf [i];
   return sum;
}

// ----------------------------------------

float
geigerDecode (
   uint8_t *buf,
   int      nByte )
{
#define EXP_OFF     -15
   float   val;
   int8_t  exp  = buf [EXP] + EXP_OFF;
   int16_t mant = ((buf [MSB] << 8) | buf [LSB]);

if (exp < 0)
       val = 1. * mant / (1 << -exp);
   else
       val = 1. * mant * (1 << exp);

#define PR
#ifdef PR
   printf ("   %s:", func);

uint8_t  chksm = buf [0];
   for (int i = 0; i < nByte; i++)  {
       printf (" %02x", buf [i]);
       chksm ^= buf [i];
   }
   printf ("  %02x", chksm);

printf (" %8d", mant);
   printf (" %2d",   exp);

printf (" %8.4f", val);
   printf ("\n");
#endif

return val;
}







geigerDecode: 02 14 e2 55 fe 5d  00    21986 -17   0.1677
  geigerDecode: 02 14 32 53 fe 8b  00    21298 -17   0.1625
  geigerDecode: 02 14 98 50 fe 22  00    20632 -17   0.1574
  geigerDecode: 02 14 13 4e fe b7  00    19987 -17   0.1525
  geigerDecode: 02 14 a2 4b fe 03  00    19362 -17   0.1477
  geigerDecode: 02 14 44 49 fe e7  00    18756 -17   0.1431
  geigerDecode: 02 14 f9 46 fe 55  00    18169 -17   0.1386
  geigerDecode: 02 14 c1 44 fe 6f  00    17601 -17   0.1343
  geigerDecode: 02 14 9b 42 fe 33  00    17051 -17   0.1301
  geigerDecode: 02 14 85 40 fe 2f  00    16517 -17   0.1260
  geigerDecode: 02 14 02 7d fd 96  00    32002 -18   0.1221
  geigerDecode: 02 14 19 79 fd 89  00    31001 -18   0.1183
  geigerDecode: 02 14 20 44 fe 8e  00    17440 -17   0.1331
  geigerDecode: 02 14 ff 41 fe 54  00    16895 -17   0.1289
  geigerDecode: 02 14 de 7f fd 48  00    32734 -18   0.1249
  geigerDecode: 02 14 de 7b fd 4c  00    31710 -18   0.1210




after receiving a string you do something like the following



if (! geigerChksum (b, n))
#ifndef PR
           printf ("  %6.2f\n", geigerDecode (b, n));
#else
           geigerDecode (b, n);
#endif




you good?

thanks. i learned something

err tbh, dont assume anything - coding is not my forte, i can play around and try and address compiler errors but will likely have to come back and ask again!!

I manually calculated your results from your code aswell, it all checks out on paper, i only calculated to 3 decimal places though, but that doesnt matter.

geigerDecode: 02 14 e2 55 fe 5d 21986 -2 21986 * 2^-17 = 0.167
geigerDecode: 02 14 32 53 fe 8b 21298 -2 21298 * 2^-17 = 0.162
geigerDecode: 02 14 98 50 fe 22 20632 -2 20632 * 2^-17 = 0.157
geigerDecode: 02 14 13 4e fe b7 19987 -2 19987 * 2^-17 = 0.152
geigerDecode: 02 14 a2 4b fe 03 19362 -2 19362 * 2^-17 = 0.147
geigerDecode: 02 14 44 49 fe e7 18756 -2 18756 * 2^-17 = 0.143
geigerDecode: 02 14 f9 46 fe 55 18169 -2 18169 * 2^-17 = 0.138
geigerDecode: 02 14 c1 44 fe 6f 17601 -2 17601 * 2^-17 = 0.134
geigerDecode: 02 14 9b 42 fe 33 17051 -2 17051 * 2^-17 = 0.130
geigerDecode: 02 14 85 40 fe 2f 16517 -2 16517 * 2^-17 = 0.126
geigerDecode: 02 14 02 7d fd 96 32002 -3 32002 * 2^-18 = 0.122
geigerDecode: 02 14 19 79 fd 89 31001 -3 31001 * 2^-18 = 0.118
geigerDecode: 02 14 20 44 fe 8e 17440 -2 17440 * 2^-17 = 0.133
geigerDecode: 02 14 ff 41 fe 54 16895 -2 16895 * 2^-17 = 0.128
geigerDecode: 02 14 de 7f fd 48 32734 -3 32734 * 2^-18 = 0.124
geigerDecode: 02 14 de 7b fd 4c 31710 -3 31710 * 2^-18 = 0.120

which is super excellent, thanks a lot for doing that -m i really really appreciate it :slight_smile:

Pointers of how to copy it into my existing code gratefully received :confused:

thanks again

Ed

here is the code i suggest you use. i tested this on my laptop.

the results are displayed using a printf which won't work on the arduino because the calculated value is a float, and typically < 0.

i think that -15 offset needs to be left out so that the result in a significant integer value that can conveyed as an integer which can be converted to a float by dividing by 215

i will leave it to you to put this into your sketch

// --------------------------------------------------------------------
#define LSB 2
#define MSB 3
#define EXP 4

int
geigerChksum (
    uint8_t *buf,
    int      nByte )
{
    uint8_t  sum = 0;
    for (int i = 1; i < nByte; i++)  {
        sum ^= buf [i];
        if (1 < debug)
            printf (" %s: %d %02x %02x\n",
                __func__, i, buf [i], sum);
    }
    return sum;
}

// ----------------------------------------
float
geigerDecode (
    uint8_t *buf,
    int      nByte )
{
#define EXP_OFF     -15               <<<<<<<<<<<   should be zero
    float   val;
    int8_t  exp  = buf [EXP] + EXP_OFF;
    int16_t mant = ((buf [MSB] << 8) | buf [LSB]);

    if (exp < 0)
        val = 1. * mant / (1 << -exp);
    else
        val = 1. * mant * (1 << exp);

// #define PR
#ifdef PR
    printf ("   %s:", __func__);

    uint8_t  chksm = buf [0];
    for (int i = 0; i < nByte; i++)  {
        printf (" %02x", buf [i]);
        chksm ^= buf [i];
    }
    printf ("  %02x", chksm);

    printf (" %8d", mant);
    printf (" %2d",   exp);

    printf (" %8.4f", val);
    printf ("\n");
#endif

    return val;
}

// --------------------------------------------------------------------
#define STX         02
#define MSG_SIZE    6

byte myBuf [MSG_SIZE];

int
myRecv (void)
{
    static byte           ndx = 0;

    if (! mySerial.available())
        return ndx;

    byte  rb = mySerial.read ();

    if (STX == rb)
        ndx = 0;
    myBuf [ndx++] = rb;

    return ndx;
}

// --------------------------------------------------------------------
void
loop (void)  {
    if (MSG_SIZE == myRecv ())  {
        if (! geigerChksum (myBuf, MSG_SIZE))  {
            printf ("%s: %8.3f\n",                                   <<<<< replace with Serial.println
                __func__, geigerDecode (myBuf, MSG_SIZE));
        }
        else
            printf ("%s: checksum error\n", __func__);
    }
}

this is the data i tested with. it includes an incomplete message and one with a checksum error. the 3rd and last are the same.

02 14 e2 55 fe 5d
02 14 32 53 fe 8b
02 14 98 50 fe 22

02 14 e2
02 14 32 53 fe 8c
02 14 98 50 fe 22

loop:    0.168
loop:    0.162
loop:    0.157
loop: checksum error
loop:    0.157

gcjr:
here is the code i suggest you use. i tested this on my laptop.

the results are displayed using a printf which won't work on the arduino because the calculated value is a float, and typically < 0.

i think that -15 offset needs to be left out so that the result in a significant integer value that can conveyed as an integer which can be converted to a float by dividing by 215

i will leave it to you to put this into your sketch

// --------------------------------------------------------------------

#define LSB 2
#define MSB 3
#define EXP 4

int
geigerChksum (
    uint8_t *buf,
    int      nByte )
{
    uint8_t  sum = 0;
    for (int i = 1; i < nByte; i++)  {
        sum ^= buf [i];
        if (1 < debug)
            printf (" %s: %d %02x %02x\n",
                func, i, buf [i], sum);
    }
    return sum;
}

// ----------------------------------------
float
geigerDecode (
    uint8_t *buf,
    int      nByte )
{
#define EXP_OFF    -15              <<<<<<<<<<<  should be zero
    float  val;
    int8_t  exp  = buf [EXP] + EXP_OFF;
    int16_t mant = ((buf [MSB] << 8) | buf [LSB]);

if (exp < 0)
        val = 1. * mant / (1 << -exp);
    else
        val = 1. * mant * (1 << exp);

// #define PR
#ifdef PR
    printf ("  %s:", func);

uint8_t  chksm = buf [0];
    for (int i = 0; i < nByte; i++)  {
        printf (" %02x", buf [i]);
        chksm ^= buf [i];
    }
    printf ("  %02x", chksm);

printf (" %8d", mant);
    printf (" %2d",  exp);

printf (" %8.4f", val);
    printf ("\n");
#endif

return val;
}

// --------------------------------------------------------------------
#define STX        02
#define MSG_SIZE    6

byte myBuf [MSG_SIZE];

int
myRecv (void)
{
    static byte          ndx = 0;

if (! mySerial.available())
        return ndx;

byte  rb = mySerial.read ();

if (STX == rb)
        ndx = 0;
    myBuf [ndx++] = rb;

return ndx;
}

// --------------------------------------------------------------------
void
loop (void)  {
    if (MSG_SIZE == myRecv ())  {
        if (! geigerChksum (myBuf, MSG_SIZE))  {
            printf ("%s: %8.3f\n",                                  <<<<< replace with Serial.println
                func, geigerDecode (myBuf, MSG_SIZE));
        }
        else
            printf ("%s: checksum error\n", func);
    }
}




this is the data i tested with. it includes an incomplete message and one with a checksum error. the 3rd and last are the same.



02 14 e2 55 fe 5d
02 14 32 53 fe 8b
02 14 98 50 fe 22

02 14 e2
02 14 32 53 fe 8c
02 14 98 50 fe 22

loop:    0.168
loop:    0.162
loop:    0.157
loop: checksum error
loop:    0.157

thanks Greg, no idea, but i am in no hurry so can play around and try and learn :slight_smile: thanks for your help!

going to work through this is think

https://en.wikiversity.org/wiki/Arduino_Sketch_Merge

so i can understand what it is i am doing to merge 2 different bits of code, will try get to that this weekend, if i get time.

Ed