bemasher / rtlamr

An rtl-sdr receiver for Itron ERT compatible smart meters operating in the 900MHz ISM band.
GNU Affero General Public License v3.0
2.19k stars 249 forks source link

question about checksum for standard SCM #128

Closed gpgib6 closed 4 years ago

gpgib6 commented 4 years ago

the preamble is 21 bits so must in theory take up more than 2 bytes. but in the checksum (scm.go, line 76):

if p.Checksum(p.data.Bytes[2:12]) != 0 {

It looks like Bytes[0] and Bytes[1] are passed over to skip the preamble but wouldn't part of the preamble still be in Bytes[2]? Also it looks like the 16-bit checksum supplied by the meter is also passed to the internal checksum calculation of this code.

bemasher commented 4 years ago

The frame sync bytes include five reserved bits that have fixed values. Because these bits are fixed, they are included in the preamble to reduce false-positives when searching sample data, but they are actually part of the packet body and are necessary for the checksum.

The checksum is generated from bytes 2-10 and appended to the packet. If you then calculate the checksum over the packet and the provided checksum (bytes 2-12), the packet is valid if the calculated checksum is 0.

func TestChecksum(t *testing.T) {
    // Standard checksum parameters for SCM.
    bch := crc.NewCRC("BCH", 0, 0x6F63, 0)

    // Allocate a packet. We're leaving off the sync words here.
    pkt := make([]byte, 10)

    // Fill the packet with random bytes except the checksum bytes.
    rand.Read(pkt[:8])

    // Calculate the checksum over the first 8 bytes.
    check := bch.Checksum(pkt[:8])
    t.Logf("%02X %04X\n", pkt, check)

    // Append the checksum to the packet.
    pkt[8] = uint8(check >> 8)
    pkt[9] = uint8(check)

    // Check that the packet is valid by calculating the checksum over the
    // packet and the previously calculated checksum.
    check = bch.Checksum(pkt)
    t.Logf("%02X %04X\n", pkt, check)

    if check != 0 {
        t.Fatalf("invalid checksum 0x%04X != 0x%04X\n", check, 0)
    }
}
$ go test -v -run=Checksum
=== RUN   TestChecksum
--- PASS: TestChecksum (0.00s)
    scm_test.go:100: F0B970E815CA48130000 7184
    scm_test.go:109: F0B970E815CA48137184 0000
PASS
ok      github.com/bemasher/rtlamr/scm  0.405s
gpgib6 commented 4 years ago

thank you for clarifying this and the additional details!