X-Git-Url: https://git.rvb.name/rtl-433.git/blobdiff_plain/ca13278b24eb61443559bcb61e64627fba3d8823..6d15c6f967221af825cf84e3ed12b96c763b127b:/src/devices/radiohead_ask.c diff --git a/src/devices/radiohead_ask.c b/src/devices/radiohead_ask.c new file mode 100644 index 0000000..6f42735 --- /dev/null +++ b/src/devices/radiohead_ask.c @@ -0,0 +1,174 @@ +#include "rtl_433.h" +#include "pulse_demod.h" +#include "util.h" + +// Transmitter speed in bits per seconds +#define RH_ASK_SPEED 2000 +#define RH_ASK_BIT_LEN (int)1e6/RH_ASK_SPEED + +// Maximum message length (including the headers, byte count and FCS) we are willing to support +// This is pretty arbitrary +#define RH_ASK_MAX_PAYLOAD_LEN 67 +#define RH_ASK_HEADER_LEN 4 +#ifndef RH_ASK_MAX_MESSAGE_LEN + #define RH_ASK_MAX_MESSAGE_LEN (RH_ASK_MAX_PAYLOAD_LEN - RH_ASK_HEADER_LEN - 3) +#endif + +uint8_t payload[RH_ASK_MAX_PAYLOAD_LEN] = {0}; +int data_payload[RH_ASK_MAX_MESSAGE_LEN]; + +// Note: all tje "4to6 code" came from RadioHead source code. +// see: http://www.airspayce.com/mikem/arduino/RadioHead/index.html + +// 4 bit to 6 bit symbol converter table +// Used to convert the high and low nybbles of the transmitted data +// into 6 bit symbols for transmission. Each 6-bit symbol has 3 1s and 3 0s +// with at most 3 consecutive identical bits +static uint8_t symbols[] = { + 0xd, 0xe, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, + 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x32, 0x34 +}; + +// Convert a 6 bit encoded symbol into its 4 bit decoded equivalent +uint8_t symbol_6to4(uint8_t symbol) +{ + uint8_t i; + // Linear search :-( Could have a 64 byte reverse lookup table? + // There is a little speedup here courtesy Ralph Doncaster: + // The shortcut works because bit 5 of the symbol is 1 for the last 8 + // symbols, and it is 0 for the first 8. + // So we only have to search half the table + for (i = (symbol>>2) & 8; i < 16 ; i++){ + if (symbol == symbols[i]) return i; + } + return 0xFF; // Not found +} + + +static int radiohead_ask_callback(bitbuffer_t *bitbuffer) { + // Get time + char time_str[LOCAL_TIME_BUFLEN]; + data_t *data; + local_time_str(0, time_str); + + uint8_t row = 0; // we are considering only first row + unsigned int len = bitbuffer->bits_per_row[row]; + + uint8_t msg_len = RH_ASK_MAX_MESSAGE_LEN; + unsigned int pos, nb_bytes; + uint8_t rxBits[2] = {0}; + + uint16_t crc, crc_recompute; + uint8_t data_len, header_to, header_from, header_id, header_flags; + + + // Looking for preamble + uint8_t init_pattern[] = { + 0x55, // 8 + 0x55, // 16 + 0x55, // 24 + 0x51, // 32 + 0xcd, // 40 + }; + // The first 0 is ignored by the decoder, so we look only for 28 bits of "01" + // and not 32. Also "0x1CD" is 0xb38 (RH_ASK_START_SYMBOL) with LSBit first. + uint8_t init_pattern_len = 40; + + pos = bitbuffer_search(bitbuffer, row, 0, init_pattern, init_pattern_len); + if(pos == len){ + if(debug_output) { + printf("RH ASK preamble not found\n"); + } + return 0; + } + + // read "bytes" of 12 bit + nb_bytes=0; + pos += init_pattern_len; + for(; pos < len && nb_bytes < msg_len; pos += 12){ + bitbuffer_extract_bytes(bitbuffer, row, pos, rxBits, /*len=*/16); + // ^ we should read 16 bits and not 12, elsewhere last 4bits are ignored + rxBits[0] = reverse8(rxBits[0]); + rxBits[1] = reverse8(rxBits[1]); + rxBits[1] = ((rxBits[1] & 0x0F)<<2) + (rxBits[0]>>6); + rxBits[0] &= 0x3F; + uint8_t hi_nibble = symbol_6to4(rxBits[0]); + if(hi_nibble > 0xF){ + if(debug_output){ + fprintf(stdout, "Error on 6to4 decoding high nibble: %X\n", rxBits[0]); + } + return 0; + } + uint8_t lo_nibble = symbol_6to4(rxBits[1]); + if(lo_nibble > 0xF){ + if(debug_output){ + fprintf(stdout, "Error on 6to4 decoding low nibble: %X\n", rxBits[1]); + } + return 0; + } + uint8_t byte = hi_nibble<<4 | lo_nibble; + payload[nb_bytes] = byte; + if(nb_bytes == 0){ + msg_len = byte; + } + nb_bytes++; + } + + // Get header + data_len = msg_len - RH_ASK_HEADER_LEN - 3; + header_to = payload[1]; + header_from = payload[2]; + header_id = payload[3]; + header_flags = payload[4]; + + // Check CRC + crc = payload[5 + data_len] + (payload[5 + data_len + 1]<<8); + crc_recompute = ~crc16(payload, msg_len-2, 0x8408, 0xFFFF); + if(crc_recompute != crc){ + if(debug_output){ + fprintf(stdout, "CRC error: %04X != %04X\n", crc_recompute, crc); + } + return 0; + } + + // Format data + for(int j=0; j