-
Notifications
You must be signed in to change notification settings - Fork 3
/
main.c
229 lines (202 loc) · 5.69 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/*
* Copyright 2016, Grinn
* Author: Marcin Niestroj <m.niestroj@grinn-global.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <asm-generic/ioctls.h>
#include <linux/serial.h>
#include <sys/ioctl.h>
void show_help(const char *progname)
{
printf("usage: %s [-h] tty\n", progname);
printf("\n");
printf("Get/set RS485 configuration of TTY.\n");
printf("\n");
printf("positional arguments:\n");
printf(" tty TTY to get/set configuration (e.g. /dev/ttyS1)\n");
printf("\n");
printf("optional arguments:\n");
printf(" -e {0,1} Disable/enable RS485 mode\n");
printf(" -o {0,1} Set RTS on send low/high\n");
printf(" -a {0,1} Set RTS after send low/high\n");
printf(" -r {0,1} Set RX during TX\n");
printf(" -d d1 d2 Set delay RTS before (d1) and after (d2) send\n");
printf(" -t {0,1} Set bus termination\n");
}
void dump_conf(struct serial_rs485 *rs485conf)
{
printf("RS485 enabled: %s\n", (rs485conf->flags & SER_RS485_ENABLED) ? "true" : "false");
printf("RTS on send: %s\n", (rs485conf->flags & SER_RS485_RTS_ON_SEND) ? "high" : "low");
printf("RTS after send: %s\n", (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) ? "high" : "low");
printf("RTS delay before send: %d\n", (int) rs485conf->delay_rts_before_send);
printf("RTS delay after send: %d\n", (int) rs485conf->delay_rts_after_send);
printf("Receive during sending data: %s\n", (rs485conf->flags & SER_RS485_RX_DURING_TX) ? "true" : "false");
printf("Bus termination enabled: %s\n", (rs485conf->flags & SER_RS485_TERMINATE_BUS) ? "true" : "false");
}
enum state {
STATE_NONE,
STATE_TRUE,
STATE_FALSE
};
struct config {
const char *tty;
enum state enabled;
enum state rts_on_send;
enum state rts_after_send;
enum state rx_during_tx;
int delay_rts_before_send;
int delay_rts_after_send;
enum state bus_term;
};
static struct config config = {
.delay_rts_before_send = -1,
.delay_rts_after_send = -1,
};
#define SET_FLAGS_FROM_STATE(flags, bit, state) \
do { \
if (state) { \
if (state == STATE_TRUE) \
flags |= bit; \
else \
flags &= ~(bit); \
} \
} while (0);
void opt_fail(const char *err)
{
fprintf(stderr, "Error: %s\n", err);
exit(1);
}
void parse_options(int argc, char **argv)
{
int c;
while ((c = getopt(argc, argv, "he:o:a:r:d:t:")) != -1) {
switch (c) {
case 'h':
show_help(argv[0]);
exit(0);
break;
case 'e':
if (!strcmp(optarg, "0"))
config.enabled = STATE_FALSE;
else if (!strcmp(optarg, "1"))
config.enabled = STATE_TRUE;
else
opt_fail("Invalid -e argument!\n");
break;
case 'o':
if (!strcmp(optarg, "0"))
config.rts_on_send = STATE_FALSE;
else if (!strcmp(optarg, "1"))
config.rts_on_send = STATE_TRUE;
else
opt_fail("Invalid -o argument!\n");
break;
case 'a':
if (!strcmp(optarg, "0"))
config.rts_after_send = STATE_FALSE;
else if (!strcmp(optarg, "1"))
config.rts_after_send = STATE_TRUE;
else
opt_fail("Invalid -a argument!\n");
break;
case 'r':
if (!strcmp(optarg, "0"))
config.rx_during_tx = STATE_FALSE;
else if (!strcmp(optarg, "1"))
config.rx_during_tx = STATE_TRUE;
else
opt_fail("Invalid -r argument!\n");
break;
case 'd': {
unsigned long int d1;
unsigned long int d2;
errno = 0;
d1 = strtoul(optarg, NULL, 0);
if (errno)
opt_fail("Invalid -d 1st argument\n");
d2 = strtoul(argv[optind], NULL, 0);
if (errno)
opt_fail("Invalid -d 2nd argument\n");
optind++;
config.delay_rts_before_send = d1;
config.delay_rts_after_send = d2;
break;
}
case 't':
if (!strcmp(optarg, "0"))
config.bus_term = STATE_FALSE;
else if (!strcmp(optarg, "1"))
config.bus_term = STATE_TRUE;
else
opt_fail("Invalid -t argument!\n");
break;
}
}
if (!argv[optind]) {
show_help(argv[0]);
exit(1);
}
config.tty = argv[optind];
}
int main(int argc, char *argv[])
{
struct serial_rs485 rs485conf;
int fd;
int ret;
parse_options(argc, argv);
fd = open(config.tty, O_RDWR);
if (fd < 0) {
perror("Failed to open tty device\n");
exit(1);
}
/* Get current configuration */
ret = ioctl(fd, TIOCGRS485, &rs485conf);
if (ret < 0) {
perror("Failed to get RS485 configuration");
exit(1);
}
printf("= Current configuration:\n");
dump_conf(&rs485conf);
if (config.enabled == STATE_NONE &&
config.rts_on_send == STATE_NONE &&
config.rts_after_send == STATE_NONE &&
config.rx_during_tx == STATE_NONE &&
config.delay_rts_before_send == -1 &&
config.delay_rts_after_send == -1 &&
config.bus_term == STATE_NONE)
goto close_fd;
/* Set new configuration */
SET_FLAGS_FROM_STATE(rs485conf.flags, SER_RS485_ENABLED, config.enabled);
SET_FLAGS_FROM_STATE(rs485conf.flags, SER_RS485_RTS_ON_SEND, config.rts_on_send);
SET_FLAGS_FROM_STATE(rs485conf.flags, SER_RS485_RTS_AFTER_SEND, config.rts_after_send);
SET_FLAGS_FROM_STATE(rs485conf.flags, SER_RS485_RX_DURING_TX, config.rx_during_tx);
SET_FLAGS_FROM_STATE(rs485conf.flags, SER_RS485_TERMINATE_BUS, config.bus_term);
if (config.delay_rts_before_send != -1)
rs485conf.delay_rts_before_send = config.delay_rts_before_send;
if (config.delay_rts_after_send != -1)
rs485conf.delay_rts_after_send = config.delay_rts_after_send;
printf("\n");
printf("= New configuration:\n");
dump_conf(&rs485conf);
ret = ioctl(fd, TIOCSRS485, &rs485conf);
if (ret < 0) {
perror("Failed to set RS485 configuration");
exit(1);
}
printf("\n");
printf("= Saved configuration:\n");
dump_conf(&rs485conf);
close_fd:
if (close(fd) < 0) {
perror("Failed to close tty\n");
exit(1);
}
return 0;
}