2 #include "pulse_demod.h"
5 // Transmitter speed in bits per seconds
6 #define RH_ASK_SPEED 2000
7 #define RH_ASK_BIT_LEN (int)1e6/RH_ASK_SPEED
9 // Maximum message length (including the headers, byte count and FCS) we are willing to support
10 // This is pretty arbitrary
11 #define RH_ASK_MAX_PAYLOAD_LEN 67
12 #define RH_ASK_HEADER_LEN 4
13 #ifndef RH_ASK_MAX_MESSAGE_LEN
14 #define RH_ASK_MAX_MESSAGE_LEN (RH_ASK_MAX_PAYLOAD_LEN - RH_ASK_HEADER_LEN - 3)
17 uint8_t payload[RH_ASK_MAX_PAYLOAD_LEN] = {0};
18 int data_payload[RH_ASK_MAX_MESSAGE_LEN];
20 // Note: all tje "4to6 code" came from RadioHead source code.
21 // see: http://www.airspayce.com/mikem/arduino/RadioHead/index.html
23 // 4 bit to 6 bit symbol converter table
24 // Used to convert the high and low nybbles of the transmitted data
25 // into 6 bit symbols for transmission. Each 6-bit symbol has 3 1s and 3 0s
26 // with at most 3 consecutive identical bits
27 static uint8_t symbols[] = {
28 0xd, 0xe, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,
29 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x32, 0x34
32 // Convert a 6 bit encoded symbol into its 4 bit decoded equivalent
33 uint8_t symbol_6to4(uint8_t symbol)
36 // Linear search :-( Could have a 64 byte reverse lookup table?
37 // There is a little speedup here courtesy Ralph Doncaster:
38 // The shortcut works because bit 5 of the symbol is 1 for the last 8
39 // symbols, and it is 0 for the first 8.
40 // So we only have to search half the table
41 for (i = (symbol>>2) & 8; i < 16 ; i++){
42 if (symbol == symbols[i]) return i;
44 return 0xFF; // Not found
48 static int radiohead_ask_callback(bitbuffer_t *bitbuffer) {
50 char time_str[LOCAL_TIME_BUFLEN];
52 local_time_str(0, time_str);
54 uint8_t row = 0; // we are considering only first row
55 unsigned int len = bitbuffer->bits_per_row[row];
57 uint8_t msg_len = RH_ASK_MAX_MESSAGE_LEN;
58 unsigned int pos, nb_bytes;
59 uint8_t rxBits[2] = {0};
61 uint16_t crc, crc_recompute;
62 uint8_t data_len, header_to, header_from, header_id, header_flags;
65 // Looking for preamble
66 uint8_t init_pattern[] = {
73 // The first 0 is ignored by the decoder, so we look only for 28 bits of "01"
74 // and not 32. Also "0x1CD" is 0xb38 (RH_ASK_START_SYMBOL) with LSBit first.
75 uint8_t init_pattern_len = 40;
77 pos = bitbuffer_search(bitbuffer, row, 0, init_pattern, init_pattern_len);
80 printf("RH ASK preamble not found\n");
85 // read "bytes" of 12 bit
87 pos += init_pattern_len;
88 for(; pos < len && nb_bytes < msg_len; pos += 12){
89 bitbuffer_extract_bytes(bitbuffer, row, pos, rxBits, /*len=*/16);
90 // ^ we should read 16 bits and not 12, elsewhere last 4bits are ignored
91 rxBits[0] = reverse8(rxBits[0]);
92 rxBits[1] = reverse8(rxBits[1]);
93 rxBits[1] = ((rxBits[1] & 0x0F)<<2) + (rxBits[0]>>6);
95 uint8_t hi_nibble = symbol_6to4(rxBits[0]);
98 fprintf(stdout, "Error on 6to4 decoding high nibble: %X\n", rxBits[0]);
102 uint8_t lo_nibble = symbol_6to4(rxBits[1]);
105 fprintf(stdout, "Error on 6to4 decoding low nibble: %X\n", rxBits[1]);
109 uint8_t byte = hi_nibble<<4 | lo_nibble;
110 payload[nb_bytes] = byte;
118 data_len = msg_len - RH_ASK_HEADER_LEN - 3;
119 header_to = payload[1];
120 header_from = payload[2];
121 header_id = payload[3];
122 header_flags = payload[4];
125 crc = payload[5 + data_len] + (payload[5 + data_len + 1]<<8);
126 crc_recompute = ~crc16(payload, msg_len-2, 0x8408, 0xFFFF);
127 if(crc_recompute != crc){
129 fprintf(stdout, "CRC error: %04X != %04X\n", crc_recompute, crc);
135 for(int j=0; j<msg_len; j++){
136 data_payload[j] = (int)payload[5+j];
138 data = data_make("time", "", DATA_STRING, time_str,
139 "model", "", DATA_STRING, "RadioHead ASK",
140 "crc", "", DATA_STRING, "OK",
141 "len", "Data len", DATA_INT, data_len,
142 "to", "To", DATA_INT, header_to,
143 "from", "From", DATA_INT, header_from,
144 "id", "Id", DATA_INT, header_id,
145 "flags", "Flags", DATA_INT, header_flags,
146 "payload", "Payload", DATA_ARRAY, data_array(data_len, DATA_INT, data_payload),
148 data_acquired_handler(data);
153 static char *output_fields[] = {
166 r_device radiohead_ask = {
167 .name = "Radiohead ASK",
168 .modulation = OOK_PULSE_PCM_RZ,
169 .short_limit = RH_ASK_BIT_LEN,
170 .long_limit = RH_ASK_BIT_LEN,
171 .reset_limit = RH_ASK_BIT_LEN*10,
172 .json_callback = &radiohead_ask_callback,
173 .fields = output_fields,