/**************************************************************************** * apps/canutils/slcan/slcan.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "slcan.h" /**************************************************************************** * Defines ****************************************************************************/ #define DEFAULT_PRIORITY 100 #define DEFAULT_STACK_SIZE 2048 #ifdef CONFIG_SLCAN_TRACE # define DEBUG 1 #else # define DEBUG 0 #endif #define debug_print(fmt, ...) \ do \ { \ if (DEBUG) \ syslog(LOG_DEBUG, fmt, ##__VA_ARGS__); \ } \ while (0) /**************************************************************************** * private data ****************************************************************************/ #ifdef CONFIG_SLCAN_TRACE static char opening[] = "starting slcan\n"; #else static char opening[] = ""; #endif static void ok_return(int fd) { write(fd, "\r", 1); } static void fail_return(int fd) { write(fd, "\a", 1); /* BELL return for error */ } static int readlinebuffer(int fd, char *buf, int maxlen) { size_t n; int meslen = 0; int noeol = 1; uint8_t ch; while ((meslen < maxlen) && noeol) { n = read(fd, &ch, 1); if (n > 0) { /* valid input */ if (ch == '\r') { noeol = 0; *buf = '\0'; } else { *buf++ = ch; meslen++; } } else { return (meslen); } } return (meslen); } static int caninit(char *candev, int *s, struct sockaddr_can *addr, char *ctrlmsg, struct canfd_frame *frame, struct msghdr *msg, struct iovec *iov) { struct ifreq ifr; debug_print("slcanBus\n"); if ((*s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { syslog(LOG_ERR, "Error opening CAN socket\n"); return -1; } strncpy(ifr.ifr_name, candev, 4); ifr.ifr_name[4] = '\0'; ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name); if (!ifr.ifr_ifindex) { syslog(LOG_ERR, "error finding index %s\n", candev); return -1; } memset(addr, 0, sizeof(struct sockaddr)); addr->can_family = AF_CAN; addr->can_ifindex = ifr.ifr_ifindex; setsockopt(*s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); if (bind(*s, (struct sockaddr *)addr, sizeof(struct sockaddr)) < 0) { syslog(LOG_ERR, "bind error\n"); return -1; } iov->iov_base = frame; msg->msg_name = addr; msg->msg_iov = iov; msg->msg_iovlen = 1; msg->msg_control = ctrlmsg; /* CAN interface ready to be used */ debug_print("CAN socket open\n"); return 0; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: slcan_main ****************************************************************************/ int main(int argc, char *argv[]) { /* UART */ char buf[31]; int mode = 0; size_t n; int canspeed = 1000000; /* default to 1MBps */ int fd; /* UART slcan channel */ /* CAN */ int s, nbytes, i, ret, reccount; struct sockaddr_can addr; struct canfd_frame frame; struct msghdr msg; struct iovec iov; fd_set rdfs; char ctrlmsg[CMSG_SPACE(sizeof(struct timeval) + 3 * sizeof(struct timespec) + sizeof(int))]; char sbuf[40], *sbp; if (argc != 3) { fprintf(stderr, "Usage: slcan \n"); fflush(stderr); return -1; } char *chrdev = argv[2]; char *candev = argv[1]; debug_print("Starting slcan on NuttX\n"); fd = open(chrdev, O_RDWR | O_BINARY); if (fd < 0) { syslog(LOG_ERR, "Failed to open serial channel %s\n", chrdev); return -1; } else { /* Create CAN socket */ if (caninit(candev, &s, &addr, &ctrlmsg[0], &frame, &msg, &iov) < 0) { syslog(LOG_ERR, "Failed to open CAN socket %s\n", candev); close(fd); return -1; } /* serial interface active */ debug_print("Serial interface open %s\n", chrdev); write(fd, opening, (sizeof(opening) - 1)); while (mode < 100) { /* Setup ooll */ FD_ZERO(&rdfs); FD_SET(s, &rdfs); /* CAN Socket */ FD_SET(fd, &rdfs); /* UART */ if ((ret = select(s + 1, &rdfs, NULL, NULL, NULL)) <= 0) { continue; } if (FD_ISSET(s, &rdfs)) { /* CAN received new message in socketCAN input */ iov.iov_len = sizeof(frame); msg.msg_namelen = sizeof(addr); msg.msg_controllen = sizeof(ctrlmsg); msg.msg_flags = 0; nbytes = recvmsg(s, &msg, 0); if (nbytes == CAN_MTU) { reccount++; debug_print("R%d, Id:0x%lX\n", reccount, frame.can_id); if (frame.can_id & CAN_EFF_FLAG) { /* 29 bit address */ frame.can_id = frame.can_id & ~CAN_EFF_FLAG; sprintf(sbuf, "T%08lX%d", frame.can_id, frame.len); sbp = &sbuf[10]; } else { /* 11 bit address */ sprintf(sbuf, "t%03lX%d", frame.can_id, frame.len); sbp = &sbuf[5]; } for (i = 0; i < frame.len; i++) { sprintf(sbp, "%02X", frame.data[i]); sbp += 2; } *sbp++ = '\r'; *sbp = '\0'; write(fd, sbuf, strlen(sbuf)); } } if (FD_ISSET(fd, &rdfs)) { /* UART receive */ n = readlinebuffer(fd, buf, 30); switch (mode) { case 0: /* CAN channel not open */ if (n > 0) { if (buf[0] == 'F') { /* return clear flags */ write(fd, "F00\r", 4); } else if (buf[0] == 'O') { /* open CAN interface */ mode = 1; debug_print("Open interface\n"); ok_return(fd); } else if (buf[0] == 'S') { /* set CAN interface speed */ switch (buf[1]) { case '0': canspeed = 10000; break; case '1': canspeed = 20000; break; case '2': canspeed = 50000; break; case '3': canspeed = 100000; break; case '4': canspeed = 125000; break; case '5': canspeed = 250000; break; case '6': canspeed = 500000; break; case '7': canspeed = 800000; break; case '8': /* set speed to 1Mbps */ canspeed = 1000000; break; default: break; } struct ifreq ifr; /* set the device name */ strncpy(ifr.ifr_name, argv[1], IFNAMSIZ - 1); ifr.ifr_name[IFNAMSIZ - 1] = '\0'; ifr.ifr_ifru.ifru_can_data.arbi_bitrate = canspeed / 1000; /* Convert bit/s to kbit/s */ ifr.ifr_ifru.ifru_can_data.arbi_samplep = 80; if (ioctl(s, SIOCSCANBITRATE, &ifr) < 0) { syslog(LOG_ERR, "set speed %d failed\n", canspeed); fail_return(fd); } else { debug_print("set speed %d\n", canspeed); ok_return(fd); } } else { /* whatever */ ok_return(fd); } } break; case 1: /* CAN task running open interface */ if (n > 0) { if (buf[0] == 'C') { /* close interface */ mode = 0; debug_print("Close interface\n"); ok_return(fd); } else if (buf[0] == 'T') { /* Transmit an extended 29 bit CAN frame */ char tbuf[9]; int idval, val; /* get 29bit CAN ID */ strncpy(tbuf, &buf[1], 8); tbuf[8] = '\0'; sscanf(tbuf, "%x", &idval); frame.len = buf[9] - '0'; /* get byte count */ /* get canmessage */ for (i = 0; i < frame.len; i++) { tbuf[0] = buf[10 + (2 * i)]; tbuf[1] = buf[11 + (2 * i)]; tbuf[2] = '\0'; sscanf(tbuf, "%x", &val); frame.data[i] = val & 0xff; } debug_print("Transmitt: 0x%X ", idval); for (i = 0; i < frame.len; i++) { debug_print("0x%02X ", frame.data[i]); } debug_print("\n"); frame.can_id = idval | CAN_EFF_FLAG; /* 29 bit */ if (write(s, &frame, CAN_MTU) != CAN_MTU) { syslog(LOG_ERR, "transmitt error\n"); /* TODO update error flags */ } ok_return(fd); } else if (buf[0] == 't') { /* Transmit an 11 bit CAN frame */ char tbuf[9]; int idval, val; /* get 11bit CAN ID */ strncpy(tbuf, &buf[1], 3); tbuf[3] = '\0'; sscanf(tbuf, "%x", &idval); frame.len = buf[4] - '0'; /* get byte count */ /* get canmessage */ for (i = 0; i < frame.len; i++) { tbuf[0] = buf[5 + (2 * i)]; tbuf[1] = buf[6 + (2 * i)]; tbuf[2] = '\0'; sscanf(tbuf, "%x", &val); frame.data[i] = val & 0xff; } debug_print("Transmitt: 0x%X ", idval); for (i = 0; i < frame.len; i++) { debug_print("0x%02X ", frame.data[i]); } debug_print("\n"); frame.can_id = idval; /* 11 bit address command */ if (write(s, &frame, CAN_MTU) != CAN_MTU) { syslog(LOG_ERR, "transmitt error\n"); /* TODO update error flags */ } ok_return(fd); } else { /* whatever */ ok_return(fd); } } break; default: /* should not happen */ mode = 100; break; } } } close(fd); close(s); } return 0; }