|
@@ -0,0 +1,418 @@
|
|
1
|
+From fa68debd94d40299dd2a69abd0a820ccfaadcbe8 Mon Sep 17 00:00:00 2001
|
|
2
|
+From: Michael Heimpold <michael.heimpold@i2se.com>
|
|
3
|
+Date: Wed, 22 Apr 2015 13:35:43 +0200
|
|
4
|
+Subject: [PATCH] Add support for triggering LEDs during serial traffic
|
|
5
|
+
|
|
6
|
+Signed-off-by: Michael Heimpold <michael.heimpold@i2se.com>
|
|
7
|
+---
|
|
8
|
+
|
|
9
|
+Patch sent upstream:
|
|
10
|
+ http://sourceforge.net/p/ser2net/mailman/message/34064847/
|
|
11
|
+
|
|
12
|
+ Makefile.am | 4 +--
|
|
13
|
+ dataxfer.c | 20 ++++++++++++
|
|
14
|
+ readconfig.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
15
|
+ ser2net.conf | 13 ++++++++
|
|
16
|
+ sysfs-led.c | 43 +++++++++++++++++++++++++
|
|
17
|
+ sysfs-led.h | 11 +++++++
|
|
18
|
+ utils.c | 30 ++++++++++++++++++
|
|
19
|
+ utils.h | 9 ++++++
|
|
20
|
+ 8 files changed, 228 insertions(+), 2 deletions(-)
|
|
21
|
+ create mode 100644 sysfs-led.c
|
|
22
|
+ create mode 100644 sysfs-led.h
|
|
23
|
+
|
|
24
|
+diff --git a/Makefile.am b/Makefile.am
|
|
25
|
+index d56179f..866eb89 100644
|
|
26
|
+--- a/Makefile.am
|
|
27
|
|
|
28
|
+@@ -2,9 +2,9 @@ sbin_PROGRAMS = ser2net
|
|
29
|
+ ACLOCAL_AMFLAGS = -I m4
|
|
30
|
+ AM_CFLAGS=-Wall
|
|
31
|
+ ser2net_SOURCES = controller.c dataxfer.c devcfg.c readconfig.c selector.c \
|
|
32
|
+- ser2net.c utils.c telnet.c buffer.c
|
|
33
|
++ ser2net.c utils.c telnet.c buffer.c sysfs-led.c
|
|
34
|
+ noinst_HEADERS = controller.h dataxfer.h devio.h readconfig.h selector.h \
|
|
35
|
+- utils.h telnet.h buffer.h ser2net.h
|
|
36
|
++ utils.h telnet.h buffer.h sysfs-led.h ser2net.h
|
|
37
|
+ man_MANS = ser2net.8
|
|
38
|
+ EXTRA_DIST = $(man_MANS) ser2net.conf ser2net.spec ser2net.init
|
|
39
|
+
|
|
40
|
+diff --git a/dataxfer.c b/dataxfer.c
|
|
41
|
+index 646a71b..b99cabf 100644
|
|
42
|
+--- a/dataxfer.c
|
|
43
|
|
|
44
|
+@@ -42,6 +42,7 @@
|
|
45
|
+ #include "telnet.h"
|
|
46
|
+ #include "devio.h"
|
|
47
|
+ #include "buffer.h"
|
|
48
|
++#include "sysfs-led.h"
|
|
49
|
+
|
|
50
|
+ #define SERIAL "term"
|
|
51
|
+ #define NET "tcp "
|
|
52
|
+@@ -230,6 +231,12 @@ typedef struct port_info
|
|
53
|
+ #ifdef USE_RS485_FEATURE
|
|
54
|
+ struct serial_rs485 *rs485conf;
|
|
55
|
+ #endif
|
|
56
|
++
|
|
57
|
++ /*
|
|
58
|
++ * LED names to flash for serial traffic
|
|
59
|
++ */
|
|
60
|
++ char *led_tx;
|
|
61
|
++ char *led_rx;
|
|
62
|
+ } port_info_t;
|
|
63
|
+
|
|
64
|
+ port_info_t *ports = NULL; /* Linked list of ports. */
|
|
65
|
+@@ -311,6 +318,8 @@ init_port_data(port_info_t *port)
|
|
66
|
+ #ifdef USE_RS485_FEATURE
|
|
67
|
+ port->rs485conf = NULL;
|
|
68
|
+ #endif
|
|
69
|
++ port->led_tx = NULL;
|
|
70
|
++ port->led_rx = NULL;
|
|
71
|
+ }
|
|
72
|
+
|
|
73
|
+ static void
|
|
74
|
+@@ -530,6 +539,9 @@ handle_dev_fd_read(struct devio *io)
|
|
75
|
+ /* Do both tracing, ignore errors. */
|
|
76
|
+ do_trace(port, port->tb, port->dev_to_tcp.buf, count, SERIAL);
|
|
77
|
+
|
|
78
|
++ if (port->led_rx)
|
|
79
|
++ led_blink_kick(port->led_rx);
|
|
80
|
++
|
|
81
|
+ port->dev_bytes_received += count;
|
|
82
|
+
|
|
83
|
+ if (port->enabled == PORT_TELNET) {
|
|
84
|
+@@ -759,6 +771,8 @@ handle_tcp_fd_read(int fd, void *data)
|
|
85
|
+ return;
|
|
86
|
+ }
|
|
87
|
+ } else {
|
|
88
|
++ if (port->led_tx)
|
|
89
|
++ led_blink_kick(port->led_tx);
|
|
90
|
+ port->dev_bytes_sent += count;
|
|
91
|
+ port->tcp_to_dev.cursize -= count;
|
|
92
|
+ if (port->tcp_to_dev.cursize != 0) {
|
|
93
|
+@@ -1854,6 +1868,12 @@ myconfig(void *data, struct absout *eout, const char *pos)
|
|
94
|
+ } else if (strncmp(pos, "tb=", 3) == 0) {
|
|
95
|
+ /* trace both directions. */
|
|
96
|
+ port->trace_both.filename = find_tracefile(pos + 3);
|
|
97
|
++ } else if (strncmp(pos, "led-rx=", 7) == 0) {
|
|
98
|
++ /* LED for UART RX traffic */
|
|
99
|
++ port->led_rx = find_led(pos + 7);
|
|
100
|
++ } else if (strncmp(pos, "led-tx=", 7) == 0) {
|
|
101
|
++ /* LED for UART TX traffic */
|
|
102
|
++ port->led_tx = find_led(pos + 7);
|
|
103
|
+ #ifdef USE_RS485_FEATURE
|
|
104
|
+ } else if (strncmp(pos, "rs485=", 6) == 0) {
|
|
105
|
+ /* get RS485 configuration. */
|
|
106
|
+diff --git a/readconfig.c b/readconfig.c
|
|
107
|
+index d4ca0d4..62cff5c 100644
|
|
108
|
+--- a/readconfig.c
|
|
109
|
|
|
110
|
+@@ -31,6 +31,7 @@
|
|
111
|
+ #include "readconfig.h"
|
|
112
|
+ #include "utils.h"
|
|
113
|
+ #include "telnet.h"
|
|
114
|
++#include "sysfs-led.h"
|
|
115
|
+
|
|
116
|
+ #define MAX_LINE_SIZE 256 /* Maximum line length in the config file. */
|
|
117
|
+
|
|
118
|
+@@ -361,6 +362,89 @@ free_rs485confs(void)
|
|
119
|
+ }
|
|
120
|
+ #endif
|
|
121
|
+
|
|
122
|
++struct led_s
|
|
123
|
++{
|
|
124
|
++ char *name;
|
|
125
|
++ char *device;
|
|
126
|
++ unsigned int duration;
|
|
127
|
++ struct led_s *next;
|
|
128
|
++};
|
|
129
|
++
|
|
130
|
++/* all LEDs in the system. */
|
|
131
|
++struct led_s *leds = NULL;
|
|
132
|
++
|
|
133
|
++static void
|
|
134
|
++handle_led(char *name, char *cfg)
|
|
135
|
++{
|
|
136
|
++ struct led_s *new_led;
|
|
137
|
++ char devicename[256];
|
|
138
|
++
|
|
139
|
++ new_led = malloc(sizeof(*new_led));
|
|
140
|
++ if (!new_led) {
|
|
141
|
++ syslog(LOG_ERR, "Out of memory handling LED on %d", lineno);
|
|
142
|
++ return;
|
|
143
|
++ }
|
|
144
|
++
|
|
145
|
++ new_led->name = strdup(name);
|
|
146
|
++ if (!new_led->name) {
|
|
147
|
++ syslog(LOG_ERR, "Out of memory handling LED on %d", lineno);
|
|
148
|
++ free(new_led);
|
|
149
|
++ return;
|
|
150
|
++ }
|
|
151
|
++
|
|
152
|
++ if (sscanf(cfg, "%256s %u", devicename, &new_led->duration) != 2) {
|
|
153
|
++ syslog(LOG_ERR, "Couldn't parse LED config on %d", lineno);
|
|
154
|
++ free(new_led->name);
|
|
155
|
++ free(new_led);
|
|
156
|
++ return;
|
|
157
|
++ }
|
|
158
|
++
|
|
159
|
++ new_led->device = strdup(devicename);
|
|
160
|
++ if (!new_led->device) {
|
|
161
|
++ syslog(LOG_ERR, "Out of memory handling LED on %d", lineno);
|
|
162
|
++ free(new_led->name);
|
|
163
|
++ free(new_led);
|
|
164
|
++ return;
|
|
165
|
++ }
|
|
166
|
++
|
|
167
|
++ /* setup the led */
|
|
168
|
++ led_blink_prepare(new_led->device, new_led->duration);
|
|
169
|
++
|
|
170
|
++ new_led->next = leds;
|
|
171
|
++ leds = new_led;
|
|
172
|
++}
|
|
173
|
++
|
|
174
|
++char *
|
|
175
|
++find_led(const char *name)
|
|
176
|
++{
|
|
177
|
++ struct led_s *led = leds;
|
|
178
|
++
|
|
179
|
++ while (led) {
|
|
180
|
++ if (strcmp(name, led->name) == 0)
|
|
181
|
++ return strdup(led->device);
|
|
182
|
++ led = led->next;
|
|
183
|
++ }
|
|
184
|
++ syslog(LOG_ERR, "LED %s not found, it will be ignored", name);
|
|
185
|
++ return NULL;
|
|
186
|
++}
|
|
187
|
++
|
|
188
|
++static void
|
|
189
|
++free_leds(void)
|
|
190
|
++{
|
|
191
|
++ struct led_s *led;
|
|
192
|
++
|
|
193
|
++ while (leds) {
|
|
194
|
++ led = leds;
|
|
195
|
++ leds = leds->next;
|
|
196
|
++
|
|
197
|
++ led_off(led->device);
|
|
198
|
++
|
|
199
|
++ free(led->name);
|
|
200
|
++ free(led->device);
|
|
201
|
++ free(led);
|
|
202
|
++ }
|
|
203
|
++}
|
|
204
|
++
|
|
205
|
+ static int
|
|
206
|
+ startswith(char *str, const char *test, char **strtok_data)
|
|
207
|
+ {
|
|
208
|
+@@ -503,6 +587,21 @@ handle_config_line(char *inbuf)
|
|
209
|
+ return;
|
|
210
|
+ }
|
|
211
|
+
|
|
212
|
++ if (startswith(inbuf, "LED", &strtok_data)) {
|
|
213
|
++ char *name = strtok_r(NULL, ":", &strtok_data);
|
|
214
|
++ char *str = strtok_r(NULL, "\n", &strtok_data);
|
|
215
|
++ if (name == NULL) {
|
|
216
|
++ syslog(LOG_ERR, "No LED name given on line %d", lineno);
|
|
217
|
++ return;
|
|
218
|
++ }
|
|
219
|
++ if ((str == NULL) || (strlen(str) == 0)) {
|
|
220
|
++ syslog(LOG_ERR, "No LED given on line %d", lineno);
|
|
221
|
++ return;
|
|
222
|
++ }
|
|
223
|
++ handle_led(name, str);
|
|
224
|
++ return;
|
|
225
|
++ }
|
|
226
|
++
|
|
227
|
+ comma = strchr(inbuf, ',');
|
|
228
|
+ if (comma) {
|
|
229
|
+ if (!strtok_r(comma, ":", &strtok_data)) {
|
|
230
|
+@@ -568,6 +667,7 @@ readconfig(char *filename)
|
|
231
|
+ #ifdef USE_RS485_FEATURE
|
|
232
|
+ free_rs485confs();
|
|
233
|
+ #endif
|
|
234
|
++ free_leds();
|
|
235
|
+
|
|
236
|
+ config_num++;
|
|
237
|
+
|
|
238
|
+diff --git a/ser2net.conf b/ser2net.conf
|
|
239
|
+index 870926c..dc2ba19 100644
|
|
240
|
+--- a/ser2net.conf
|
|
241
|
|
|
242
|
+@@ -53,6 +53,8 @@
|
|
243
|
+ # specified in TRACEFILE that will take all traced data.
|
|
244
|
+ # tw is data written to the device, tr is data read from
|
|
245
|
+ # the device, and tb is both.
|
|
246
|
++# The "led-tx" and "led-rx" options allow to specify
|
|
247
|
++# a LED defined above to trigger for traffic.
|
|
248
|
+ #
|
|
249
|
+ # or...
|
|
250
|
+
|
|
251
|
+@@ -79,6 +81,12 @@
|
|
252
|
+ # This specifies a filename to trace output into, as tw=/tmp/trace1.
|
|
253
|
+ # This takes the same escape sequences as banners.
|
|
254
|
+ #
|
|
255
|
++# LED:<name>:sysfs-filename duration
|
|
256
|
++# This specifies a LED which will be configured to use linux's transient trigger.
|
|
257
|
++# The LED is always kicked when traffic is detected on serial side. The duration
|
|
258
|
++# is given in milliseconds. See Linux's documentation for transient trigger for
|
|
259
|
++# details.
|
|
260
|
++#
|
|
261
|
+ # OPENSTR:<name>:str
|
|
262
|
+ # This specifies a string to be transmitted to the device when the
|
|
263
|
+ # port is opened. This takes the same escape sequences as banners.
|
|
264
|
+@@ -108,6 +116,9 @@ SIGNATURE:signature1:ser2net port ttyS2
|
|
265
|
+
|
|
266
|
+ RS485CONF:rs485port1:0:0:0:0
|
|
267
|
+
|
|
268
|
++LED:rx:duckbill:green:rs485 10
|
|
269
|
++LED:tx:duckbill:red:rs485 10
|
|
270
|
++
|
|
271
|
+ TRACEFILE:tw1:/tmp/tw-\p-\Y-\M-\D-\H:\i:\s.\U
|
|
272
|
+ TRACEFILE:tr1:/tmp/tr-\p-\Y-\M-\D-\H:\i:\s.\U
|
|
273
|
+
|
|
274
|
+@@ -138,3 +149,5 @@ CLOSESTR:close1:close str\r\n
|
|
275
|
+
|
|
276
|
+ 3020:telnet:0:/dev/ttyUSB0:9600 banner1 remctl asdfasd
|
|
277
|
+ 3021:telnet:0:/dev/ttyUSB1:9600 banner2 open1 close1 remctl
|
|
278
|
++
|
|
279
|
++5000:telnet:0:/dev/ttyAPP0:9600 NONE 1STOPBIT 8DATABITS -XONXOFF LOCAL -RTSCTS led-tx=tx led-rx=rx
|
|
280
|
+diff --git a/sysfs-led.c b/sysfs-led.c
|
|
281
|
+new file mode 100644
|
|
282
|
+index 0000000..efe0b29
|
|
283
|
+--- /dev/null
|
|
284
|
|
|
285
|
+@@ -0,0 +1,43 @@
|
|
286
|
++/*
|
|
287
|
++ * Copyright (C) 2015 I2SE GmbH
|
|
288
|
++ */
|
|
289
|
++#include <stdio.h>
|
|
290
|
++#include <string.h>
|
|
291
|
++
|
|
292
|
++#include "utils.h"
|
|
293
|
++#include "sysfs-led.h"
|
|
294
|
++
|
|
295
|
++#define SYSFS_LED_BASE "/sys/class/leds"
|
|
296
|
++
|
|
297
|
++static int led_write(char *led, char *property, char *buf)
|
|
298
|
++{
|
|
299
|
++ char fn[255];
|
|
300
|
++
|
|
301
|
++ snprintf(fn, sizeof(fn), "%s/%s/%s", SYSFS_LED_BASE, led, property);
|
|
302
|
++
|
|
303
|
++ return file_store(fn, buf, strlen(buf));
|
|
304
|
++}
|
|
305
|
++
|
|
306
|
++int led_off(char *led)
|
|
307
|
++{
|
|
308
|
++ led_write(led, "trigger", "none");
|
|
309
|
++ led_write(led, "brightness", "0");
|
|
310
|
++ return 0;
|
|
311
|
++}
|
|
312
|
++
|
|
313
|
++int led_blink_prepare(char *led, unsigned int duration)
|
|
314
|
++{
|
|
315
|
++ char buffer[10];
|
|
316
|
++
|
|
317
|
++ snprintf(buffer, sizeof(buffer), "%u", duration);
|
|
318
|
++ led_write(led, "trigger", "transient");
|
|
319
|
++ msleep(10);
|
|
320
|
++ led_write(led, "state", "1");
|
|
321
|
++ led_write(led, "duration", buffer);
|
|
322
|
++ return 0;
|
|
323
|
++}
|
|
324
|
++
|
|
325
|
++int led_blink_kick(char *led)
|
|
326
|
++{
|
|
327
|
++ return led_write(led, "activate", "1");
|
|
328
|
++}
|
|
329
|
+diff --git a/sysfs-led.h b/sysfs-led.h
|
|
330
|
+new file mode 100644
|
|
331
|
+index 0000000..00b21b6
|
|
332
|
+--- /dev/null
|
|
333
|
|
|
334
|
+@@ -0,0 +1,11 @@
|
|
335
|
++/*
|
|
336
|
++ * Copyright (C) 2015 I2SE GmbH
|
|
337
|
++ */
|
|
338
|
++#ifndef SYSFS_LED_H
|
|
339
|
++#define SYSFS_LED_H
|
|
340
|
++
|
|
341
|
++int led_off(char *led);
|
|
342
|
++int led_blink_prepare(char *led, unsigned int duration);
|
|
343
|
++int led_blink_kick(char *led);
|
|
344
|
++
|
|
345
|
++#endif /* SYSFS_LED_H */
|
|
346
|
+diff --git a/utils.c b/utils.c
|
|
347
|
+index c194c4c..c96cedb 100644
|
|
348
|
+--- a/utils.c
|
|
349
|
|
|
350
|
+@@ -25,6 +25,9 @@
|
|
351
|
+ #include <errno.h>
|
|
352
|
+ #include <unistd.h>
|
|
353
|
+ #include <fcntl.h>
|
|
354
|
++#include <time.h>
|
|
355
|
++#include <sys/types.h>
|
|
356
|
++#include <sys/stat.h>
|
|
357
|
+
|
|
358
|
+ #include "ser2net.h"
|
|
359
|
+ #include "utils.h"
|
|
360
|
+@@ -205,3 +208,30 @@ write_ignore_fail(int fd, const char *data, size_t count)
|
|
361
|
+ count -= written;
|
|
362
|
+ }
|
|
363
|
+ }
|
|
364
|
++
|
|
365
|
++int
|
|
366
|
++msleep(int msec)
|
|
367
|
++{
|
|
368
|
++ struct timespec req;
|
|
369
|
++
|
|
370
|
++ req.tv_sec = 0;
|
|
371
|
++ req.tv_nsec = msec * 1000000;
|
|
372
|
++
|
|
373
|
++ return nanosleep(&req, NULL);
|
|
374
|
++}
|
|
375
|
++
|
|
376
|
++int
|
|
377
|
++file_store(const char *filename, const char *buf, size_t count)
|
|
378
|
++{
|
|
379
|
++ int fd;
|
|
380
|
++
|
|
381
|
++ if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1)
|
|
382
|
++ return -1;
|
|
383
|
++
|
|
384
|
++ if (write(fd, buf, count) != count) {
|
|
385
|
++ close(fd);
|
|
386
|
++ return -1;
|
|
387
|
++ }
|
|
388
|
++
|
|
389
|
++ return close(fd);
|
|
390
|
++}
|
|
391
|
+diff --git a/utils.h b/utils.h
|
|
392
|
+index 582ea88..8af65ec 100644
|
|
393
|
+--- a/utils.h
|
|
394
|
|
|
395
|
+@@ -64,6 +64,9 @@ char *find_tracefile(const char *name);
|
|
396
|
+ /* Search for RS485 configuration by name. */
|
|
397
|
+ struct serial_rs485 *find_rs485conf(const char *name);
|
|
398
|
+
|
|
399
|
++/* Search for a LED by name */
|
|
400
|
++char *find_led(const char *name);
|
|
401
|
++
|
|
402
|
+ void check_ipv6_only(int family, struct sockaddr *addr, int fd);
|
|
403
|
+
|
|
404
|
+ /* Make sure the full contents get written, return an error if it occurs. */
|
|
405
|
+@@ -72,4 +75,10 @@ int write_full(int fd, char *data, size_t count);
|
|
406
|
+ /* Write the data completely out, return without comment on error. */
|
|
407
|
+ void write_ignore_fail(int fd, const char *data, size_t count);
|
|
408
|
+
|
|
409
|
++/* Helper to sleep a given amount of milli-seconds */
|
|
410
|
++int msleep(int msec);
|
|
411
|
++
|
|
412
|
++/* Store the given data to a file */
|
|
413
|
++int file_store(const char *filename, const char *buf, size_t count);
|
|
414
|
++
|
|
415
|
+ #endif /* UTILS */
|
|
416
|
+--
|
|
417
|
+1.7.10.4
|
|
418
|
+
|