Skip to content

Commit

Permalink
If HL/LH formats are not available, fallback to RAW and generate the …
Browse files Browse the repository at this point in the history
…frame
  • Loading branch information
jcrona committed Dec 3, 2018
1 parent 72d9a57 commit f99d7be
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ endif
CC=$(GNU_PREFIX)gcc
LD=$(GNU_PREFIX)ld

LDLIBS = -lusb-1.0 -lpthread
LDLIBS = -lusb-1.0 -lpthread -lm

ifeq ($(USE_EXTERNAL_LIBICONV), true)
LDLIBS += -liconv
Expand Down
41 changes: 41 additions & 0 deletions raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>

#include "rf-ctrl.h"
#include "raw.h"


Expand Down Expand Up @@ -77,3 +79,42 @@ size_t raw_write_bits(uint8_t *buf, size_t offset, uint8_t *data, size_t data_bi

return (count - offset);
}

int raw_generate_hl_frame(uint8_t *dest_frame_data, size_t dest_data_len, struct timing_config *config, uint8_t *src_frame_data, uint16_t src_bit_count, uint16_t base_time) {
uint16_t i;
size_t count = 0;
raw_edge_order_t order = (config->bit_fmt == RF_BIT_FMT_HL) ? RAW_EDGE_ORDER_HL : RAW_EDGE_ORDER_LH;
uint8_t start_h_len = round(config->start_bit_h_time/base_time);
uint8_t start_l_len = round(config->start_bit_l_time/base_time);
uint8_t end_h_len = round(config->end_bit_h_time/base_time);
uint8_t end_l_len = round(config->end_bit_l_time/base_time);
uint8_t zero_h_len = round(config->data_bit0_h_time/base_time);
uint8_t zero_l_len = round(config->data_bit0_l_time/base_time);
uint8_t one_h_len = round(config->data_bit1_h_time/base_time);
uint8_t one_l_len = round(config->data_bit1_l_time/base_time);

/* Compute the final length of the frame */
count = 0;
for (i = 0; i < src_bit_count; i++) {
if (src_frame_data[i/8] & (1 << (i % 8))) {
count++;
}
}

count = start_h_len + start_l_len + end_h_len + end_l_len +
(zero_h_len + zero_l_len) * (src_bit_count - count) +
(one_h_len + one_l_len) * count;

if (count > (dest_data_len * 8)) {
fprintf(stderr, "RAW buffer to small (%lu bits) for this frame (%lu bits)\n", dest_data_len * 8, count);
return -1;
}

/* Generate the RAW frame */
count = 0;
count += raw_write_edge(dest_frame_data, count, order, start_h_len, start_l_len);
count += raw_write_bits(dest_frame_data, count, src_frame_data, src_bit_count, order, zero_h_len, zero_l_len, order, one_h_len, one_l_len);
count += raw_write_edge(dest_frame_data, count, order, end_h_len, end_l_len);

return count;
}
1 change: 1 addition & 0 deletions raw.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ size_t raw_write_low(uint8_t *buf, size_t offset, uint8_t length);
size_t raw_write_high(uint8_t *buf, size_t offset, uint8_t length);
size_t raw_write_edge(uint8_t *buf, size_t offset, raw_edge_order_t order, uint8_t h_len, uint8_t l_len);
size_t raw_write_bits(uint8_t *buf, size_t offset, uint8_t *data, size_t data_bit_len, raw_edge_order_t zero_order, uint8_t zero_h_len, uint8_t zero_l_len, raw_edge_order_t one_order, uint8_t one_h_len, uint8_t one_l_len);
int raw_generate_hl_frame(uint8_t *dest_frame_data, size_t dest_data_len, struct timing_config *config, uint8_t *src_frame_data, uint16_t src_bit_count, uint16_t base_time);

#endif /* _RAW_H_ */
100 changes: 99 additions & 1 deletion rf-ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <unistd.h>

#include "rf-ctrl.h"
#include "raw.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

Expand All @@ -43,6 +44,8 @@

#define MAX_FRAME_LENGTH 512

#define RAW_FALLBACK_ACCURACY 10 // This changes how accurate will be the base_time for generated RAW frames (allowed error in % of the smallest timing)

/* WARNING: Needs to remain in-sync with PARAM_* defines in rf-ctrl.h */
char *(parameter_str[]) = {
"hw",
Expand Down Expand Up @@ -262,10 +265,73 @@ static int get_cmd_id_by_name(char *cmd_str) {
return -1;
}

static int gcd(uint16_t a, uint16_t b, uint16_t accuracy) {
if (a <= accuracy) {
return b;
}

return gcd(b % a, a, accuracy);
}

static uint16_t find_best_base_time(struct timing_config *config) {
uint16_t gcd1, gcd2, gcd3, gcd4;
uint16_t accuracy = 0xFFFF;

if ((config->start_bit_h_time > 0) && (accuracy > config->start_bit_h_time)) {
accuracy = config->start_bit_h_time;
}

if ((config->start_bit_l_time > 0) && (accuracy > config->start_bit_l_time)) {
accuracy = config->start_bit_l_time;
}

if ((config->end_bit_h_time > 0) && (accuracy > config->end_bit_h_time)) {
accuracy = config->end_bit_h_time;
}

if ((config->end_bit_l_time > 0) && (accuracy > config->end_bit_l_time)) {
accuracy = config->end_bit_l_time;
}

if ((config->data_bit0_h_time > 0) && (accuracy > config->data_bit0_h_time)) {
accuracy = config->data_bit0_h_time;
}

if ((config->data_bit0_l_time > 0) && (accuracy > config->data_bit0_l_time)) {
accuracy = config->data_bit0_l_time;
}

if ((config->data_bit1_h_time > 0) && (accuracy > config->data_bit1_h_time)) {
accuracy = config->data_bit1_h_time;
}

if ((config->data_bit1_l_time > 0) && (accuracy > config->data_bit1_l_time)) {
accuracy = config->data_bit1_l_time;
}

accuracy = (accuracy * RAW_FALLBACK_ACCURACY)/100;

dbg_printf(3, " RAW Accuracy: %u us (%u%%)\n", accuracy, RAW_FALLBACK_ACCURACY);

gcd1 = gcd(config->start_bit_h_time, config->start_bit_l_time, accuracy);
gcd2 = gcd(config->end_bit_h_time, config->end_bit_l_time, accuracy);
gcd3 = gcd(config->data_bit0_h_time, config->data_bit0_l_time, accuracy);
gcd4 = gcd(config->data_bit1_h_time, config->data_bit1_l_time, accuracy);

gcd1 = gcd(gcd1, gcd2, accuracy);
gcd3 = gcd(gcd3, gcd4, accuracy);

return (uint16_t) gcd(gcd1, gcd3, accuracy);
}

static int send_cmd(uint32_t remote_code, uint32_t device_code, rf_command_t command, int protocol) {
struct rf_protocol_driver *protocol_driver;
uint8_t data[MAX_FRAME_LENGTH];
int data_bit_count;
struct timing_config fallback_timings;
uint8_t fallback_data[MAX_FRAME_LENGTH];
int fallback_data_bit_count;
uint16_t base_time;
int ret = 0;
int i;

Expand Down Expand Up @@ -321,7 +387,39 @@ static int send_cmd(uint32_t remote_code, uint32_t device_code, rf_command_t com
dbg_printf(1, "\n");
}

ret = current_hw_driver->send_cmd(protocol_driver->timings, data, (uint16_t) data_bit_count);
if (!(current_hw_driver->supported_bit_fmts & (1 << protocol_driver->timings->bit_fmt))) {
if (current_hw_driver->supported_bit_fmts & (1 << RF_BIT_FMT_RAW)) {
dbg_printf(1, "\n Requested bit format not supported by %s, falling back to RAW\n", current_hw_driver->name);

/* Generate a RAW frame */
base_time = find_best_base_time(protocol_driver->timings);

fallback_data_bit_count = raw_generate_hl_frame(fallback_data, sizeof(fallback_data), protocol_driver->timings, data, (uint16_t) data_bit_count, base_time);

fallback_timings.base_time = base_time;
fallback_timings.bit_fmt = RF_BIT_FMT_RAW;
fallback_timings.frame_count = protocol_driver->timings->frame_count;

if (is_dbg_enabled(1)) {
dbg_printf(3, " RAW Timings (%s): Base HLTime %u us\n", protocol_driver->name,
fallback_timings.base_time);

dbg_printf(1, " RAW Frame data (%s):", protocol_driver->name);
for (i = 0; i < (fallback_data_bit_count + 7)/8; i++) {
dbg_printf(1, " %02X", fallback_data[i]);
}
dbg_printf(1, "\n");
}

ret = current_hw_driver->send_cmd(&fallback_timings, fallback_data, (uint16_t) fallback_data_bit_count);
} else {
fprintf(stderr, "%s - %s: Bit format %u not supported\n", current_hw_driver->name, protocol_driver->name, protocol_driver->timings->bit_fmt);
return -1;
}
} else {
ret = current_hw_driver->send_cmd(protocol_driver->timings, data, (uint16_t) data_bit_count);
}

if (ret < 0) {
fprintf(stderr, "%s - %s: configuration failed\n", current_hw_driver->name, protocol_driver->name);
return ret;
Expand Down

0 comments on commit f99d7be

Please sign in to comment.