|
|
- From fa68debd94d40299dd2a69abd0a820ccfaadcbe8 Mon Sep 17 00:00:00 2001
- From: Michael Heimpold <michael.heimpold@i2se.com>
- Date: Wed, 22 Apr 2015 13:35:43 +0200
- Subject: [PATCH] Add support for triggering LEDs during serial traffic
-
- Signed-off-by: Michael Heimpold <michael.heimpold@i2se.com>
- ---
-
- Patch sent upstream:
- http://sourceforge.net/p/ser2net/mailman/message/34064847/
-
- Makefile.am | 4 +--
- dataxfer.c | 20 ++++++++++++
- readconfig.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- ser2net.conf | 13 ++++++++
- sysfs-led.c | 43 +++++++++++++++++++++++++
- sysfs-led.h | 11 +++++++
- utils.c | 30 ++++++++++++++++++
- utils.h | 9 ++++++
- 8 files changed, 228 insertions(+), 2 deletions(-)
- create mode 100644 sysfs-led.c
- create mode 100644 sysfs-led.h
-
- diff --git a/Makefile.am b/Makefile.am
- index d56179f..866eb89 100644
- --- a/Makefile.am
- +++ b/Makefile.am
- @@ -2,9 +2,9 @@ sbin_PROGRAMS = ser2net
- ACLOCAL_AMFLAGS = -I m4
- AM_CFLAGS=-Wall
- ser2net_SOURCES = controller.c dataxfer.c devcfg.c readconfig.c selector.c \
- - ser2net.c utils.c telnet.c buffer.c
- + ser2net.c utils.c telnet.c buffer.c sysfs-led.c
- noinst_HEADERS = controller.h dataxfer.h devio.h readconfig.h selector.h \
- - utils.h telnet.h buffer.h ser2net.h
- + utils.h telnet.h buffer.h sysfs-led.h ser2net.h
- man_MANS = ser2net.8
- EXTRA_DIST = $(man_MANS) ser2net.conf ser2net.spec ser2net.init
-
- diff --git a/dataxfer.c b/dataxfer.c
- index 646a71b..b99cabf 100644
- --- a/dataxfer.c
- +++ b/dataxfer.c
- @@ -42,6 +42,7 @@
- #include "telnet.h"
- #include "devio.h"
- #include "buffer.h"
- +#include "sysfs-led.h"
-
- #define SERIAL "term"
- #define NET "tcp "
- @@ -230,6 +231,12 @@ typedef struct port_info
- #ifdef USE_RS485_FEATURE
- struct serial_rs485 *rs485conf;
- #endif
- +
- + /*
- + * LED names to flash for serial traffic
- + */
- + char *led_tx;
- + char *led_rx;
- } port_info_t;
-
- port_info_t *ports = NULL; /* Linked list of ports. */
- @@ -311,6 +318,8 @@ init_port_data(port_info_t *port)
- #ifdef USE_RS485_FEATURE
- port->rs485conf = NULL;
- #endif
- + port->led_tx = NULL;
- + port->led_rx = NULL;
- }
-
- static void
- @@ -530,6 +539,9 @@ handle_dev_fd_read(struct devio *io)
- /* Do both tracing, ignore errors. */
- do_trace(port, port->tb, port->dev_to_tcp.buf, count, SERIAL);
-
- + if (port->led_rx)
- + led_blink_kick(port->led_rx);
- +
- port->dev_bytes_received += count;
-
- if (port->enabled == PORT_TELNET) {
- @@ -759,6 +771,8 @@ handle_tcp_fd_read(int fd, void *data)
- return;
- }
- } else {
- + if (port->led_tx)
- + led_blink_kick(port->led_tx);
- port->dev_bytes_sent += count;
- port->tcp_to_dev.cursize -= count;
- if (port->tcp_to_dev.cursize != 0) {
- @@ -1854,6 +1868,12 @@ myconfig(void *data, struct absout *eout, const char *pos)
- } else if (strncmp(pos, "tb=", 3) == 0) {
- /* trace both directions. */
- port->trace_both.filename = find_tracefile(pos + 3);
- + } else if (strncmp(pos, "led-rx=", 7) == 0) {
- + /* LED for UART RX traffic */
- + port->led_rx = find_led(pos + 7);
- + } else if (strncmp(pos, "led-tx=", 7) == 0) {
- + /* LED for UART TX traffic */
- + port->led_tx = find_led(pos + 7);
- #ifdef USE_RS485_FEATURE
- } else if (strncmp(pos, "rs485=", 6) == 0) {
- /* get RS485 configuration. */
- diff --git a/readconfig.c b/readconfig.c
- index d4ca0d4..62cff5c 100644
- --- a/readconfig.c
- +++ b/readconfig.c
- @@ -31,6 +31,7 @@
- #include "readconfig.h"
- #include "utils.h"
- #include "telnet.h"
- +#include "sysfs-led.h"
-
- #define MAX_LINE_SIZE 256 /* Maximum line length in the config file. */
-
- @@ -361,6 +362,89 @@ free_rs485confs(void)
- }
- #endif
-
- +struct led_s
- +{
- + char *name;
- + char *device;
- + unsigned int duration;
- + struct led_s *next;
- +};
- +
- +/* all LEDs in the system. */
- +struct led_s *leds = NULL;
- +
- +static void
- +handle_led(char *name, char *cfg)
- +{
- + struct led_s *new_led;
- + char devicename[256];
- +
- + new_led = malloc(sizeof(*new_led));
- + if (!new_led) {
- + syslog(LOG_ERR, "Out of memory handling LED on %d", lineno);
- + return;
- + }
- +
- + new_led->name = strdup(name);
- + if (!new_led->name) {
- + syslog(LOG_ERR, "Out of memory handling LED on %d", lineno);
- + free(new_led);
- + return;
- + }
- +
- + if (sscanf(cfg, "%256s %u", devicename, &new_led->duration) != 2) {
- + syslog(LOG_ERR, "Couldn't parse LED config on %d", lineno);
- + free(new_led->name);
- + free(new_led);
- + return;
- + }
- +
- + new_led->device = strdup(devicename);
- + if (!new_led->device) {
- + syslog(LOG_ERR, "Out of memory handling LED on %d", lineno);
- + free(new_led->name);
- + free(new_led);
- + return;
- + }
- +
- + /* setup the led */
- + led_blink_prepare(new_led->device, new_led->duration);
- +
- + new_led->next = leds;
- + leds = new_led;
- +}
- +
- +char *
- +find_led(const char *name)
- +{
- + struct led_s *led = leds;
- +
- + while (led) {
- + if (strcmp(name, led->name) == 0)
- + return strdup(led->device);
- + led = led->next;
- + }
- + syslog(LOG_ERR, "LED %s not found, it will be ignored", name);
- + return NULL;
- +}
- +
- +static void
- +free_leds(void)
- +{
- + struct led_s *led;
- +
- + while (leds) {
- + led = leds;
- + leds = leds->next;
- +
- + led_off(led->device);
- +
- + free(led->name);
- + free(led->device);
- + free(led);
- + }
- +}
- +
- static int
- startswith(char *str, const char *test, char **strtok_data)
- {
- @@ -503,6 +587,21 @@ handle_config_line(char *inbuf)
- return;
- }
-
- + if (startswith(inbuf, "LED", &strtok_data)) {
- + char *name = strtok_r(NULL, ":", &strtok_data);
- + char *str = strtok_r(NULL, "\n", &strtok_data);
- + if (name == NULL) {
- + syslog(LOG_ERR, "No LED name given on line %d", lineno);
- + return;
- + }
- + if ((str == NULL) || (strlen(str) == 0)) {
- + syslog(LOG_ERR, "No LED given on line %d", lineno);
- + return;
- + }
- + handle_led(name, str);
- + return;
- + }
- +
- comma = strchr(inbuf, ',');
- if (comma) {
- if (!strtok_r(comma, ":", &strtok_data)) {
- @@ -568,6 +667,7 @@ readconfig(char *filename)
- #ifdef USE_RS485_FEATURE
- free_rs485confs();
- #endif
- + free_leds();
-
- config_num++;
-
- diff --git a/ser2net.conf b/ser2net.conf
- index 870926c..dc2ba19 100644
- --- a/ser2net.conf
- +++ b/ser2net.conf
- @@ -53,6 +53,8 @@
- # specified in TRACEFILE that will take all traced data.
- # tw is data written to the device, tr is data read from
- # the device, and tb is both.
- +# The "led-tx" and "led-rx" options allow to specify
- +# a LED defined above to trigger for traffic.
- #
- # or...
-
- @@ -79,6 +81,12 @@
- # This specifies a filename to trace output into, as tw=/tmp/trace1.
- # This takes the same escape sequences as banners.
- #
- +# LED:<name>:sysfs-filename duration
- +# This specifies a LED which will be configured to use linux's transient trigger.
- +# The LED is always kicked when traffic is detected on serial side. The duration
- +# is given in milliseconds. See Linux's documentation for transient trigger for
- +# details.
- +#
- # OPENSTR:<name>:str
- # This specifies a string to be transmitted to the device when the
- # port is opened. This takes the same escape sequences as banners.
- @@ -108,6 +116,9 @@ SIGNATURE:signature1:ser2net port ttyS2
-
- RS485CONF:rs485port1:0:0:0:0
-
- +LED:rx:duckbill:green:rs485 10
- +LED:tx:duckbill:red:rs485 10
- +
- TRACEFILE:tw1:/tmp/tw-\p-\Y-\M-\D-\H:\i:\s.\U
- TRACEFILE:tr1:/tmp/tr-\p-\Y-\M-\D-\H:\i:\s.\U
-
- @@ -138,3 +149,5 @@ CLOSESTR:close1:close str\r\n
-
- 3020:telnet:0:/dev/ttyUSB0:9600 banner1 remctl asdfasd
- 3021:telnet:0:/dev/ttyUSB1:9600 banner2 open1 close1 remctl
- +
- +5000:telnet:0:/dev/ttyAPP0:9600 NONE 1STOPBIT 8DATABITS -XONXOFF LOCAL -RTSCTS led-tx=tx led-rx=rx
- diff --git a/sysfs-led.c b/sysfs-led.c
- new file mode 100644
- index 0000000..efe0b29
- --- /dev/null
- +++ b/sysfs-led.c
- @@ -0,0 +1,43 @@
- +/*
- + * Copyright (C) 2015 I2SE GmbH
- + */
- +#include <stdio.h>
- +#include <string.h>
- +
- +#include "utils.h"
- +#include "sysfs-led.h"
- +
- +#define SYSFS_LED_BASE "/sys/class/leds"
- +
- +static int led_write(char *led, char *property, char *buf)
- +{
- + char fn[255];
- +
- + snprintf(fn, sizeof(fn), "%s/%s/%s", SYSFS_LED_BASE, led, property);
- +
- + return file_store(fn, buf, strlen(buf));
- +}
- +
- +int led_off(char *led)
- +{
- + led_write(led, "trigger", "none");
- + led_write(led, "brightness", "0");
- + return 0;
- +}
- +
- +int led_blink_prepare(char *led, unsigned int duration)
- +{
- + char buffer[10];
- +
- + snprintf(buffer, sizeof(buffer), "%u", duration);
- + led_write(led, "trigger", "transient");
- + msleep(10);
- + led_write(led, "state", "1");
- + led_write(led, "duration", buffer);
- + return 0;
- +}
- +
- +int led_blink_kick(char *led)
- +{
- + return led_write(led, "activate", "1");
- +}
- diff --git a/sysfs-led.h b/sysfs-led.h
- new file mode 100644
- index 0000000..00b21b6
- --- /dev/null
- +++ b/sysfs-led.h
- @@ -0,0 +1,11 @@
- +/*
- + * Copyright (C) 2015 I2SE GmbH
- + */
- +#ifndef SYSFS_LED_H
- +#define SYSFS_LED_H
- +
- +int led_off(char *led);
- +int led_blink_prepare(char *led, unsigned int duration);
- +int led_blink_kick(char *led);
- +
- +#endif /* SYSFS_LED_H */
- diff --git a/utils.c b/utils.c
- index c194c4c..c96cedb 100644
- --- a/utils.c
- +++ b/utils.c
- @@ -25,6 +25,9 @@
- #include <errno.h>
- #include <unistd.h>
- #include <fcntl.h>
- +#include <time.h>
- +#include <sys/types.h>
- +#include <sys/stat.h>
-
- #include "ser2net.h"
- #include "utils.h"
- @@ -205,3 +208,30 @@ write_ignore_fail(int fd, const char *data, size_t count)
- count -= written;
- }
- }
- +
- +int
- +msleep(int msec)
- +{
- + struct timespec req;
- +
- + req.tv_sec = 0;
- + req.tv_nsec = msec * 1000000;
- +
- + return nanosleep(&req, NULL);
- +}
- +
- +int
- +file_store(const char *filename, const char *buf, size_t count)
- +{
- + int fd;
- +
- + if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1)
- + return -1;
- +
- + if (write(fd, buf, count) != count) {
- + close(fd);
- + return -1;
- + }
- +
- + return close(fd);
- +}
- diff --git a/utils.h b/utils.h
- index 582ea88..8af65ec 100644
- --- a/utils.h
- +++ b/utils.h
- @@ -64,6 +64,9 @@ char *find_tracefile(const char *name);
- /* Search for RS485 configuration by name. */
- struct serial_rs485 *find_rs485conf(const char *name);
-
- +/* Search for a LED by name */
- +char *find_led(const char *name);
- +
- void check_ipv6_only(int family, struct sockaddr *addr, int fd);
-
- /* Make sure the full contents get written, return an error if it occurs. */
- @@ -72,4 +75,10 @@ int write_full(int fd, char *data, size_t count);
- /* Write the data completely out, return without comment on error. */
- void write_ignore_fail(int fd, const char *data, size_t count);
-
- +/* Helper to sleep a given amount of milli-seconds */
- +int msleep(int msec);
- +
- +/* Store the given data to a file */
- +int file_store(const char *filename, const char *buf, size_t count);
- +
- #endif /* UTILS */
- --
- 1.7.10.4
-
|