2 This file is part of CanFestival, a library implementing CanOpen Stack.
4 Copyright (C): James Steward
6 See COPYING file for copyrights details.
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 Pseudo CAN hub application.
27 #define _GNU_SOURCE //for asprintf()
38 #define NEED_PRINT_MESSAGE
44 #define DLL_CALL(funcname) (* funcname##_driver)
46 #include "canfestival.h"
48 int DLL_CALL(canfd)(CAN_HANDLE)FCT_PTR_INIT;
54 #define DLL_CALL(funcname) funcname##_driver
57 *(void **) (&name##_driver) = dlsym(handle, #name"_driver");\
58 if ((error = dlerror()) != NULL) {\
59 fprintf (stderr, "%s\n", error);\
60 UnLoadCanDriver(handle);\
64 #define MAX_HUB_PORTS 16
68 struct termios old_termio, new_termio;
72 port hub_ports[MAX_HUB_PORTS + 1]; //An extra for a CAN driver port
74 s_BOARD bus_if = { "/dev/ttyS0", "125K" };
76 /* Receive a CAN message from a hub (pseudo) port */
77 int hub_receive(port *p, Message *m)
83 N = 4; //initially try to read 4 bytes, including the length byte
86 rv = read(p->fd, &((char *)m)[n], N - n);
89 fprintf(stderr, "read: %d, %s\n", p->fd, strerror(errno));
99 fprintf(stderr, "Warning: invalid message length %d\n",
111 FD_SET(p->fd, &rfds);
116 rv = select(p->fd + 1, &rfds, NULL, NULL, &tv);
117 if (rv == 0 || rv == -1) {
118 fprintf(stderr, "select: %s\n", strerror(errno));
128 /* send a CAN message to one of the hub ports */
129 UNS8 hub_send(port *p, Message *m)
133 rv = write(p->fd, m, 4 + m->len);
135 if (rv != 4 + m->len) {
142 /* Open a hub port */
143 int hub_open(port *p)
146 fprintf(stderr, "Warning, port %s is already open, fd %d!\n",
150 p->fd = open(p->name, O_RDWR);
153 fprintf(stderr, "open: %s, %s\n", p->name, strerror(errno));
157 if (tcgetattr(p->fd, &p->old_termio) != 0) {
158 fprintf(stderr, "tcgetattr: %s, %s\n",
159 p->name, strerror(errno));
165 memcpy(&p->new_termio, &p->old_termio, sizeof(p->old_termio));
166 cfmakeraw(&p->new_termio);
167 cfsetispeed(&p->new_termio, B115200);
168 cfsetospeed(&p->new_termio, B115200);
169 tcsetattr(p->fd, TCSANOW, &p->new_termio);
175 /* Close a hub port*/
176 int hub_close(port *p)
179 tcsetattr(p->fd, TCSANOW, &p->old_termio);
187 /** Read from the port index rd_port, and write to all other ports. */
188 int read_write(int rd_port, port *p, CAN_HANDLE h, fd_set *wfds, int max_fd)
193 struct timeval tv = {.tv_sec = 0, .tv_usec = 0}; //wait 0 msec
195 if (rd_port == MAX_HUB_PORTS) {
196 rv = DLL_CALL(canReceive)(h, &m);
202 rv = hub_receive(&p[rd_port], &m);
209 memcpy(&wfds_copy, wfds, sizeof(fd_set));
211 rv = select(max_fd + 1, NULL, &wfds_copy, NULL, &tv);
217 for (i = 0; i < MAX_HUB_PORTS + 1; i++) {
220 fprintf(stderr, "[%d] ", i);
224 if (p[i].fd < 0 || !FD_ISSET(p[i].fd, &wfds_copy)) {
225 fprintf(stderr, "{%d} ", i);
229 fprintf(stderr, "<%d> ", i);
231 if (i == MAX_HUB_PORTS && h) {
232 DLL_CALL(canSend)(h, &m);
246 printf("This is a software hub for the CANFestival library, \n");
247 printf("based on the *nix pseudo tty. It supports up to 16\n");
248 printf("connections from clients, and a connection to a CANFestival\n");
249 printf("driver, for connection to the outside world.\n");
251 printf("Basic use is simply to run can_hub. Without arguments, it\n");
252 printf("will use /dev/ptya[0..f] ptys. You should then run your\n");
253 printf("linux CANFestival app using libcanfestival_can_serial.so\n");
254 printf("with the bus name /dev/ttyaX, where X is 0..f and unused.\n");
256 printf("You can alter the pty base with -p /dev/ptyx .\n");
258 printf("If you want to interface with some other CAN driver, supply\n");
259 printf("the option -l /path/to/libcanfestival_can_foo.so .\n");
260 printf("The default bus name and baud are /dev/ttyS0 and 125k.\n");
261 printf("These can be overridden with -b /dev/{bus name} and -s {baud}.\n");
265 UNS8 UnLoadCanDriver(LIB_HANDLE handle)
277 /*Loads the dll and get funcs ptr*/
278 LIB_HANDLE LoadCanDriver(char* driver_name)
280 LIB_HANDLE handle = NULL;
285 handle = dlopen(driver_name, RTLD_LAZY);
289 fprintf (stderr, "%s\n", dlerror());
297 DLSYM(canChangeBaudRate)
306 int main(int argc, char **argv)
308 int i, rv, max_fd = 0, ret = 0;
309 fd_set rfds, rfds_copy;
310 CAN_HANDLE can_h = NULL;
311 LIB_HANDLE lib_h = NULL;
316 char *can_drv = NULL;
317 char *pty_base = "/dev/ptya";
319 while ((c = getopt(argc, argv, "-b:s:l:p:h")) != EOF) {
322 if (optarg[0] == 0) {
326 bus_if.busname = optarg;
329 if (optarg[0] == 0) {
333 bus_if.baudrate = optarg;
336 if (optarg[0] == 0) {
343 if (optarg[0] == 0) {
361 hub_ports[MAX_HUB_PORTS].fd = -1;
364 lib_h = LoadCanDriver(can_drv);
366 printf("Unable to load library: %s\n", can_drv);
370 can_h = DLL_CALL(canOpen)(&bus_if);
372 fprintf(stderr,"canOpen : failed\n");
376 hub_ports[MAX_HUB_PORTS].fd = DLL_CALL(canfd)(can_h);
378 FD_SET(hub_ports[MAX_HUB_PORTS].fd, &rfds);
380 if (hub_ports[MAX_HUB_PORTS].fd > max_fd) {
381 max_fd = hub_ports[MAX_HUB_PORTS].fd;
386 for (i = 0; i < MAX_HUB_PORTS; i++) {
388 hub_ports[i].fd = -1;
389 hub_ports[i].name = NULL;
391 rv = asprintf(&hub_ports[i].name, "%s%x", pty_base, i);
394 fprintf(stderr, "asprintf: %s\n", strerror(errno));
399 rv = hub_open(&hub_ports[i]);
418 memcpy(&rfds_copy, &rfds, sizeof(rfds));
420 rv = select(max_fd + 1, &rfds_copy, NULL, NULL, NULL);
424 fprintf(stderr, "select: %s\n", strerror(errno));
429 //as timeout is NULL, must be a rfds set.
430 for (i = 0; i < MAX_HUB_PORTS + 1; i++) {
431 if (hub_ports[i].fd >= 0 &&
432 FD_ISSET(hub_ports[i].fd, &rfds_copy)) {
434 rv = read_write(i, hub_ports, can_h, &rfds, max_fd);
436 if (rv < 0 && i < MAX_HUB_PORTS) {
438 FD_CLR(hub_ports[i].fd, &rfds);
440 hub_close(&hub_ports[i]);
444 if (hub_ports[i].fd < 0 && i < MAX_HUB_PORTS) {
445 rv = hub_open(&hub_ports[i]);
458 for (i = 0; i < MAX_HUB_PORTS; i++) {
459 hub_close(&hub_ports[i]);
462 if (hub_ports[MAX_HUB_PORTS].fd >= 0) {
463 DLL_CALL(canClose)(&bus_if);