Bugfixes
[rtl-433.git] / src / devices / steelmate.c
1 /* Steelmate TPMS FSK protocol
2  *
3  * Copyright © 2016 Benjamin Larsson
4  * Copyright © 2016 John Jore
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Packet payload: 9 bytes.
12  * Bytes 2 to 9 are inverted Manchester with swaped MSB/LSB:
13  *
14  *                               0  1  2  3  4  5  6  7  8
15  *                    [00] {72} 00 00 7f 3c f0 d7 ad 8e fa
16  * After translating            00 00 01 c3 f0 14 4a 8e a0
17  *                              SS SS AA II II PP TT BB CC
18  * S = sync, (0x00)
19  * A = preamble, (0x01)
20  * I = id, 0xc3f0
21  * P = Pressure as double the PSI, 0x14 = 10 PSI
22  * T = Temperature in Fahrenheit, 0x4a = 74 'F
23  * B = Battery as half the millivolt, 0x8e = 2.84 V
24  * C = Checksum, adding bytes 2 to 7 modulo 256 = byte 8,(0x01+0xc3+0xf0+0x14+0x4a+0x8e) modulus 256 = 0xa0
25  */
26
27
28 #include "rtl_433.h"
29 #include "pulse_demod.h"
30 #include "util.h"
31
32 static int steelmate_callback(bitbuffer_t *bitbuffer) {
33         //if (debug_output >= 1) {
34         //      fprintf(stdout, "Steelmate TPMS decoder\n");
35         //      bitbuffer_print(bitbuffer);
36         //      fprintf(stdout, "\n");
37         //}
38
39         char time_str[LOCAL_TIME_BUFLEN];
40         local_time_str(0, time_str);
41         bitrow_t *bb = bitbuffer->bb;
42
43         //Loop through each row of data
44         for (int i = 0; i < bitbuffer->num_rows; i++)
45         {
46                 //Payload is inverted Manchester encoded, and reversed MSB/LSB order
47                 uint8_t preAmble, ID1, ID2, p1, tempFahrenheit, tmpbattery_mV, payload_checksum, calculated_checksum;
48                 uint16_t sensorID, battery_mV;
49                 float pressurePSI;
50                 char sensorIDhex[7];
51                 data_t *data;
52
53                 //Length must be 72 bits to be considered a valid packet
54                 if (bitbuffer->bits_per_row[i] != 72)
55                         continue;
56
57                 //Valid preamble? (Note, the data is still wrong order at this point. Correct pre-amble: 0x00 0x00 0x01)
58                 if (bb[i][0] != 0x00 || bb[i][1] != 0x00 || bb[i][2] != 0x7f)
59                         continue;
60
61                 //Preamble
62                 preAmble = ~reverse8(bb[i][2]);
63
64                 //Sensor ID
65                 ID1 = ~reverse8(bb[i][3]);
66                 ID2 = ~reverse8(bb[i][4]);
67
68                 //Pressure is stored as twice the PSI
69                 p1 = ~reverse8(bb[i][5]);
70
71                 //Temperature is stored in Fahrenheit. Note that the datasheet claims operational to -40'C, but can only express values from -17.8'C
72                 tempFahrenheit = ~reverse8(bb[i][6]);
73
74                 //Battery voltage is stored as half the mV
75                 tmpbattery_mV = ~reverse8(bb[i][7]);
76
77                 //Checksum is a sum of all the other values
78                 payload_checksum = ~reverse8(bb[i][8]);
79                 calculated_checksum = preAmble + ID1 + ID2 + p1 + tempFahrenheit + tmpbattery_mV;
80                 if (payload_checksum != calculated_checksum)
81                         continue;
82
83                 sensorID = (ID1 << 8) + ID2;
84                 sprintf(sensorIDhex, "0x%04x", sensorID);
85                 pressurePSI = (float)p1 / 2;
86                 battery_mV = tmpbattery_mV * 2;
87
88                 data = data_make("time", "", DATA_STRING, time_str,
89                         "type", "", DATA_STRING, "TPMS",
90                         "make", "", DATA_STRING, "Steelmate",
91                         "id", "", DATA_STRING, sensorIDhex,
92                         "pressure_PSI", "", DATA_DOUBLE, pressurePSI,
93                         "temperature_F", "", DATA_DOUBLE, (float)tempFahrenheit,
94                         "battery_mV", "", DATA_INT, battery_mV,
95                         "checksum", "", DATA_STRING, "OK",
96                         NULL);
97                 data_acquired_handler(data);
98
99                 return 1;
100         }
101
102         //Was not a Steelmate TPMS after all
103         return 0;
104 }
105
106 static char *output_fields[] = {
107         "time",
108         "type",
109         "make",
110         "id",
111         "pressure_PSI",
112         "temperature_F",
113         "battery_mV",
114         "checksum",
115         NULL
116 };
117
118 r_device steelmate = {
119         .name                   = "Steelmate TPMS",
120         .modulation             = FSK_PULSE_MANCHESTER_ZEROBIT,
121         .short_limit    = 12*4,
122         .long_limit     = 0,
123         .reset_limit    = 27*4,
124         .json_callback  = &steelmate_callback,
125         .disabled               = 0,
126         .fields                 = output_fields,
127 };