Figures 1 and 2 show differing schemes for computing checksums, from References 1 and 2, respectively. Let's call these Method 1 and Method 2. (Unhelpfully, the modern equivalent to Ref 1, that is, Ref 3, has no sample code.)
As shown in Figure 3, ref 2 provides sample data that can be used as a test. It is used here as a test. Specifically, page 8 of ref 2 states that the checksum of the sequence a5 21 4f 00 45 17 14 15 20 05 00 00 00 00 92 00 is b4e0. The endianness is unstated, but I tried both possibilities, and it is the second, i.e. b2 below, not the b1 that is written in Ref 3.
The file checksum.c
(see Appendix 3) holds a version of the Nortek code
written to modern C standards (with specified-length types). Running it on
the b1
file (created with R code shown in Appendix 3) produced with R code as
above does not retrieve the same checksum as Nortek states, but using b2
yields agreement. In other words, Nortek is (confusingly!) writing bytes in
little-endian order.
The output of checksum b2
is as follows. The final value matches expectations
for the b2
file, but not for b1
. In other words, the Nortek manual is not
listing bytes in actual order, but rather in the order that would occur if you
read by little-endian 2-byte chunks.
./checksum b2 buf[0:15]: 0x21 0xa5 0x0 0x4f 0x17 0x45 0x15 0x14 0x5 0x20 0x0 0x0 0x0 0x0 0x0 0x92 checksum(buffer, n=8) start with 0xb58c add 0xa521 to get 0x00015aad add 0x4f00 to get 0x0001a9ad add 0x4517 to get 0x0001eec4 add 0x1415 to get 0x000202d9 add 0x2005 to get 0x000222de add 0x0000 to get 0x000222de add 0x0000 to get 0x000222de add 0x9200 to get 0x0002b4de computed checksum: 0xb4e0 (expect 0xb4e0)
Nortek AS. “Signature Integration 55|250|500|1000kHz.” Nortek AS, 2017. https://www.nortekgroup.com/assets/software/N3015-007-Integrators-Guide-AD2CP_1018.pdf.
Nortek AS. “Classic Integrators Guide: Aquadopp | Aquadopp DW | Aquadopp Profiler | HQ Aquadopp Profiler | Vector | AWAC.” Nortek AS, 2022. https://support.nortekgroup.com/hc/en-us/articles/360029514052-Integrators-Guide-Classic.
Nortek AS. “Signature Integration 55|250|500|1000kHz.” Nortek AS, March 31, 2022.
\includegraphics[width=.8\hsize]{ref1_p47.png}
\includegraphics[width=.45\hsize]{ref2_p79.png}
\includegraphics[width=.7\hsize]{ref2_p8.png}
Ref 3 on page 8 states that the checksum of the sequence a5 21 4f 00 45 17 14 15 20 05 00 00 00 00 92 00 is b4e0. The endianness is unstated, but I tried both possibilities, and it is the second, i.e. b2 below, not the b1 that is written in Ref 3.
b1 <- as.raw(c( 0xa5, 0x21, 0x4f, 0x00, 0x45, 0x17, 0x14, 0x15, 0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00)) b2 <- as.raw(c( 0x21, 0xa5, 0x00, 0x4f, 0x17, 0x45, 0x15, 0x14, 0x05, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92)) writeBin(b1, "b1", size=1L, useBytes=TRUE) B1 <- readBin("b1", "raw", length(b1)) stopifnot(identical(b1, B1)) writeBin(b2, "b2", size=1L, useBytes=TRUE) B2 <- readBin("b2", "raw", length(b2)) stopifnot(identical(b2, B2))
The local file checksum.c
holds a version of the Nortek code written to
modern C standards (with specified-length types). It is given in the
Appendix. Running it on the b1
file produced with R code as above does
not retrieve the same checksum as Nortek states, but using b2
yields
agreement. In other words, Nortek is (confusingly!) writing bytes in
little-endian order.
Nortek AS. “Signature Integration 55|250|500|1000kHz.” Nortek AS, 2017. https://www.nortekgroup.com/assets/software/N3015-007-Integrators-Guide-AD2CP_1018.pdf.
Nortek AS. “Signature Integration 55|250|500|1000kHz.” Nortek AS, March 31, 2022.
Nortek AS. “Classic Integrators Guide: Aquadopp | Aquadopp DW | Aquadopp Profiler | HQ Aquadopp Profiler | Vector | AWAC.” Nortek AS, 2022. https://support.nortekgroup.com/hc/en-us/articles/360029514052-Integrators-Guide-Classic.
checksum.c
follows
#include <stdio.h> #include <stdlib.h> short ChecksumORIG(short *phBuff, int n) { int i; short hChecksum = 0xb58c; for (i=0; i<n; i++) hChecksum += phBuff[i]; return hChecksum; } // This follows the pattern of Page 79 of Ref 3, but with specified types, to // avoid possibly problems porting the nortek code, which has unstated // assumptions (on endianness, on the size of a 'short', etc. int16_t nortek_checksum(uint16_t *phBuff, int n) { uint32_t hChecksum = 0xb58c; // I think this is large enough uint16_t res; printf("checksum(buffer, n=%d)\n", n); printf(" start with 0x%04x\n", hChecksum); for (int i=0; i<n; i++) { hChecksum += phBuff[i]; printf(" add 0x%04x to get 0x%08x\n", phBuff[i], hChecksum); } res = hChecksum % 0xffff; return res; } int main(int argc, char **argv) { FILE *in; int32_t len; unsigned char *buf; uint16_t *buf2; uint16_t cs2; if (argc != 2) { printf("ERROR: give a filename\n"); exit(1); } in = fopen(argv[1], "rb"); fseek(in, 0, SEEK_END); len = ftell(in); rewind(in); buf = (unsigned char*)malloc(len*sizeof(unsigned char)); fread(buf, 1, len, in); printf("buf[0:%d]: ", len-1); for (int32_t i = 0; i < len; i++) printf("0x%x ", buf[i]); printf("\n"); // read 2 bytes at a time rewind(in); buf2 = (uint16_t*)malloc(len/2*sizeof(uint16_t)); fread(buf2, 2, len/2, in); cs2 = nortek_checksum(buf2, len/2); printf("computed checksum: 0x%04x (expect 0xb4e0)\n", cs2); fclose(in); }
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.