aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Young <sean@mess.org>2019-08-27 21:26:44 +0100
committerSean Young <sean@mess.org>2019-08-28 12:12:09 +0100
commit16d14351f0875073aea222ad797d78d0afcea4b7 (patch)
treeb2c917ef7fc8186456a0d18e7d2ec2c5dcab313c
parentdece02f862f38d8f866230ca9f1015cb93ddfac4 (diff)
ir-ctl: support raw format by defaultmode2
When "ir-ctl -r" outputs data it prints one line per space and pulse. This is not very space efficient and long protocols like rc-6 are unlikely to fit on the screen. The new format is much more compact. A single IR message is printed on a single line. The pulse is prefixed with an optional + and a space is prefixed with -. The rc-5 example from the man page becomes: $ ./ir-ctl -r +889 -889 +1778 -1778 +889 -889 +889 -889 +889 -889 +1778 -889 +889 -889 +889 -889 +889 -889 +889 -889 +889 -1778 +889 # timeout 133889 The old behaviour can be resurrected with: ./ir-ctl -r --mode2 This commit also add support for sending the same format. Signed-off-by: Sean Young <sean@mess.org>
-rw-r--r--utils/common/keymap.c8
-rw-r--r--utils/ir-ctl/ir-ctl.1.in30
-rw-r--r--utils/ir-ctl/ir-ctl.c205
3 files changed, 205 insertions, 38 deletions
diff --git a/utils/common/keymap.c b/utils/common/keymap.c
index 9ca599a0..19d63661 100644
--- a/utils/common/keymap.c
+++ b/utils/common/keymap.c
@@ -272,19 +272,23 @@ static error_t parse_toml_raw_part(const char *fname, struct toml_array_t *raw,
if (!traw) {
fprintf(stderr, _("%s: missing raw value for entry %d\n"),
fname, ind);
+ free(keycode);
return EINVAL;
}
if (toml_rtos(traw, &raw_str)) {
fprintf(stderr, _("%s: bad value `%s' for keycode\n"),
fname, traw);
+ free(keycode);
return EINVAL;
}
- if (parse_rawir_string(fname, raw_str, &re))
+ if (parse_rawir_string(fname, raw_str, &re)) {
+ free(keycode);
return EINVAL;
+ }
- re->keycode = strdup(keycode);
+ re->keycode = keycode;
re->next = map->raw;
map->raw = re;
}
diff --git a/utils/ir-ctl/ir-ctl.1.in b/utils/ir-ctl/ir-ctl.1.in
index 7564066a..3cdaef38 100644
--- a/utils/ir-ctl/ir-ctl.1.in
+++ b/utils/ir-ctl/ir-ctl.1.in
@@ -9,7 +9,7 @@ ir\-ctl \- a swiss\-knife tool to handle raw IR and to set lirc options
[\fIOPTION\fR]... \fI\-\-features\fR
.br
.B ir\-ctl
-[\fIOPTION\fR]... \fI\-\-send\fR [\fIpulse and space file to send\fR]
+[\fIOPTION\fR]... \fI\-\-send\fR [\fIfile to send\fR]
.br
.B ir\-ctl
[\fIOPTION\fR]... \fI\-\-scancode\fR [\fIprotocol and scancode to send\fR]
@@ -65,6 +65,9 @@ man page.
When receiving, stop receiving after the first message, i.e. after a space or
timeout of more than 19ms is received.
.TP
+\fB\-\-mode2\fR
+When receiving, output IR in lirc mode2 format. One line per space and pulse.
+.TP
\fB\-w\fR, \fB\-\-wideband\fR
Use the wideband receiver if available on the hardware. This is also
known as learning mode. The measurements should be more precise and any
@@ -118,14 +121,17 @@ Verbose output; this prints the IR before sending.
\fB\-V\fR, \fB\-\-version\fR
print the v4l2\-utils version
.PP
-.SS Format of pulse and space file
-When sending IR, the format of the file should be as follows. A comment
-starts with #. The carrier frequency can be specified as:
+.SS Format of file
+When sending or receiving raw IR, two formats can be used. The first is
+a list of integers representing pulse and space values. A pulse value can be
+prefixed with + and a space with -, but this is optional. The rc-5 scancode
+0x1e01 is encoded so:
.PP
- carrier 38000
++889 -889 +1778 -1778 +889 -889 +889 -889 +889 -889 +1778 -889 +889 -889 +889 -889 +889 -889 +889 -889 +889 -1778 +889
.PP
-The file should contain alternating lines with pulse and space, followed
-by length in microseconds. The following is a rc-5 encoded message:
+The other format mimics the mode2 tool. This produces one line per space
+or pulse. For receiving it can selected by specifying \fB\-\-mode2\fR. Here is
+the same message as above, now encoded in mode2:
.PP
carrier 36000
.br
@@ -175,9 +181,13 @@ by length in microseconds. The following is a rc-5 encoded message:
.br
pulse 840
.PP
-Rather than specifying the raw IR, you can also specify the scancode and
-protocol you want to send. This will also automatically set the correct
-carrier. The above can be written as:
+Note that in this format, the carrier can also be specified. This can only
+by done with a separate \fB\-\-carrier=38000\fR command line option with
+the first format.
+.PP
+Rather than specifying just the raw IR, in this format you can also specify
+the scancode and protocol you want to send. This will also automatically set
+the correct carrier. The above can be written as:
.PP
scancode rc5:0x1e01
.PP
diff --git a/utils/ir-ctl/ir-ctl.c b/utils/ir-ctl/ir-ctl.c
index 837dffef..af1c22e8 100644
--- a/utils/ir-ctl/ir-ctl.c
+++ b/utils/ir-ctl/ir-ctl.c
@@ -88,6 +88,7 @@ struct arguments {
bool features;
bool receive;
bool verbose;
+ bool mode2;
struct keymap *keymap;
struct file *send;
bool oneshot;
@@ -113,6 +114,7 @@ static const struct argp_option options[] = {
{ "verbose", 'v', 0, 0, N_("verbose output") },
{ .doc = N_("Receiving options:") },
{ "one-shot", '1', 0, 0, N_("end receiving after first message") },
+ { "mode2", 2, 0, 0, N_("output IR in lirc mode2 format") },
{ "wideband", 'w', 0, 0, N_("use wideband receiver aka learning mode") },
{ "narrowband", 'n', 0, 0, N_("use narrowband receiver, disable learning mode") },
{ "carrier-range", 'R', N_("RANGE"), 0, N_("set receiver carrier range") },
@@ -145,7 +147,7 @@ static const char doc[] = N_(
" CARRIER - the carrier frequency to use for sending\n"
" DUTY - the duty cycle to use for sending\n"
" EMITTERS - comma separated list of emitters to use for sending, e.g. 1,2\n"
- " GAP - gap between pulse and files or scancodes in microseconds\n"
+ " GAP - gap between sending in microseconds\n"
" RANGE - set range of accepted carrier frequencies, e.g. 20000-40000\n"
" TIMEOUT - set length of space before receiving stops in microseconds\n"
" KEYCODE - key code in keymap\n"
@@ -201,7 +203,7 @@ static unsigned parse_emitters(char *p)
return emit;
}
-static struct file *read_file(struct arguments *args, const char *fname)
+static struct file *read_file_pulse_space(struct arguments *args, const char *fname, FILE *input)
{
bool expect_pulse = true;
int lineno = 0, lastspace = 0;
@@ -210,13 +212,6 @@ static struct file *read_file(struct arguments *args, const char *fname)
static const char *whitespace = " \n\r\t";
struct file *f;
- FILE *input = fopen(fname, "r");
-
- if (!input) {
- fprintf(stderr, _("%s: could not open: %m\n"), fname);
- return NULL;
- }
-
f = malloc(sizeof(*f));
if (f == NULL) {
fprintf(stderr, _("Failed to allocate memory\n"));
@@ -360,6 +355,137 @@ static struct file *read_file(struct arguments *args, const char *fname)
return f;
}
+static struct file *read_file_raw(struct arguments *args, const char *fname, FILE *input)
+{
+ int lineno = 0, lastspace = 0;
+ char line[1024];
+ int len = 0;
+ static const char *whitespace = " \n\r\t,";
+ struct file *f;
+
+ f = malloc(sizeof(*f));
+ if (f == NULL) {
+ fprintf(stderr, _("Failed to allocate memory\n"));
+ return NULL;
+ }
+ f->is_scancode = false;
+ f->is_keycode = false;
+ f->carrier = 0;
+ f->fname = fname;
+
+ while (fgets(line, sizeof(line), input)) {
+ long int value;
+ char *p, *saveptr;
+ lineno++;
+ char *keyword = strtok_r(line, whitespace, &saveptr);
+
+ for (;;) {
+ if (keyword == NULL || *keyword == 0 || *keyword == '#' ||
+ (keyword[0] == '/' && keyword[1] == '/'))
+ break;
+
+ value = strtol(keyword, &p, 10);
+ if (errno || *p) {
+ fprintf(stderr, _("%s:%d: error: expected integer, got `%s'\n"),
+ fname, lineno, keyword);
+ free(f);
+ return NULL;
+ }
+
+ if (len % 2) {
+ if (keyword[0] == '+') {
+ fprintf(stderr, _("%s:%d: error: pulse found where space expected `%s'\n"), fname, lineno, keyword);
+ free(f);
+ return NULL;
+ }
+ if (keyword[0] == '-')
+ value = -value;
+ } else {
+ if (keyword[0] == '-') {
+ fprintf(stderr, _("%s:%d: error: space found where pulse expected `%s'\n"), fname, lineno, keyword);
+ free(f);
+ return NULL;
+ }
+ lastspace = lineno;
+ }
+
+ if (value <= 0 || value >= LIRC_VALUE_MASK) {
+ fprintf(stderr, _("%s:%d: error: value `%s' out of range\n"), fname, lineno, keyword);
+ free(f);
+ return NULL;
+ }
+
+ f->buf[len++] = value;
+
+ if (len >= LIRCBUF_SIZE) {
+ fprintf(stderr, _("warning: %s:%d: IR cannot exceed %u edges\n"), fname, lineno, LIRCBUF_SIZE);
+ break;
+ }
+
+ keyword = strtok_r(NULL, whitespace, &saveptr);
+ }
+ }
+
+ fclose(input);
+
+ if (len == 0) {
+ fprintf(stderr, _("%s: no pulses or spaces found\n"), fname);
+ free(f);
+ return NULL;
+ }
+
+ if ((len % 2) == 0) {
+ fprintf(stderr, _("warning: %s:%d: trailing space ignored\n"),
+ fname, lastspace);
+ len--;
+ }
+
+ f->len = len;
+
+ return f;
+}
+
+static struct file *read_file(struct arguments *args, const char *fname)
+{
+ FILE *input = fopen(fname, "r");
+ char line[1024];
+
+ if (!input) {
+ fprintf(stderr, _("%s: could not open: %m\n"), fname);
+ return NULL;
+ }
+
+ while (fgets(line, sizeof(line), input)) {
+ int start = 0;
+
+ while (isspace(line[start]))
+ start++;
+
+ switch (line[start]) {
+ case '/':
+ if (line[start+1] != '/')
+ break;
+ case 0:
+ case '#':
+ continue;
+ case '+':
+ case '-':
+ case '0' ... '9':
+ rewind(input);
+ return read_file_raw(args, fname, input);
+ default:
+ rewind(input);
+ return read_file_pulse_space(args, fname, input);
+ }
+ }
+
+ fclose(input);
+
+ fprintf(stderr, _("%s: file is empty\n"), fname);
+
+ return NULL;
+}
+
static struct file *read_scancode(const char *name)
{
enum rc_proto proto;
@@ -431,6 +557,9 @@ static error_t parse_opt(int k, char *arg, struct argp_state *state)
case '1':
arguments->oneshot = true;
break;
+ case 2:
+ arguments->mode2 = true;
+ break;
case 'v':
arguments->verbose = true;
break;
@@ -577,7 +706,7 @@ static error_t parse_opt(int k, char *arg, struct argp_state *state)
return ARGP_ERR_UNKNOWN;
}
- if (k != '1' && k != 'd' && k != 'v' && k != 'k')
+ if (k != '1' && k != 'd' && k != 'v' && k != 'k' && k != 2)
arguments->work_to_do = true;
return 0;
@@ -930,9 +1059,10 @@ static int lirc_send(struct arguments *args, int fd, unsigned features, struct f
size_t size = f->len * sizeof(unsigned);
if (args->verbose) {
int i;
- printf("Sending:\n");
+ printf("Sending:");
for (i=0; i<f->len; i++)
- printf("%s %u\n", i & 1 ? "space" : "pulse", f->buf[i]);
+ printf("%s%u", i & 1 ? " -" : " +", f->buf[i]);
+ putchar('\n');
}
ret = TEMP_FAILURE_RETRY(write(fd, f->buf, size));
if (ret < 0) {
@@ -982,6 +1112,7 @@ int lirc_receive(struct arguments *args, int fd, unsigned features)
bool keep_reading = true;
bool leading_space = true;
+ unsigned carrier = 0;
while (keep_reading) {
ssize_t ret = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)));
@@ -1015,20 +1146,42 @@ int lirc_receive(struct arguments *args, int fd, unsigned features)
break;
}
- switch (msg) {
- case LIRC_MODE2_TIMEOUT:
- fprintf(out, "timeout %u\n", val);
- leading_space = true;
- break;
- case LIRC_MODE2_PULSE:
- fprintf(out, "pulse %u\n", val);
- break;
- case LIRC_MODE2_SPACE:
- fprintf(out, "space %u\n", val);
- break;
- case LIRC_MODE2_FREQUENCY:
- fprintf(out, "carrier %u\n", val);
- break;
+ if (args->mode2) {
+ switch (msg) {
+ case LIRC_MODE2_TIMEOUT:
+ fprintf(out, "timeout %u\n", val);
+ leading_space = true;
+ break;
+ case LIRC_MODE2_PULSE:
+ fprintf(out, "pulse %u\n", val);
+ break;
+ case LIRC_MODE2_SPACE:
+ fprintf(out, "space %u\n", val);
+ break;
+ case LIRC_MODE2_FREQUENCY:
+ fprintf(out, "carrier %u\n", val);
+ break;
+ }
+ } else {
+ switch (msg) {
+ case LIRC_MODE2_TIMEOUT:
+ if (carrier)
+ fprintf(out, "# carrier %uHz, timeout %u\n", carrier, val);
+ else
+ fprintf(out, "# timeout %u\n", val);
+ leading_space = true;
+ carrier = 0;
+ break;
+ case LIRC_MODE2_PULSE:
+ fprintf(out, "+%u ", val);
+ break;
+ case LIRC_MODE2_SPACE:
+ fprintf(out, "-%u ", val);
+ break;
+ case LIRC_MODE2_FREQUENCY:
+ carrier = val;
+ break;
+ }
}
fflush(out);

Privacy Policy