Signed-off-by: Sean Young <[email protected]>
---
utils/ir-ctl/ir-ctl.c | 188 +++++++++++++++++++++++++++++++++--------------
utils/ir-ctl/ir-encode.c | 4 +
2 files changed, 135 insertions(+), 57 deletions(-)
diff --git a/utils/ir-ctl/ir-ctl.c b/utils/ir-ctl/ir-ctl.c
index f0dcd2a3..f9cf30a3 100644
--- a/utils/ir-ctl/ir-ctl.c
+++ b/utils/ir-ctl/ir-ctl.c
@@ -24,6 +24,7 @@
#include <fcntl.h>
#include <argp.h>
#include <sysexits.h>
+#include <poll.h>
#include <config.h>
@@ -840,24 +841,122 @@ static int lirc_send(struct arguments *args, int fd,
unsigned features, struct f
return 0;
}
-int lirc_record(struct arguments *args, int fd, unsigned features)
+static bool keep_reading = true;
+static bool leading_space = true;
+
+int lirc_record_mode2(FILE *out, int fd, struct arguments *args)
{
- char *dev = args->device;
- FILE *out = stdout;
- int rc = EX_IOERR;
int mode = LIRC_MODE_MODE2;
+ unsigned buf[LIRCBUF_SIZE];
+ char *dev = args->device;
+ ssize_t ret;
- if (!(features & LIRC_CAN_REC_MODE2)) {
- fprintf(stderr, _("%s: device cannot record raw ir\n"), dev);
- return EX_UNAVAILABLE;
+ // some kernel versions return errors, ignore them
+ ioctl(fd, LIRC_SET_REC_MODE, &mode);
+
+ ret = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)));
+ if (ret < 0) {
+ fprintf(stderr, _("%s: failed read: %m\n"), dev);
+ return EX_IOERR;
}
- // kernel v4.8 and v4.9 return ENOTTY
- if (ioctl(fd, LIRC_SET_REC_MODE, &mode) && errno != ENOTTY) {
- fprintf(stderr, _("%s: failed to set record mode: %m\n"), dev);
+ if (ret == 0 || ret % sizeof(unsigned)) {
+ fprintf(stderr, _("%s: read returned %zd bytes\n"), dev, ret);
+ return EX_IOERR;
+ }
+
+ for (int i=0; i<ret / sizeof(unsigned); i++) {
+ unsigned val = buf[i] & LIRC_VALUE_MASK;
+ unsigned msg = buf[i] & LIRC_MODE2_MASK;
+
+ // FIXME: the kernel often send us a space after
+ // the IR receiver comes out of idle mode. This
+ // is meaningless, maybe fix the kernel?
+ if (leading_space && msg == LIRC_MODE2_SPACE)
+ continue;
+ else
+ leading_space = false;
+
+ if (args->oneshot &&
+ (msg == LIRC_MODE2_TIMEOUT ||
+ (msg == LIRC_MODE2_SPACE && val > 19000))) {
+ keep_reading = false;
+ 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;
+ }
+
+ fflush(out);
+ }
+
+ return 0;
+}
+
+int lirc_record_scancode(FILE *out, int fd, const char *dev)
+{
+ struct lirc_scancode sc[32];
+ int mode = LIRC_MODE_SCANCODE;
+ ssize_t ret;
+
+ ret = ioctl(fd, LIRC_SET_REC_MODE, &mode);
+ if (ret < 0) {
+ fprintf(stderr, _("%s: failed set recording mode: %m\n"), dev);
+ return EX_IOERR;
+ }
+
+ ret = TEMP_FAILURE_RETRY(read(fd, sc, sizeof sc));
+ if (ret < 0) {
+ fprintf(stderr, _("%s: failed read: %m\n"), dev);
return EX_IOERR;
}
+ if (ret == 0 || ret % sizeof sc[0]) {
+ fprintf(stderr, _("%s: read returned %zd bytes\n"), dev, ret);
+ return EX_IOERR;
+ }
+
+ for (int i=0; i<ret / sizeof sc[0]; i++) {
+ const char *proto = protocol_name(sc[i].rc_proto);
+
+ if (proto)
+ fprintf(out, "scancode %s:0x%llx\n",
+ protocol_name(sc[i].rc_proto), sc[i].scancode);
+ else
+ fprintf(out, "scancode protocol-%u:0x%llx\n", i,
+ sc[i].scancode);
+ }
+
+ fflush(out);
+
+ return 0;
+}
+
+int lirc_record(struct arguments *args, int fd, unsigned features)
+{
+ char *dev = args->device;
+ FILE *out = stdout;
+ int rc = 0;
+ ssize_t ret;
+
+ if (!(features & (LIRC_CAN_REC_MODE2 | LIRC_CAN_REC_SCANCODE))) {
+ fprintf(stderr, _("%s: device cannot receive\n"), dev);
+ return EX_UNAVAILABLE;
+ }
+
if (args->savetofile) {
out = fopen(args->savetofile, "w");
if (!out) {
@@ -865,65 +964,40 @@ int lirc_record(struct arguments *args, int fd, unsigned
features)
return EX_CANTCREAT;
}
}
- unsigned buf[LIRCBUF_SIZE];
-
- bool keep_reading = true;
- bool leading_space = true;
while (keep_reading) {
- ssize_t ret = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)));
- if (ret < 0) {
- fprintf(stderr, _("%s: failed read: %m\n"), dev);
- goto err;
- }
-
- if (ret == 0 || ret % sizeof(unsigned)) {
- fprintf(stderr, _("%s: read returned %zd bytes\n"),
- dev, ret);
- goto err;
+ if (features & LIRC_CAN_REC_SCANCODE) {
+ unsigned mode = LIRC_MODE_MODE2 | LIRC_MODE_SCANCODE;
+ if (ioctl(fd, LIRC_SET_POLL_MODE, &mode)) {
+ fprintf(stderr, _("%s: set poll mode failed:
%m\n"), dev);
+ rc = EX_IOERR;
+ break;
+ }
}
- for (int i=0; i<ret / sizeof(unsigned); i++) {
- unsigned val = buf[i] & LIRC_VALUE_MASK;
- unsigned msg = buf[i] & LIRC_MODE2_MASK;
-
- // FIXME: the kernel often send us a space after
- // the IR receiver comes out of idle mode. This
- // is meaningless, maybe fix the kernel?
- if (leading_space && msg == LIRC_MODE2_SPACE)
+ struct pollfd p = { .fd = fd, .events = POLLIN };
+ ret = poll(&p, 1, -1);
+ if (ret == -1) {
+ if (errno == -EINTR)
continue;
- else
- leading_space = false;
+ fprintf(stderr, _("%s: poll failed: %m\n"), dev);
+ rc = EX_IOERR;
+ break;
+ }
- if (args->oneshot &&
- (msg == LIRC_MODE2_TIMEOUT ||
- (msg == LIRC_MODE2_SPACE && val > 19000))) {
- keep_reading = false;
+ if (features & LIRC_CAN_REC_SCANCODE) {
+ rc = lirc_record_scancode(out, fd, dev);
+ if (rc)
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);
+ if (features & LIRC_CAN_REC_MODE2) {
+ rc = lirc_record_mode2(out, fd, args);
+ if (rc)
break;
- }
-
- fflush(out);
}
}
- rc = 0;
-err:
if (args->savetofile)
fclose(out);
diff --git a/utils/ir-ctl/ir-encode.c b/utils/ir-ctl/ir-encode.c
index 8a125628..702c1bb0 100644
--- a/utils/ir-ctl/ir-encode.c
+++ b/utils/ir-ctl/ir-encode.c
@@ -18,6 +18,7 @@
*/
#include <stdbool.h>
+#include <stdlib.h>
#include <stdint.h>
#include <ctype.h>
@@ -445,5 +446,8 @@ unsigned protocol_encode(enum rc_proto proto, unsigned
scancode, unsigned *buf)
const char* protocol_name(enum rc_proto proto)
{
+ if (proto >= ARRAY_SIZE(encoders))
+ return NULL;
+
return encoders[proto].name;
}
--
2.13.5