Add RadioHead ASK device

This commit is contained in:
Emmanuel N 2016-09-02 14:46:02 +02:00
parent 0779a88499
commit e5736fd857
4 changed files with 183 additions and 2 deletions

View file

@ -68,7 +68,8 @@
DECL(efergy_optical) \
DECL(hondaremote) \
DECL(template) \
DECL(fineoffset_XC0400)
DECL(fineoffset_XC0400) \
DECL(radiohead_ask)
typedef struct {

View file

@ -82,6 +82,7 @@ add_executable(rtl_433
devices/efergy_optical.c
devices/hondaremote.c
devices/new_template.c
devices/radiohead_ask.c
)

View file

@ -67,6 +67,7 @@ rtl_433_SOURCES = baseband.c \
devices/oregon_scientific_sl109h.c \
devices/steelmate.c \
devices/schraeder.c \
devices/new_template.c
devices/new_template.c \
devices/radiohead_ask.c
rtl_433_LDADD = $(LIBRTLSDR) $(LIBM)

178
src/devices/radiohead_ask.c Normal file
View file

@ -0,0 +1,178 @@
#include "rtl_433.h"
#include "pulse_demod.h"
#include "util.h"
// Note: some code here provide from RadioHead source code.
// http://www.airspayce.com/mikem/arduino/RadioHead/index.html
// 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];
// 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
}
#define lo8(x) ((x)&0xff)
#define hi8(x) ((x)>>8)
uint16_t RHcrc_ccitt_update (uint16_t crc, uint8_t data)
{
data ^= lo8 (crc);
data ^= data << 4;
return ((((uint16_t)data << 8) | hi8 (crc)) ^ (uint8_t)(data >> 4)
^ ((uint16_t)data << 3));
}
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];
// 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;
unsigned int start_pos = bitbuffer_search(bitbuffer, row, 0, init_pattern, init_pattern_len);
if(start_pos == len){
if (debug_output) {
printf("RH ASK preamble not found\n");
}
return 0;
}
start_pos += init_pattern_len;
// read "bytes" of 12 bit
unsigned int pos;
uint8_t rxBits[2] = {0};
unsigned int nb_bytes=0;
uint8_t msg_len = RH_ASK_MAX_MESSAGE_LEN;
for(pos = start_pos; 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
//printf("() %d %d %X-%X\n", start_pos, pos, rxBits[0], rxBits[1]);
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){
printf("Error on 6to4 decoding high nibble: %X\n", rxBits[0]);
return 0;
}
uint8_t lo_nibble = symbol_6to4(rxBits[1]);
if(lo_nibble > 0xF){
printf("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;
}
//printf("%2d) %2X-%2X ==> %X %d\n", nb_bytes, rxBits[1], rxBits[0], byte, byte);
nb_bytes++;
}
// Get header
uint8_t data_len = msg_len - RH_ASK_HEADER_LEN - 3;
uint8_t header_to = payload[1];
uint8_t header_from = payload[2];
uint8_t header_id = payload[3];
uint8_t header_flags = payload[4];
// Check CRC
uint16_t crc = payload[5 + data_len] + (payload[5 + data_len + 1]<<8);
uint16_t crc_recompute = 0xFFFF;
for(int j=0; j<msg_len-2; j++){
crc_recompute = RHcrc_ccitt_update(crc_recompute, payload[j]);
}
crc_recompute = ~crc_recompute;
if(crc_recompute != crc){
printf("CRC error: %04X != %04X\n", crc_recompute, crc);
return 0;
}
// Format data
for(int j=0; j<msg_len; j++){
data_payload[j] = (int)payload[5+j];
}
data = data_make("time", "", DATA_STRING, time_str,
"model", "", DATA_STRING, "RadioHead ASK",
"len", "Data len", DATA_INT, data_len,
"to", "To", DATA_INT, header_to,
"from", "From", DATA_INT, header_from,
"id", "Id", DATA_INT, header_id,
"flags", "Flags", DATA_INT, header_flags,
"payload", "Payload", DATA_ARRAY, data_array(data_len, DATA_INT, data_payload),
NULL);
data_acquired_handler(data);
return 0;
}
static char *output_fields[] = {
"time",
"model",
"len",
"to",
"from",
"id",
"flags",
"payload",
NULL
};
r_device radiohead_ask = {
.name = "Radiohead ASK",
.modulation = OOK_PULSE_PCM_RZ,
.short_limit = RH_ASK_BIT_LEN,
.long_limit = RH_ASK_BIT_LEN,
.reset_limit = RH_ASK_BIT_LEN*10,
.json_callback = &radiohead_ask_callback,
.fields = output_fields,
};