Loading...
Searching...
No Matches
irrecord.c
Go to the documentation of this file.
/***************************************************************************
** irrecord.c **************************************************************
****************************************************************************
*
* irrecord - library for recording IR-codes for usage with lircd
*
* Copyright (C) 1998,99 Christoph Bartelmus <lirc@bartelmus.de>
*
*/
#define _GNU_SOURCE
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdint.h>
#include <unistd.h>
#include <poll.h>
#include "lirc_private.h"
#include "irrecord.h"
/* -------------------------- C file -------------------------------- */
static const logchannel_t logchannel = LOG_LIB;
// forwards
static lirc_t emulation_readdata(lirc_t timeout);
// Constants
static const struct driver hw_emulation = {
.name = "emulation",
.device = "/dev/null",
.features = LIRC_CAN_REC_MODE2,
.send_mode = 0,
.rec_mode = LIRC_MODE_MODE2,
.code_length = 0,
.init_func = NULL,
.deinit_func = NULL,
.send_func = NULL,
.rec_func = NULL,
.decode_func = NULL,
.drvctl_func = NULL,
.readdata = emulation_readdata,
.open_func = default_open,
.close_func = default_close,
.api_version = 2,
.driver_version = "0.10.2"
};
static const int IR_CODE_NODE_SIZE = sizeof(struct ir_code_node);
// Globals
struct ir_remote remote;
unsigned int eps = 30;
lirc_t aeps = 100;
// Static data
static lirc_t signals[MAX_SIGNALS];
static struct ir_remote* emulation_data;
static struct ir_ncode* next_code = NULL;
static struct ir_ncode* current_code = NULL;
static int current_index = 0;
static int current_rep = 0;
static struct lengths* first_space = NULL;
static struct lengths* first_pulse = NULL;
static struct lengths* first_sum = NULL;
static struct lengths* first_gap = NULL;
static struct lengths* first_repeat_gap = NULL;
static struct lengths* first_signal_length = NULL;
static struct lengths* first_headerp = NULL;
static struct lengths* first_headers = NULL;
static struct lengths* first_1lead = NULL;
static struct lengths* first_3lead = NULL;
static struct lengths* first_trail = NULL;
static struct lengths* first_repeatp = NULL;
static struct lengths* first_repeats = NULL;
static uint32_t lengths[MAX_SIGNALS];
static uint32_t first_length, first_lengths, second_lengths;
static unsigned int count, count_spaces, count_signals;
static unsigned int count_3repeats, count_5repeats;
// Functions
void btn_state_set_message(struct button_state* state, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(state->message, sizeof(state->message), fmt, ap);
va_end(ap);
}
static void fprint_copyright(FILE* fout)
{
fprintf(fout, "\n"
"# Please take the time to finish this file as described in\n"
"# https://sourceforge.net/p/lirc-remotes/wiki/Checklist/\n"
"# and make it available to others by sending it to\n"
"# <lirc@bartelmus.de>\n");
}
int availabledata(void)
{
struct pollfd pfd = {
.fd = curr_driver->fd, .events = POLLIN, .revents = 0};
int ret;
do {
do {
ret = curl_poll(&pfd, 1, 0);
} while (ret == -1 && errno == EINTR);
if (ret == -1) {
log_perror_err("availabledata: curl_poll() failed");
continue;
}
} while (ret == -1);
return pfd.revents & POLLIN ? 1 : 0;
}
void flushhw(void)
{
size_t size = 1;
char buffer[PACKET_SIZE];
switch (curr_driver->rec_mode) {
case LIRC_MODE_MODE2:
while (availabledata())
curr_driver->readdata(0);
return;
case LIRC_MODE_LIRCCODE:
size = curr_driver->code_length / CHAR_BIT;
if (curr_driver->code_length % CHAR_BIT)
size++;
break;
}
while (read(curr_driver->fd, buffer, size) == size)
;
}
int resethw(int started_as_root)
{
int flags;
if (started_as_root)
if (seteuid(0) == -1)
log_error("Cannot reset root uid");
if (curr_driver->deinit_func)
curr_driver->deinit_func();
if (curr_driver->init_func) {
if (!curr_driver->init_func()) {
drop_sudo_root(seteuid);
return 0;
}
}
flags = fcntl(curr_driver->fd, F_GETFL, 0);
if (flags == -1 ||
fcntl(curr_driver->fd, F_SETFL, flags | O_NONBLOCK) == -1) {
if (curr_driver->deinit_func)
curr_driver->deinit_func();
drop_sudo_root(seteuid);
return 0;
}
drop_sudo_root(seteuid);
return 1;
}
void gap_state_init(struct gap_state* state)
{
memset(state, 0, sizeof(struct gap_state));
}
void lengths_state_init(struct lengths_state* state)
{
count = 0;
count_spaces = 0;
count_3repeats = 0;
count_5repeats = 0;
count_signals = 0;
first_length = 0;
first_lengths = 0;
second_lengths = 0;
memset(state, 0, sizeof(struct lengths_state));
state->first_signal = -1;
state->retval = 1;
}
void toggle_state_init(struct toggle_state* state)
{
memset(state, 0, sizeof(struct toggle_state));
state->retries = 30;
state->retval = EXIT_SUCCESS;
}
void button_state_init(struct button_state* state, int started_as_root)
{
memset(state, 0, sizeof(struct button_state));
state->started_as_root = started_as_root;
state->retval = EXIT_SUCCESS;
}
static lirc_t calc_signal(struct lengths* len)
{
if (len->count == 0)
return 0;
return (lirc_t)(len->sum / len->count);
}
static void set_toggle_bit_mask(struct ir_remote* remote, ir_code xor)
{
ir_code mask;
struct ir_ncode* codes;
int bits;
if (!remote->codes)
return;
bits = bit_count(remote);
mask = ((ir_code)1) << (bits - 1);
while (mask) {
if (mask == xor)
break;
mask = mask >> 1;
}
if (mask) {
remote->toggle_bit_mask = xor;
codes = remote->codes;
while (codes->name != NULL) {
codes->code &= ~xor;
codes++;
}
}
/* Sharp, Denon and some others use a toggle_mask */
else if (bits == 15 && xor == 0x3ff) {
remote->toggle_mask = xor;
} else {
remote->toggle_bit_mask = xor;
}
}
void get_pre_data(struct ir_remote* remote)
{
struct ir_ncode* codes;
ir_code mask, last;
int count, i;
struct ir_code_node* n;
if (remote->bits == 0)
return;
mask = (-1);
codes = remote->codes;
if (codes->name == NULL)
return; /* at least 2 codes needed */
last = codes->code;
codes++;
if (codes->name == NULL)
return; /* at least 2 codes needed */
while (codes->name != NULL) {
mask &= ~(last ^ codes->code);
last = codes->code;
for (n = codes->next; n != NULL; n = n->next) {
mask &= ~(last ^ n->code);
last = n->code;
}
codes++;
}
count = 0;
while (mask & 0x8000000000000000LL) {
count++;
mask = mask << 1;
}
count -= sizeof(ir_code) * CHAR_BIT - remote->bits;
/* only "even" numbers should go to pre/post data */
if (count % 8 && (remote->bits - count) % 8)
count -= count % 8;
if (count > 0) {
mask = 0;
for (i = 0; i < count; i++) {
mask = mask << 1;
mask |= 1;
}
remote->bits -= count;
mask = mask << (remote->bits);
remote->pre_data_bits = count;
remote->pre_data = (last & mask) >> (remote->bits);
codes = remote->codes;
while (codes->name != NULL) {
codes->code &= ~mask;
for (n = codes->next; n != NULL; n = n->next)
n->code &= ~mask;
codes++;
}
}
}
void get_post_data(struct ir_remote* remote)
{
struct ir_ncode* codes;
ir_code mask, last;
int count, i;
struct ir_code_node* n;
if (remote->bits == 0)
return;
mask = (-1);
codes = remote->codes;
if (codes->name == NULL)
return; /* at least 2 codes needed */
last = codes->code;
codes++;
if (codes->name == NULL)
return; /* at least 2 codes needed */
while (codes->name != NULL) {
mask &= ~(last ^ codes->code);
last = codes->code;
for (n = codes->next; n != NULL; n = n->next) {
mask &= ~(last ^ n->code);
last = n->code;
}
codes++;
}
count = 0;
while (mask & 0x1) {
count++;
mask = mask >> 1;
}
/* only "even" numbers should go to pre/post data */
if (count % 8 && (remote->bits - count) % 8)
count -= count % 8;
if (count > 0) {
mask = 0;
for (i = 0; i < count; i++) {
mask = mask << 1;
mask |= 1;
}
remote->bits -= count;
remote->post_data_bits = count;
remote->post_data = last & mask;
codes = remote->codes;
while (codes->name != NULL) {
codes->code = codes->code >> count;
for (n = codes->next; n != NULL; n = n->next)
n->code = n->code >> count;
codes++;
}
}
}
void remove_pre_data(struct ir_remote* remote)
{
struct ir_ncode* codes;
struct ir_code_node* n;
if (remote->pre_data_bits == 0
|| remote->pre_p != 0
|| remote->pre_s != 0)
return;
for (codes = remote->codes; codes->name != NULL; codes++) {
codes->code |= remote->pre_data << remote->bits;
for (n = codes->next; n != NULL; n = n->next)
n->code |= remote->pre_data << remote->bits;
}
remote->bits += remote->pre_data_bits;
remote->pre_data = 0;
remote->pre_data_bits = 0;
}
void remove_post_data(struct ir_remote* remote)
{
struct ir_ncode* codes;
struct ir_code_node* n;
if (remote->post_data_bits == 0)
return;
for (codes = remote->codes; codes->name != NULL; codes++) {
codes->code <<= remote->post_data_bits;
codes->code |= remote->post_data;
for (n = codes->next; n != NULL; n = n->next) {
n->code <<= remote->post_data_bits;
n->code |= remote->post_data;
}
}
remote->bits += remote->post_data_bits;
remote->post_data = 0;
remote->post_data_bits = 0;
}
void invert_data(struct ir_remote* remote)
{
struct ir_ncode* codes;
ir_code mask;
lirc_t p, s;
struct ir_code_node* n;
/* swap one, zero */
p = remote->pone;
s = remote->sone;
remote->pone = remote->pzero;
remote->sone = remote->szero;
remote->pzero = p;
remote->szero = s;
/* invert pre_data */
if (has_pre(remote)) {
mask = gen_mask(remote->pre_data_bits);
remote->pre_data ^= mask;
}
/* invert post_data */
if (has_post(remote)) {
mask = gen_mask(remote->post_data_bits);
remote->post_data ^= mask;
}
if (remote->bits == 0)
return;
/* invert codes */
mask = gen_mask(remote->bits);
for (codes = remote->codes; codes->name != NULL; codes++) {
codes->code ^= mask;
for (n = codes->next; n != NULL; n = n->next)
n->code ^= mask;
}
}
void remove_trail(struct ir_remote* remote)
{
int extra_bit;
if (!is_space_enc(remote))
return;
if (remote->ptrail == 0)
return;
if (expect(remote, remote->pone, remote->pzero)
|| expect(remote, remote->pzero, remote->pone))
return;
if (!(expect(remote, remote->sone, remote->szero)
&& expect(remote, remote->szero, remote->sone)))
return;
if (expect(remote, remote->ptrail, remote->pone))
extra_bit = 1;
else if (expect(remote, remote->ptrail, remote->pzero))
extra_bit = 0;
else
return;
remote->post_data_bits++;
remote->post_data <<= 1;
remote->post_data |= extra_bit;
remote->ptrail = 0;
}
void for_each_remote(struct ir_remote* remotes, remote_func func)
{
struct ir_remote* remote;
remote = remotes;
while (remote != NULL) {
func(remote);
remote = remote->next;
}
}
static int mywaitfordata(uint32_t maxusec)
{
int ret;
struct pollfd pfd = {
.fd = curr_driver->fd, .events = POLLIN, .revents = 0};
do {
ret = curl_poll(&pfd, 1, maxusec / 1000);
} while (ret == -1 && errno == EINTR);
if (ret == -1 && errno != EINTR)
log_perror_err("mywaitfordata: curl_poll() failed");
return (pfd.revents & POLLIN) != 0;
}
static lirc_t emulation_readdata(lirc_t timeout)
{
static lirc_t sum = 0;
lirc_t data = 0;
if (current_code == NULL) {
data = 1000000;
if (next_code)
current_code = next_code;
else
current_code = emulation_data->codes;
current_rep = 0;
sum = 0;
} else {
if (current_code->name == NULL) {
log_warn("%s: no data found", emulation_data->name);
data = 0;
}
if (current_index >= current_code->length) {
if (next_code) {
current_code = next_code;
} else {
current_rep++;
if (current_rep > 2) {
current_code++;
current_rep = 0;
data = 1000000;
}
}
current_index = 0;
if (current_code->name == NULL) {
current_code = NULL;
return emulation_readdata(timeout);
}
if (data == 0) {
if (is_const(emulation_data))
data = emulation_data->gap - sum;
else
data = emulation_data->gap;
}
sum = 0;
} else {
data = current_code->signals[current_index];
if ((current_index % 2) == 0)
data |= PULSE_BIT;
current_index++;
sum += data & PULSE_MASK;
}
}
log_debug("delivering: %c%u\n",
data & PULSE_BIT ? 'p':'s', data & PULSE_MASK);
return data;
}
static struct lengths* new_length(lirc_t length)
{
struct lengths* l;
l = malloc(sizeof(struct lengths));
if (l == NULL)
return NULL;
l->count = 1;
l->sum = length;
l->lower_bound = length / 100 * 100;
l->upper_bound = length / 100 * 100 + 99;
l->min = l->max = length;
l->next = NULL;
return l;
}
void unlink_length(struct lengths** first, struct lengths* remove)
{
struct lengths* last;
struct lengths* scan;
if (remove == *first) {
*first = remove->next;
remove->next = NULL;
return;
}
scan = (*first)->next;
last = *first;
while (scan) {
if (scan == remove) {
last->next = remove->next;
remove->next = NULL;
return;
}
last = scan;
scan = scan->next;
}
log_error("unlink_length(): report this bug!");
}
int add_length(struct lengths** first, lirc_t length)
{
struct lengths* l;
struct lengths* last;
if (*first == NULL) {
*first = new_length(length);
if (*first == NULL)
return 0;
return 1;
}
l = *first;
while (l != NULL) {
if (l->lower_bound <= length && length <= l->upper_bound) {
l->count++;
l->sum += length;
l->min = min(l->min, length);
l->max = max(l->max, length);
return 1;
}
last = l;
l = l->next;
}
last->next = new_length(length);
if (last->next == NULL)
return 0;
return 1;
}
void free_lengths(struct lengths** firstp)
{
struct lengths* first;
struct lengths* next;
first = *firstp;
if (first == NULL)
return;
while (first != NULL) {
next = first->next;
free(first);
first = next;
}
*firstp = NULL;
}
void free_all_lengths(void)
{
free_lengths(&first_space);
free_lengths(&first_pulse);
free_lengths(&first_sum);
free_lengths(&first_gap);
free_lengths(&first_repeat_gap);
free_lengths(&first_signal_length);
free_lengths(&first_headerp);
free_lengths(&first_headers);
free_lengths(&first_1lead);
free_lengths(&first_3lead);
free_lengths(&first_trail);
free_lengths(&first_repeatp);
free_lengths(&first_repeats);
}
static void merge_lengths(struct lengths* first)
{
struct lengths* l;
struct lengths* inner;
struct lengths* last;
uint32_t new_sum;
int new_count;
l = first;
while (l != NULL) {
last = l;
inner = l->next;
while (inner != NULL) {
new_sum = l->sum + inner->sum;
new_count = l->count + inner->count;
if ((l->max <= new_sum / new_count + aeps
&& l->min + aeps >= new_sum / new_count
&& inner->max <= new_sum / new_count + aeps
&& inner->min + aeps >= new_sum / new_count)
|| (l->max <= new_sum / new_count * (100 + eps)
&& l->min >= new_sum / new_count * (100 - eps)
&& inner->max <= new_sum / new_count *
(100 + eps)
&& inner->min >= new_sum / new_count *
(100 - eps))) {
l->sum = new_sum;
l->count = new_count;
l->upper_bound = max(l->upper_bound,
inner->upper_bound);
l->lower_bound = min(l->lower_bound,
inner->lower_bound);
l->min = min(l->min, inner->min);
l->max = max(l->max, inner->max);
last->next = inner->next;
free(inner);
inner = last;
}
last = inner;
inner = inner->next;
}
l = l->next;
}
for (l = first; l != NULL; l = l->next) {
log_debug("%d x %u [%u,%u]",
l->count, (uint32_t)calc_signal(l),
(uint32_t)l->min, (uint32_t)l->max);
}
}
static struct lengths* get_max_length(struct lengths* first,
unsigned int* sump)
{
unsigned int sum;
struct lengths* scan;
struct lengths* max_length;
if (first == NULL)
return NULL;
max_length = first;
sum = first->count;
if (first->count > 0)
log_debug("%u x %u", first->count,
(uint32_t)calc_signal(first));
scan = first->next;
while (scan) {
if (scan->count > max_length->count)
max_length = scan;
sum += scan->count;
log_debug(
"%u x %u",
scan->count,
(uint32_t)calc_signal(scan));
scan = scan->next;
}
if (sump != NULL)
*sump = sum;
return max_length;
}
int get_trail_length(struct ir_remote* remote, int interactive)
{
unsigned int sum = 0, max_count;
struct lengths* max_length;
if (is_biphase(remote))
return 1;
max_length = get_max_length(first_trail, &sum);
max_count = max_length->count;
log_debug(
"get_trail_length(): sum: %u, max_count %u",
sum, max_count);
if (max_count >= sum * TH_TRAIL / 100) {
log_debug("Found trail pulse: %lu",
(uint32_t)calc_signal(max_length));
remote->ptrail = calc_signal(max_length);
return 1;
}
log_debug("No trail pulse found.");
return 1;
}
int get_lead_length(struct ir_remote* remote, int interactive)
{
unsigned int sum = 0, max_count;
struct lengths* first_lead;
struct lengths* max_length;
struct lengths* max2_length;
lirc_t a, b, swap;
if (!is_biphase(remote) || has_header(remote))
return 1;
if (is_rc6(remote))
return 1;
first_lead = has_header(remote) ? first_3lead : first_1lead;
max_length = get_max_length(first_lead, &sum);
max_count = max_length->count;
log_debug(
"get_lead_length(): sum: %u, max_count %u",
sum, max_count);
if (max_count >= sum * TH_LEAD / 100) {
log_debug(
"Found lead pulse: %lu",
(uint32_t)calc_signal(max_length));
remote->plead = calc_signal(max_length);
return 1;
}
unlink_length(&first_lead, max_length);
max2_length = get_max_length(first_lead, &sum);
max_length->next = first_lead;
first_lead = max_length;
a = calc_signal(max_length);
b = calc_signal(max2_length);
if (a > b) {
swap = a;
a = b;
b = swap;
}
if (abs(2 * a - b) < b * eps / 100 || abs(2 * a - b) < aeps) {
log_debug(
"Found hidden lead pulse: %lu",
(uint32_t)a);
remote->plead = a;
return 1;
}
log_debug("No lead pulse found.");
return 1;
}
int get_header_length(struct ir_remote* remote, int interactive)
{
unsigned int sum, max_count;
lirc_t headerp, headers;
struct lengths* max_plength;
struct lengths* max_slength;
if (first_headerp != NULL) {
max_plength = get_max_length(first_headerp, &sum);
max_count = max_plength->count;
} else {
log_debug("No header data.");
return 1;
}
log_debug(
"get_header_length(): sum: %u, max_count %u",
sum, max_count);
if (max_count >= sum * TH_HEADER / 100) {
max_slength = get_max_length(first_headers, &sum);
max_count = max_slength->count;
log_debug(
"get_header_length(): sum: %u, max_count %u",
sum, max_count);
if (max_count >= sum * TH_HEADER / 100) {
headerp = calc_signal(max_plength);
headers = calc_signal(max_slength);
log_debug(
"Found possible header: %lu %lu",
(uint32_t)headerp,
(uint32_t)headers);
remote->phead = headerp;
remote->shead = headers;
if (first_lengths < second_lengths) {
log_debug(
"Header is not being repeated.");
remote->flags |= NO_HEAD_REP;
}
return 1;
}
}
log_debug("No header found.");
return 1;
}
int get_repeat_length(struct ir_remote* remote, int interactive)
{
unsigned int sum = 0, max_count;
lirc_t repeatp, repeats, repeat_gap;
struct lengths* max_plength;
struct lengths* max_slength;
if (!((count_3repeats > SAMPLES / 2 ? 1 : 0) ^
(count_5repeats > SAMPLES / 2 ? 1 : 0))) {
if (count_3repeats > SAMPLES / 2
|| count_5repeats > SAMPLES / 2) {
log_warn("Repeat inconsistency.");
return 0;
}
log_debug("No repeat code found.");
return 1;
}
max_plength = get_max_length(first_repeatp, &sum);
max_count = max_plength->count;
log_debug(
"get_repeat_length(): sum: %u, max_count %u",
sum, max_count);
if (max_count >= sum * TH_REPEAT / 100) {
max_slength = get_max_length(first_repeats, &sum);
max_count = max_slength->count;
log_debug(
"get_repeat_length(): sum: %u, max_count %u",
sum, max_count);
if (max_count >= sum * TH_REPEAT / 100) {
if (count_5repeats > count_3repeats
&& !has_header(remote)) {
log_warn(
"Repeat code has header,"
" but no header found!");
return 0;
}
if (count_5repeats > count_3repeats
&& has_header(remote))
remote->flags |= REPEAT_HEADER;
repeatp = calc_signal(max_plength);
repeats = calc_signal(max_slength);
log_debug(
"Found repeat code: %lu %lu",
(uint32_t)repeatp,
(uint32_t)repeats);
remote->prepeat = repeatp;
remote->srepeat = repeats;
if (!(remote->flags & CONST_LENGTH)) {
max_slength = get_max_length(first_repeat_gap,
NULL);
repeat_gap = calc_signal(max_slength);
log_debug(
"Found repeat gap: %lu",
(uint32_t)repeat_gap);
remote->repeat_gap = repeat_gap;
}
return 1;
}
}
log_debug("No repeat header found.");
return 1;
}
void get_scheme(struct ir_remote* remote, int interactive)
{
unsigned int i, length = 0, sum = 0;
struct lengths* maxp;
struct lengths* max2p;
struct lengths* maxs;
struct lengths* max2s;
for (i = 1; i < MAX_SIGNALS; i++) {
if (lengths[i] > lengths[length])
length = i;
sum += lengths[i];
if (lengths[i] > 0)
log_debug("%u: %u", i, lengths[i]);
}
log_debug("get_scheme(): sum: %u length: %u signals: %u"
" first_lengths: %u second_lengths: %u\n",
sum, length + 1, lengths[length],
first_lengths, second_lengths);
/* FIXME !!! this heuristic is too bad */
if (lengths[length] >= TH_SPACE_ENC * sum / 100) {
length++;
log_debug(
"Space/pulse encoded remote control found.");
log_debug("Signal length is %u.", length);
/* this is not yet the number of bits */
remote->bits = length;
set_protocol(remote, SPACE_ENC);
return;
}
maxp = get_max_length(first_pulse, NULL);
unlink_length(&first_pulse, maxp);
if (first_pulse == NULL)
first_pulse = maxp;
max2p = get_max_length(first_pulse, NULL);
maxp->next = first_pulse;
first_pulse = maxp;
maxs = get_max_length(first_space, NULL);
unlink_length(&first_space, maxs);
if (first_space == NULL) {
first_space = maxs;
} else {
max2s = get_max_length(first_space, NULL);
maxs->next = first_space;
first_space = maxs;
maxs = get_max_length(first_space, NULL);
if (length > 20
&& (calc_signal(maxp) < TH_RC6_SIGNAL
|| calc_signal(max2p) < TH_RC6_SIGNAL)
&& (calc_signal(maxs) < TH_RC6_SIGNAL
|| calc_signal(max2s) < TH_RC6_SIGNAL)) {
log_debug("RC-6 remote control found.");
set_protocol(remote, RC6);
} else {
log_debug("RC-5 remote control found.");
set_protocol(remote, RC5);
}
return;
}
length++;
log_debug("Suspicious data length: %u.", length);
/* this is not yet the number of bits */
remote->bits = length;
set_protocol(remote, SPACE_ENC);
}
int get_data_length(struct ir_remote* remote, int interactive)
{
unsigned int sum = 0, max_count;
lirc_t p1, p2, s1, s2;
struct lengths* max_plength;
struct lengths* max_slength;
struct lengths* max2_plength;
struct lengths* max2_slength;
max_plength = get_max_length(first_pulse, &sum);
max_count = max_plength->count;
log_debug("get_data_length(): sum: %u, max_count %u",
sum, max_count);
if (max_count >= sum * TH_IS_BIT / 100) {
unlink_length(&first_pulse, max_plength);
max2_plength = get_max_length(first_pulse, NULL);
if (max2_plength != NULL)
if (max2_plength->count < max_count * TH_IS_BIT / 100)
max2_plength = NULL;
log_debug("Pulse candidates: ");
log_debug("%u x %u", max_plength->count,
(uint32_t)calc_signal(max_plength));
if (max2_plength)
log_debug(", %u x %u",
max2_plength->count,
(uint32_t)calc_signal(max2_plength));
max_slength = get_max_length(first_space, &sum);
max_count = max_slength->count;
log_debug(
"get_data_length(): sum: %u, max_count %u",
sum, max_count);
if (max_count >= sum * TH_IS_BIT / 100) {
unlink_length(&first_space, max_slength);
max2_slength = get_max_length(first_space, NULL);
if (max2_slength != NULL)
if (max2_slength->count <
max_count * TH_IS_BIT / 100)
max2_slength = NULL;
if (max_count >= sum * TH_IS_BIT / 100) {
log_debug("Space candidates: ");
log_debug(
"%u x %u",
max_slength->count,
(uint32_t)calc_signal(max_slength));
if (max2_slength) {
log_debug(
"%u x %u",
max2_slength->count,
(uint32_t)calc_signal(max2_slength));
}
}
remote->eps = eps;
remote->aeps = aeps;
if (is_biphase(remote)) {
if (max2_plength == NULL
|| max2_slength == NULL) {
log_notice(
"Unknown encoding found.");
return 0;
}
log_debug(
"Signals are biphase encoded.");
p1 = calc_signal(max_plength);
p2 = calc_signal(max2_plength);
s1 = calc_signal(max_slength);
s2 = calc_signal(max2_slength);
remote->pone =
(min(p1, p2) + max(p1, p2) / 2) / 2;
remote->sone =
(min(s1, s2) + max(s1, s2) / 2) / 2;
remote->pzero = remote->pone;
remote->szero = remote->sone;
} else {
if (max2_plength == NULL
&& max2_slength == NULL) {
log_notice(
"No encoding found");
return 0;
}
if (max2_plength && max2_slength) {
log_notice(
"Unknown encoding found.");
return 0;
}
p1 = calc_signal(max_plength);
s1 = calc_signal(max_slength);
if (max2_plength) {
p2 = calc_signal(max2_plength);
log_debug("Signals are pulse encoded.");
remote->pone = max(p1, p2);
remote->sone = s1;
remote->pzero = min(p1, p2);
remote->szero = s1;
if (expect(remote, remote->ptrail, p1)
|| expect(remote, remote->ptrail,
p2))
remote->ptrail = 0;
} else {
s2 = calc_signal(max2_slength);
log_debug("Signals are space encoded.");
remote->pone = p1;
remote->sone = max(s1, s2);
remote->pzero = p1;
remote->szero = min(s1, s2);
}
}
if (has_header(remote)
&& (!has_repeat(remote)
|| remote->flags & NO_HEAD_REP)) {
if (!is_biphase(remote)
&& ((expect(remote, remote->phead,
remote->pone)
&& expect(remote,
remote->shead,
remote->sone))
|| (expect(remote,
remote->phead,
remote->pzero)
&& expect(remote,
remote->shead,
remote->szero)))) {
remote->phead = remote->shead = 0;
remote->flags &= ~NO_HEAD_REP;
log_debug(
"Removed header.");
}
if (is_biphase(remote)
&& expect(remote,
remote->shead,
remote->sone)) {
remote->plead = remote->phead;
remote->phead = remote->shead = 0;
remote->flags &= ~NO_HEAD_REP;
log_debug(
"Removed header.");
}
}
if (is_biphase(remote)) {
struct lengths* signal_length;
lirc_t data_length;
signal_length =
get_max_length(first_signal_length,
NULL);
data_length =
calc_signal(signal_length) -
remote->plead - remote->phead -
remote->shead +
/* + 1/2 bit */
(remote->pone + remote->sone) / 2;
remote->bits = data_length / (remote->pone +
remote->sone);
if (is_rc6(remote))
remote->bits--;
} else {
remote->bits =
(remote->bits -
(has_header(remote) ? 2 : 0) + 1 -
(remote->ptrail > 0 ? 2 : 0)) / 2;
}
log_debug(
"Signal length is %d",
remote->bits);
free_lengths(&max_plength);
free_lengths(&max_slength);
return 1;
}
free_lengths(&max_plength);
}
log_notice("Could not find data lengths.");
return 0;
}
enum get_gap_status get_gap_length(struct gap_state* state,
struct ir_remote* remote)
{
while (availabledata())
curr_driver->rec_func(NULL);
if (!mywaitfordata(10000000)) {
free_lengths(&(state->gaps));
return STS_GAP_TIMEOUT;
}
gettimeofday(&(state->start), NULL);
while (availabledata())
curr_driver->rec_func(NULL);
gettimeofday(&(state->end), NULL);
if (state->flag) {
state->gap = time_elapsed(&(state->last), &(state->start));
add_length(&(state->gaps), state->gap);
merge_lengths(state->gaps);
state->maxcount = 0;
state->scan = state->gaps;
while (state->scan) {
state->maxcount = max(state->maxcount,
state->scan->count);
if (state->scan->count > SAMPLES) {
remote->gap = calc_signal(state->scan);
free_lengths(&(state->gaps));
return STS_GAP_FOUND;
}
state->scan = state->scan->next;
}
if (state->maxcount > state->lastmaxcount) {
state->lastmaxcount = state->maxcount;
return STS_GAP_GOT_ONE_PRESS;
}
} else {
state->flag = 1;
}
state->last = state->end;
return STS_GAP_AGAIN;
}
int needs_toggle_mask(struct ir_remote* remote)
{
struct ir_ncode* codes;
if (!is_rc6(remote))
return 0;
if (remote->codes) {
codes = remote->codes;
while (codes->name != NULL) {
if (codes->next)
/* asume no toggle bit mask when key
* sequences are used */
return 0;
codes++;
}
}
return 1;
}
/* Compute lengths from four recorded signals. */
static void compute_lengths_4_signals(void)
{
add_length(&first_repeatp, signals[0]);
merge_lengths(first_repeatp);
add_length(&first_repeats, signals[1]);
merge_lengths(first_repeats);
add_length(&first_trail, signals[2]);
merge_lengths(first_trail);
add_length(&first_repeat_gap, signals[3]);
merge_lengths(first_repeat_gap);
}
/* Compute lengths from six recorded signals. */
static void compute_lengths_6_signals(void)
{
add_length(&first_headerp, signals[0]);
merge_lengths(first_headerp);
add_length(&first_headers, signals[1]);
merge_lengths(first_headers);
add_length(&first_repeatp, signals[2]);
merge_lengths(first_repeatp);
add_length(&first_repeats, signals[3]);
merge_lengths(first_repeats);
add_length(&first_trail, signals[4]);
merge_lengths(first_trail);
add_length(&first_repeat_gap, signals[5]);
merge_lengths(first_repeat_gap);
}
/* Compute lengths from more than six recorded signals. */
static void compute_lengths_many_signals(struct lengths_state* state)
{
int i;
add_length(&first_1lead, signals[0]);
merge_lengths(first_1lead);
for (i = 2; i < state->count - 2; i++) {
if (i % 2) {
add_length(&first_space, signals[i]);
merge_lengths(first_space);
} else {
add_length(&first_pulse, signals[i]);
merge_lengths(first_pulse);
}
}
add_length(&first_trail, signals[state->count - 2]);
merge_lengths(first_trail);
lengths[state->count - 2]++;
add_length(&first_signal_length, state->sum - state->data);
merge_lengths(first_signal_length);
if (state->first_signal == 1
|| (first_length > 2
&& first_length - 2 != state->count - 2)) {
add_length(&first_3lead, signals[2]);
merge_lengths(first_3lead);
add_length(&first_headerp, signals[0]);
merge_lengths(first_headerp);
add_length(&first_headers, signals[1]);
merge_lengths(first_headers);
}
if (state->first_signal == 1) {
first_lengths++;
first_length = state->count - 2;
state->header = signals[0] + signals[1];
} else if (state->first_signal == 0
&& first_length - 2 == state->count - 2) {
lengths[state->count - 2]--;
lengths[state->count - 2 + 2]++;
second_lengths++;
}
}
static struct lengths* scan_gap1(struct lengths_state* state,
struct ir_remote* remote,
int* maxcount,
enum lengths_status* again)
{
struct lengths* scan;
for (scan = first_sum; scan; scan = scan->next) {
*maxcount = max(*maxcount, scan->count);
if (scan->count > SAMPLES) {
remote->gap = calc_signal(scan);
remote->flags |= CONST_LENGTH;
state->mode = MODE_HAVE_GAP;
log_debug("Found gap: %u", remote->gap);
*again = STS_LEN_AGAIN_INFO;
break;
}
}
return scan;
}
static struct lengths* scan_gap2(struct lengths_state* state,
struct ir_remote* remote,
int* maxcount,
enum lengths_status* again)
{
struct lengths* scan;
for (scan = first_gap; scan; scan = scan->next) {
*maxcount = max(*maxcount, scan->count);
if (scan->count > SAMPLES) {
remote->gap = calc_signal(scan);
state->mode = MODE_HAVE_GAP;
log_debug("Found gap: %u", remote->gap);
*again = STS_LEN_AGAIN_INFO;
break;
}
}
return scan;
}
enum lengths_status get_lengths(struct lengths_state* state,
struct ir_remote* remote,
int force, int interactive)
{
struct lengths* scan;
int maxcount = 0;
static int lastmaxcount = 0;
enum lengths_status again = STS_LEN_AGAIN;
state->data = curr_driver->readdata(10000000);
if (!state->data) {
state->retval = 0;
return STS_LEN_TIMEOUT;
}
if (is_timeout(state->data) || is_overflow(state->data)) {
return STS_LEN_AGAIN;
}
state->count++;
if (state->mode == MODE_GET_GAP) {
if (state->sum != 0 || is_pulse(state->data)) {
state->sum += state->data & PULSE_MASK;
}else{
return STS_LEN_AGAIN;
}
if (state->average == 0 && is_space(state->data)) {
if (state->data > 100000) {
state->sum = 0;
return STS_LEN_AGAIN;
}
state->average = state->data;
state->maxspace = state->data;
} else if (is_space(state->data)) {
if (state->data > MIN_GAP
|| state->data > 100 * state->average
/* this MUST be a gap */
|| (state->data >= 5000 && count_spaces > 10
&& state->data > 5 * state->average)
|| (state->data < 5000 && count_spaces > 10
&& state->data > 5 * state->maxspace / 2)) {
add_length(&first_sum, state->sum);
merge_lengths(first_sum);
add_length(&first_gap, state->data);
merge_lengths(first_gap);
state->sum = 0;
count_spaces = 0;
state->average = 0;
state->maxspace = 0;
maxcount = 0;
scan = scan_gap1(state,
remote,
&maxcount,
&again);
if (scan == NULL) {
scan = scan_gap2(state,
remote,
&maxcount,
&again);
}
if (scan != NULL) {
state->mode = MODE_HAVE_GAP;
state->sum = 0;
state->count = 0;
state->remaining_gap =
is_const(remote) ?
(remote->gap >
state->data ?
remote->gap - state->data : 0)
: (has_repeat_gap(remote) ?
remote->
repeat_gap : remote->gap);
if (force) {
state->retval = 0;
return STS_LEN_RAW_OK;
}
return STS_LEN_AGAIN_INFO;
}
lastmaxcount = maxcount;
state->keypresses = lastmaxcount;
return again;
}
state->average =
(state->average * count_spaces + state->data)
/ (count_spaces + 1);
count_spaces++;
if (state->data > state->maxspace)
state->maxspace = state->data;
}
if (state->count > SAMPLES * MAX_SIGNALS * 2) {
state->retval = 0;
return STS_LEN_NO_GAP_FOUND;
}
state->keypresses = lastmaxcount;
return STS_LEN_AGAIN;
} else if (state->mode == MODE_HAVE_GAP) {
if (state->count==1 && is_space(state->data)) {
state->count = 0;
return STS_LEN_AGAIN;
}
if (state->count <= MAX_SIGNALS) {
signals[state->count - 1] = state->data & PULSE_MASK;
} else {
state->retval = 0;
return STS_LEN_TOO_LONG;
}
if (is_const(remote))
state->remaining_gap =
remote->gap > state->sum ?
remote->gap - state->sum : 0;
else
state->remaining_gap = remote->gap;
state->sum += state->data & PULSE_MASK;
if (state->count > 2
&& ((state->data & PULSE_MASK) >=
state->remaining_gap * (100 - eps) / 100
|| (state->data & PULSE_MASK) >=
state->remaining_gap - aeps)) {
if (is_space(state->data)) {
/* signal complete */
state->keypresses += 1;
if (state->count == 4) {
count_3repeats++;
compute_lengths_4_signals();
} else if (state->count == 6) {
count_5repeats++;
compute_lengths_6_signals();
} else if (state->count > 6) {
count_signals++;
compute_lengths_many_signals(state);
}
state->count = 0;
state->sum = 0;
}
/* such long pulses may appear with
* crappy hardware (receiver? / remote?)
*/
else if(is_pulse(state->data)) {
remote->gap = 0;
return STS_LEN_NO_GAP_FOUND;
}
if (count_signals >= SAMPLES) {
get_scheme(remote, interactive);
if (!get_header_length(remote, interactive)
|| !get_trail_length(remote, interactive)
|| !get_lead_length(remote, interactive)
|| !get_repeat_length(remote, interactive)
|| !get_data_length(remote, interactive))
state->retval = 0;
return state->retval ==
0 ? STS_LEN_FAIL : STS_LEN_OK;
}
if ((state->data & PULSE_MASK) <=
(state->remaining_gap + state->header) *
(100 + eps) / 100
|| (state->data & PULSE_MASK) <=
(state->remaining_gap + state->header) + aeps) {
state->first_signal = 0;
state->header = 0;
} else {
state->first_signal = 1;
}
}
}
return STS_LEN_AGAIN;
}
enum toggle_status get_toggle_bit_mask(struct toggle_state* state,
struct ir_remote* remote)
{
struct decode_ctx_t decode_ctx = { 0 };
int i;
ir_code mask;
if (!state->inited) {
sleep(1);
while (availabledata())
curr_driver->rec_func(NULL);
state->inited = 1;
}
if (state->retries <= 0) {
if (!state->found)
return STS_TGL_NOT_FOUND;
if (state->seq > 0) {
remote->min_repeat = state->repeats / state->seq;
log_debug("min_repeat=%d",
remote->min_repeat);
}
return STS_TGL_FOUND;
}
if (!mywaitfordata(10000000))
return STS_TGL_TIMEOUT;
curr_driver->rec_func(remote);
if (is_rc6(remote) && remote->rc6_mask == 0) {
for (i = 0, mask = 1; i < remote->bits; i++, mask <<= 1) {
remote->rc6_mask = mask;
state->success =
curr_driver->decode_func(remote, &decode_ctx);
if (state->success) {
remote->min_remaining_gap =
decode_ctx.min_remaining_gap;
remote->max_remaining_gap =
decode_ctx.max_remaining_gap;
break;
}
}
if (!state->success)
remote->rc6_mask = 0;
} else {
state->success =
curr_driver->decode_func(remote, &decode_ctx);
if (state->success) {
remote->min_remaining_gap =
decode_ctx.min_remaining_gap;
remote->max_remaining_gap =
decode_ctx.max_remaining_gap;
}
}
if (state->success) {
if (state->flag == 0) {
state->flag = 1;
state->first = decode_ctx.code;
} else if (!decode_ctx.repeat_flag
|| decode_ctx.code != state->last) {
state->seq++;
mask = state->first ^ decode_ctx.code;
if (!state->found && mask) {
set_toggle_bit_mask(remote, mask);
state->found = 1;
if (state->seq > 0)
remote->min_repeat =
state->repeats / state->seq;
}
state->retries--;
state->last = decode_ctx.code;
return STS_TGL_GOT_ONE_PRESS;
}
state->repeats++;
state->last = decode_ctx.code;
} else {
state->retries--;
while (availabledata())
curr_driver->rec_func(NULL);
}
return STS_TGL_AGAIN;
}
int analyse_get_lengths(struct lengths_state* lengths_state)
{
enum lengths_status status = STS_LEN_AGAIN;
while (status == STS_LEN_AGAIN) {
status = get_lengths(lengths_state, &remote, 0, 0);
switch (status) {
case STS_LEN_AGAIN_INFO:
status = STS_LEN_AGAIN;
break;
case STS_LEN_AGAIN:
break;
case STS_LEN_OK:
break;
case STS_LEN_FAIL:
log_error("get_lengths() failure");
return 0;
case STS_LEN_RAW_OK:
log_error("raw analyse result?!");
return 0;
case STS_LEN_TIMEOUT:
log_error("analyse timeout?!");
return 0;
case STS_LEN_NO_GAP_FOUND:
log_error("analyse, no gap?!");
return 0;
case STS_LEN_TOO_LONG:
log_error("analyse, signal too long?!");
return 0;
default:
log_error("Cannot read raw data (%d)",
status);
return 0;
}
}
return 1;
}
int analyse_remote(struct ir_remote* raw_data, const struct opts* opts)
{
struct ir_ncode* codes;
struct decode_ctx_t decode_ctx;
struct lengths_state lengths_state;
int code;
int code2;
struct ir_ncode* new_codes;
size_t new_codes_count = 100;
int new_index = 0;
int ret;
if (!is_raw(raw_data)) {
log_error("remote %s not in raw mode, ignoring",
raw_data->name);
return 0;
}
flushhw();
aeps = raw_data->aeps;
eps = raw_data->eps;
emulation_data = raw_data;
next_code = NULL;
current_code = NULL;
current_index = 0;
memset(&remote, 0, sizeof(remote));
lengths_state_init(&lengths_state);
if (!analyse_get_lengths(&lengths_state))
return 0;
if (is_rc6(&remote) && remote.bits >= 5)
/* have to assume something as it's very difficult to
* extract the rc6_mask from the data that we have */
remote.rc6_mask = ((ir_code)0x1ll) << (remote.bits - 5);
remote.name = raw_data->name;
remote.freq = raw_data->freq;
new_codes = malloc(new_codes_count * sizeof(*new_codes));
if (new_codes == NULL) {
log_error("Out of memory");
return 0;
}
memset(new_codes, 0, new_codes_count * sizeof(*new_codes));
codes = raw_data->codes;
while (codes->name != NULL) {
// printf("decoding %s\n", codes->name);
current_code = NULL;
current_index = 0;
next_code = codes;
rec_buffer_init();
ret = receive_decode(&remote, &decode_ctx);
if (!ret) {
log_warn(
"Decoding of %s failed", codes->name);
} else {
if (new_index + 1 >= new_codes_count) {
struct ir_ncode* renew_codes;
new_codes_count *= 2;
renew_codes =
realloc(new_codes,
new_codes_count *
sizeof(*new_codes));
if (renew_codes == NULL) {
log_error("Out of memory");
free(new_codes);
return 0;
}
memset(&new_codes[new_codes_count / 2],
0,
new_codes_count / 2 *
sizeof(*new_codes));
new_codes = renew_codes;
}
rec_buffer_clear();
code = decode_ctx.code;
ret = receive_decode(&remote, &decode_ctx);
code2 = decode_ctx.code;
decode_ctx.code = code;
if (ret && code2 != decode_ctx.code) {
new_codes[new_index].next =
malloc(IR_CODE_NODE_SIZE);
if (new_codes[new_index].next) {
memset(new_codes[new_index].next,
0,
IR_CODE_NODE_SIZE);
new_codes[new_index].next->code =
code2;
}
}
new_codes[new_index].name = codes->name;
new_codes[new_index].code = decode_ctx.code;
new_index++;
}
codes++;
}
new_codes[new_index].name = NULL;
remote.codes = new_codes;
fprint_remotes(stdout, &remote, opts->commandline);
remote.codes = NULL;
free(new_codes);
return 1;
}
int do_analyse(const struct opts* opts, struct main_state* state)
{
FILE* f;
struct ir_remote* r;
memcpy((void*)curr_driver, &hw_emulation, sizeof(struct driver));
f = fopen(opts->filename, "r");
if (f == NULL) {
fprintf(stderr, "Cannot open file: %s\n", opts->filename);
return 0;
}
r = read_config(f, opts->filename);
if (r == NULL) {
fprintf(stderr, "Cannot parse file: %s\n", opts->filename);
return 0;
}
for (; r != NULL; r = r->next) {
if (!is_raw(r)) {
log_error("remote %s not in raw mode, ignoring",
r->name);
continue;
}
analyse_remote(r, opts);
}
return 1;
}
ssize_t raw_read(void* buffer, size_t size, unsigned int timeout_us)
{
if (!mywaitfordata(timeout_us))
return 0;
return read(curr_driver->fd, buffer, size);
}
static int raw_data_ok(struct button_state* btn_state)
{
int r = 0;
int ref;
if (is_pulse(btn_state->data)) {
r = 0;
} else if (is_space(btn_state->data)) {
if (is_const(&remote)) {
if (remote.gap > btn_state->sum) {
ref = (remote.gap - btn_state->sum);
ref *= (100 - remote.eps);
ref /= 100;
} else {
ref = 0;
}
r = btn_state->data > ref;
} else {
r = btn_state->data > (remote.gap * (100 - remote.eps)) / 100;
}
}
return r;
}
enum button_status record_buttons(struct button_state* btn_state,
enum button_status last_status,
struct main_state* state,
const struct opts* opts)
{
const char* const MSG_BAD_LENGTH =
"Signal length is %d\n"
"That's weird because the signal length must be odd!\n";
ir_code code2;
int decode_ok;
uint32_t timeout;
int retries;
struct ir_remote* my_remote;
FILE* f;
enum button_status sts;
if (btn_state->no_data) {
btn_state->no_data = 0;
return STS_BTN_TIMEOUT;
}
switch (last_status) {
case STS_BTN_INIT:
return STS_BTN_GET_NAME;
case STS_BTN_GET_NAME:
if (strchr(btn_state->buffer, ' ') != NULL) {
btn_state_set_message(
btn_state,
"The name must not contain any whitespace.");
return STS_BTN_SOFT_ERROR;
}
if (strchr(btn_state->buffer, '\t') != NULL) {
btn_state_set_message(
btn_state,
"The name must not contain any whitespace.");
return STS_BTN_SOFT_ERROR;
}
if (strcasecmp(btn_state->buffer, "begin") == 0) {
btn_state_set_message(
btn_state,
"'%s' is not allowed as button name\n",
btn_state->buffer);
return STS_BTN_SOFT_ERROR;
}
if (strcasecmp(btn_state->buffer, "end") == 0) {
btn_state_set_message(
btn_state,
"'%s' is not allowed as button name\n",
btn_state->buffer);
return STS_BTN_SOFT_ERROR;
}
if (strlen(btn_state->buffer) == 0)
return STS_BTN_RECORD_DONE;
if (!opts->disable_namespace
&& !is_in_namespace(btn_state->buffer)) {
btn_state_set_message(
btn_state,
"'%s' is not in name space"
" (use --disable-namespace to override)\n",
btn_state->buffer);
return STS_BTN_SOFT_ERROR;
}
return STS_BTN_INIT_DATA;
case STS_BTN_INIT_DATA:
if (opts->force)
flushhw();
else
while (availabledata())
curr_driver->rec_func(NULL);
if (curr_driver->fd == -1)
curr_driver->init_func();
return opts->force ? STS_BTN_GET_RAW_DATA : STS_BTN_GET_DATA;
case STS_BTN_GET_DATA:
for (retries = RETRIES; retries > 0; ) {
if (!mywaitfordata(10000000)) {
btn_state->no_data = 1;
return STS_BTN_TIMEOUT;
}
decode_ok = 0;
last_remote = NULL;
sleep(1);
while (availabledata()) {
curr_driver->rec_func(NULL);
if (curr_driver->decode_func(
&remote,
&(state->decode_ctx))) {
decode_ok = 1;
break;
}
}
if (!decode_ok) {
if (!resethw(btn_state->started_as_root)) {
btn_state_set_message(
btn_state,
"Could not reset hardware.\n");
return STS_BTN_HARD_ERROR;
}
btn_state_set_message(btn_state,
"Cannot decode data\n");
flushhw();
return STS_BTN_SOFT_ERROR;
}
btn_state->ncode.name = btn_state->buffer;
btn_state->ncode.code = state->decode_ctx.code;
curr_driver->rec_func(NULL);
if (!curr_driver->decode_func(&remote,
&(state->decode_ctx))) {
code2 = state->decode_ctx.code;
state->decode_ctx.code = btn_state->ncode.code;
if (state->decode_ctx.code != code2) {
btn_state->ncode.next =
malloc(IR_CODE_NODE_SIZE);
if (btn_state->ncode.next) {
memset(btn_state->ncode.next,
0,
IR_CODE_NODE_SIZE);
btn_state->ncode.next->code =
code2;
}
}
}
break;
}
return STS_BTN_BUTTON_DONE;
case STS_BTN_GET_RAW_DATA:
btn_state->count = 0;
btn_state->sum = 0;
while (btn_state->count < MAX_SIGNALS) {
if (btn_state->count == 0)
timeout = 10000000;
else
timeout = remote.gap * 5;
btn_state->data = curr_driver->readdata(timeout);
if (!btn_state->data) {
if (btn_state->count == 0)
return STS_BTN_TIMEOUT;
btn_state->data = remote.gap;
}
if (btn_state->count == 0) {
if (is_pulse(btn_state->data)
|| btn_state->data <
remote.gap - remote.gap * remote.eps /
100) {
sleep(3);
flushhw();
btn_state->count = 0;
btn_state_set_message(
btn_state,
"Something went wrong.");
return STS_BTN_SOFT_ERROR;
}
} else {
if (raw_data_ok(btn_state)) {
log_info("Got it.\n");
log_info("Signal length is %d\n",
btn_state->count - 1);
if (btn_state->count % 2) {
btn_state_set_message(
btn_state,
MSG_BAD_LENGTH,
btn_state->count - 1);
sleep(3);
flushhw();
btn_state->count = 0;
return STS_BTN_SOFT_ERROR;
}
btn_state->ncode.name =
btn_state->buffer;
btn_state->ncode.length =
btn_state->count - 1;
btn_state->ncode.signals = signals;
break;
}
signals[btn_state->count - 1] =
btn_state->data & PULSE_MASK;
btn_state->sum +=
btn_state->data & PULSE_MASK;
}
btn_state->count++;
}
if (btn_state->count == MAX_SIGNALS) {
btn_state_set_message(btn_state,
"Signal is too long.\n");
return STS_BTN_SOFT_ERROR;
}
return STS_BTN_BUTTON_DONE;
case STS_BTN_RECORD_DONE:
if (is_raw(&remote))
return STS_BTN_ALL_DONE;
if (!resethw(btn_state->started_as_root)) {
btn_state_set_message(btn_state,
"Could not reset hardware.");
return STS_BTN_HARD_ERROR;
}
return STS_BTN_BUTTONS_DONE;
case STS_BTN_BUTTONS_DONE:
f = fopen(opts->tmpfile, "r");
if (f == NULL) {
btn_state_set_message(btn_state,
"Could not reopen config file");
return STS_BTN_HARD_ERROR;
}
my_remote = read_config(f, opts->filename);
fclose(f);
if (my_remote == NULL) {
btn_state_set_message(
btn_state,
"Internal error: "
"config file contains no valid remote");
return STS_BTN_HARD_ERROR;
}
if (my_remote == (void*)-1) {
btn_state_set_message(
btn_state,
"Internal error: "
"Reading of config file failed");
return STS_BTN_HARD_ERROR;
}
sts = STS_BTN_ALL_DONE;
if (opts->force) {
remote = *my_remote;
return sts;
}
if (!has_toggle_bit_mask(my_remote)) {
if (!opts->using_template
&& strcmp(curr_driver->name, "devinput") != 0) {
remote = *(my_remote);
sts = STS_BTN_GET_TOGGLE_BITS;
}
} else {
set_toggle_bit_mask(my_remote,
my_remote->toggle_bit_mask);
if (curr_driver->deinit_func)
curr_driver->deinit_func();
}
if (!opts->update) {
get_pre_data(my_remote);
get_post_data(my_remote);
}
remote = *my_remote;
return sts;
case STS_BTN_BUTTON_DONE:
return STS_BTN_BUTTON_DONE;
case STS_BTN_HARD_ERROR:
return STS_BTN_HARD_ERROR;
default:
btn_state_set_message(btn_state,
"record_buttons(): bad state: %d\n",
last_status);
return STS_BTN_HARD_ERROR;
}
}
void config_file_setup(struct main_state* state, const struct opts* opts)
{
state->fout = fopen(opts->tmpfile, "w");
if (state->fout == NULL) {
log_error("Could not open new config file %s", tmpfile);
log_perror_err("While opening temporary file for write");
return;
}
fprint_copyright(state->fout);
fprint_comment(state->fout, &remote, opts->commandline);
fprint_remote_head(state->fout, &remote);
fprint_remote_signal_head(state->fout, &remote);
}
int config_file_finish(struct main_state* state, const struct opts* opts)
{
state->fout = fopen(opts->filename, "w");
if (state->fout == NULL) {
log_perror_err("While opening \"%s\" for write",
opts->filename);
return 0;
}
fprint_copyright(state->fout);
fprint_remotes(state->fout, &remote, opts->commandline);
return 1;
}
curr_driver
const struct driver *const curr_driver
Read-only access to drv for client code.
Definition driver.c:34
last_remote
struct ir_remote * last_remote
TODO.
Definition ir_remote.c:55
default_close
int default_close(void)
For now, a placeholder.
Definition driver.c:52
rec_buffer_init
void rec_buffer_init(void)
Clear internal buffer to pristine state.
Definition receive.c:213
default_open
int default_open(const char *path)
Stores path in drv.device if non-null.
Definition driver.c:37
receive_decode
int receive_decode(struct ir_remote *remote, struct decode_ctx_t *ctx)
Decode data from remote.
Definition receive.c:1038
rec_buffer_clear
int rec_buffer_clear(void)
Flush the internal fifo and store a single code read from the driver in it.
Definition receive.c:233
read_config
struct ir_remote * read_config(FILE *f, const char *name)
Parse a lircd.conf config file.
Definition config_file.c:833
drop_sudo_root
const char * drop_sudo_root(int(*set_some_uid)(uid_t))
Try to drop possible root privileges, returning new user or "" on error.
Definition lirc-utils.c:28
RC6
#define RC6
IR data follows RC6 protocol.
Definition ir_remote_types.h:107
REPEAT_HEADER
#define REPEAT_HEADER
header is also sent before repeat code
Definition ir_remote_types.h:121
ir_code
uint64_t ir_code
Denotes an internal coded representation for an IR transmission.
Definition ir_remote_types.h:43
SPACE_ENC
#define SPACE_ENC
IR data is space encoded.
Definition ir_remote_types.h:109
RC5
#define RC5
IR data follows RC5 protocol.
Definition ir_remote_types.h:101
NO_HEAD_REP
#define NO_HEAD_REP
no header for key repeats
Definition ir_remote_types.h:118
CONST_LENGTH
#define CONST_LENGTH
signal length+gap is always constant
Definition ir_remote_types.h:120
resethw
int resethw(int started_as_root)
Reset the hardware.
Definition irrecord.c:161
eps
unsigned int eps
Shared list of remotes.
Definition irrecord.c:62
flushhw
void flushhw(void)
Clear the driver input buffers.
Definition irrecord.c:139
analyse_remote
int analyse_remote(struct ir_remote *raw_data, const struct opts *opts)
Implement the analyse task, return 1 for ok, 0 for errors.
Definition irrecord.c:1678
get_lengths
enum lengths_status get_lengths(struct lengths_state *state, struct ir_remote *remote, int force, int interactive)
Try to find out pre/post etc.
Definition irrecord.c:1387
analyse_get_lengths
int analyse_get_lengths(struct lengths_state *lengths_state)
analyse non-interactive get_lengths, returns boolean ok/fail.
Definition irrecord.c:1638
record_buttons
enum button_status record_buttons(struct button_state *btn_state, enum button_status last_status, struct main_state *state, const struct opts *opts)
Try to record one button, returning button_status.
Definition irrecord.c:1848
config_file_finish
int config_file_finish(struct main_state *state, const struct opts *opts)
Write the final config file.
Definition irrecord.c:2119
needs_toggle_mask
int needs_toggle_mask(struct ir_remote *remote)
Return true if a given remote needs to compute toggle_mask.
Definition irrecord.c:1249
get_toggle_bit_mask
enum toggle_status get_toggle_bit_mask(struct toggle_state *state, struct ir_remote *remote)
Try to find out toggle_bit_mask, returning toggle_status.
Definition irrecord.c:1556
config_file_setup
void config_file_setup(struct main_state *state, const struct opts *opts)
Write the provisionary config file.
Definition irrecord.c:2102
button_state_init
void button_state_init(struct button_state *state, int started_as_root)
Initiate a pristine button_state.
Definition irrecord.c:219
raw_read
ssize_t raw_read(void *buffer, size_t size, unsigned int timeout_us)
Absolute error tolerance (us).
Definition irrecord.c:1815
remove_pre_data
void remove_pre_data(struct ir_remote *remote)
Test hook: Move remote->pre_data into remote->bits.
Definition irrecord.c:383
availabledata
int availabledata(void)
Return 1 if there is available after running poll(2), else 0.
Definition irrecord.c:118
remove_post_data
void remove_post_data(struct ir_remote *remote)
Test hook: Move remote->post_data into remote->bits.
Definition irrecord.c:403
invert_data
void invert_data(struct ir_remote *remote)
Test hook: Invert all data items in remote.
Definition irrecord.c:424
get_gap_length
enum get_gap_status get_gap_length(struct gap_state *state, struct ir_remote *remote)
Try to find out gap length, returning gap_status.
Definition irrecord.c:1207
free_all_lengths
void free_all_lengths(void)
Free heap data allocated by get_lengths().
Definition irrecord.c:664
gap_state_init
void gap_state_init(struct gap_state *state)
Initiate a pristine gap_state.
Definition irrecord.c:189
remove_trail
void remove_trail(struct ir_remote *remote)
Test hook: Move remote->trail into remote->bits.
Definition irrecord.c:463
do_analyse
int do_analyse(const struct opts *opts, struct main_state *state)
The –analyse wrapper.
Definition irrecord.c:1787
get_post_data
void get_post_data(struct ir_remote *remote)
Test hook: Extract remote->post_data and post_data_bits from bits.
Definition irrecord.c:327
aeps
lirc_t aeps
Error tolerance in per cent.
Definition irrecord.c:63
btn_state_set_message
void btn_state_set_message(struct button_state *state, const char *fmt,...)
snprintf-style message formatting into state->message.
Definition irrecord.c:97
lengths_state_init
void lengths_state_init(struct lengths_state *state)
Initiate a pristine lengths_state.
Definition irrecord.c:195
toggle_state_init
void toggle_state_init(struct toggle_state *state)
Initiate a pristine toggle_state.
Definition irrecord.c:211
for_each_remote
void for_each_remote(struct ir_remote *remotes, remote_func func)
Unconditionally apply func(remote) for all items in remotes list.
Definition irrecord.c:491
get_pre_data
void get_pre_data(struct ir_remote *remote)
Test hook: Extract remote->pre_data from remote->bits.
Definition irrecord.c:269
irrecord.h
Library part of irrecord, functions to identify unknown remotes.
button_status
button_status
Return from one pass in record_buttons().
Definition irrecord.h:124
lengths_status
lengths_status
Return from one attempt to determine lengths in get_lengths().
Definition irrecord.h:91
get_gap_status
get_gap_status
Return form one attempt to get gap in get_gap().
Definition irrecord.h:104
toggle_status
toggle_status
Return from one attempt in get_toggle_bit_mask().
Definition irrecord.h:114
PACKET_SIZE
#define PACKET_SIZE
IR transmission packet size.
Definition lirc_config.h:84
log_notice
#define log_notice(fmt,...)
Log a notice message.
Definition lirc_log.h:119
log_debug
#define log_debug(fmt,...)
Log a debug message.
Definition lirc_log.h:124
log_perror_err
#define log_perror_err(fmt,...)
perror wrapper logging with level LIRC_ERROR.
Definition lirc_log.h:89
log_info
#define log_info(fmt,...)
Log an info message.
Definition lirc_log.h:114
log_error
#define log_error(fmt,...)
Log an error message.
Definition lirc_log.h:104
logchannel_t
logchannel_t
Log channels used to filter messages.
Definition lirc_log.h:53
log_warn
#define log_warn(fmt,...)
Log a warning message.
Definition lirc_log.h:109
lirc_private.h
Main include file for lirc applications.
button_state
State while recording buttons, privates besides commented.
Definition irrecord.h:236
button_state::message
char message[128]
Error message, valid on STS_BTN_*_ERROR.
Definition irrecord.h:240
button_state::ncode
struct ir_ncode ncode
Recorded button, valid on STS_BTN_BUTTON_DONE.
Definition irrecord.h:238
decode_ctx_t
State describing code, pre, post + gap and repeat state.
Definition ir_remote_types.h:137
decode_ctx_t::code
ir_code code
Code part, matched to code defintion.
Definition ir_remote_types.h:138
decode_ctx_t::repeat_flag
int repeat_flag
True if code is a repeated one.
Definition ir_remote_types.h:141
decode_ctx_t::min_remaining_gap
lirc_t min_remaining_gap
Estimated min time of trailing gap.
Definition ir_remote_types.h:143
decode_ctx_t::max_remaining_gap
lirc_t max_remaining_gap
Estimated max time of trailing gap.
Definition ir_remote_types.h:142
driver
The data the driver exports i.
Definition driver.h:132
gap_state
Private state in get_gap_length().
Definition irrecord.h:185
ir_code_node
An ir_code for entering into (singly) linked lists, i.e.
Definition ir_remote_types.h:49
ir_ncode
IR Command, corresponding to one (command defining) line of the configuration file.
Definition ir_remote_types.h:60
ir_ncode::next
struct ir_code_node * next
Linked list of the subsequent ir_code's, after the first one.
Definition ir_remote_types.h:75
ir_ncode::code
ir_code code
The first code of the command.
Definition ir_remote_types.h:65
ir_ncode::length
int length
(private)
Definition ir_remote_types.h:68
ir_ncode::signals
lirc_t * signals
(private)
Definition ir_remote_types.h:71
ir_ncode::name
char * name
Name of command.
Definition ir_remote_types.h:62
ir_remote
One remote as represented in the configuration file.
Definition ir_remote_types.h:150
ir_remote::freq
unsigned int freq
modulation frequency
Definition ir_remote_types.h:203
ir_remote::aeps
unsigned int aeps
detecting very short pulses is difficult with relative tolerance for some remotes,...
Definition ir_remote_types.h:157
ir_remote::eps
int eps
eps (relative tolerance)
Definition ir_remote_types.h:156
ir_remote::name
const char * name
name of remote control
Definition ir_remote_types.h:151
ir_remote::toggle_bit_mask
ir_code toggle_bit_mask
previously only one bit called toggle_bit
Definition ir_remote_types.h:190
lengths_state
State in get_lengths(), private besides commented.
Definition irrecord.h:199
lengths_state::count
int count
Number of processed data items.
Definition irrecord.h:206
lengths_state::keypresses
int keypresses
Number of counted button presses.
Definition irrecord.h:203
lengths_state::sum
lirc_t sum
Number of bits accounted for in signal.
Definition irrecord.h:211
lengths
Definition irrecord.h:142
main_state
Overall state in main.
Definition irrecord.h:177
opts
Parsed run-time options, reflects long_options and the command line, mostly a const object.
Definition irrecord.h:153
toggle_state
Private state in get_togggle_bit_mask().
Definition irrecord.h:220