diff --git a/doc/protocol.md b/doc/protocol.md index 2f82195..50dc100 100644 --- a/doc/protocol.md +++ b/doc/protocol.md @@ -74,6 +74,22 @@ Send a single CAN frame without cyclic transmission // ID: 1AAAAAAA, Length: 2, Data: 0x01 0xF1 < send 1AAAAAAA 2 1 F1 > +#### Send a single Remote-transfer-request frame #### +This command is used to send a single RTR CAN frame. + + < sendrtr can_id can_dlc > + +Example: +Send a single CAN frame without cyclic transmission + + // ID: 123, DLC 0 + < sendrtr 123 0 > + + // ID: 1AAAAAAA, DLC 2 + < sendrtr 1AAAAAAA 2 > + +Note that DLC may cause collisions on CAN bus. Check CiA application note 802 + ### Commands for reception ### The commands for reception are 'subscribe' , 'unsubscribe' and 'filter'. @@ -169,7 +185,16 @@ Example: Reception of a CAN frame with CAN ID 0x123 , data length 4 and data 0x11, 0x22, 0x33 and 0x44 at time 23.424242> < frame 123 23.424242 11 22 33 44 > + +#### RTR frame transmission #### +CAN RTR messages received in raw mode: + < rtr can_id seconds.useconds can_dlc > +Example: +Reception of a RTR frame with CAN ID 0x123 , data length 4 at time 23.424242 + + < rtr 123 23.424242 4 > + #### Switch to BCM mode #### With '< bcmmode >' it is possible to switch back to BCM mode. diff --git a/doc/raspberrypi.md b/doc/raspberrypi.md new file mode 100644 index 0000000..ef8931d --- /dev/null +++ b/doc/raspberrypi.md @@ -0,0 +1,77 @@ +Running on Raspberry PI +=================== + +For this example used adapter-board: https://www.waveshare.com/rs485-can-hat.htm you can find it on aliexpress too. +After flashing Raspberry image to SD card modify 'config.txt', uncomment this line: + + dtparam=spi=on + +Add this line: + + dtoverlay=mcp2515-can0,oscillator=12000000,interrupt=25,spimaxfrequency=5000000 + +Save file and create empty 'SSH' file if you want to remotely login over ethenet to pi. +For Windows (10+) use: + + ssh raspberrypi.local -l pi + +Password: raspberry + +You can check if CAN driver initialized successfully with: + + dmesg | grep -i '\(can\|spi\)' + +Prepare something needed for build + + sudo apt-get install libconfig-dev + +Now lets clone socketcand to sd card and build it + + cd boot + sudo git clone https://github.com/linux-can/socketcand.git + cd socketcand + sudo ./autogen.sh + sudo ./configure + sudo make + +Now you can install it into system + + sudo make install + +After that you may want to make it run on boot as service, run this command to edit it + + sudo systemctl edit --force --full socketcand.service + +Replace content with this rescription: + + [Unit] + Description=CAN ethernet + After=server.service multi-user.target + + [Service] + ExecStart= + ExecStart=-/usr/local/bin/socketcand -i can0 + Restart=always + TimeoutSec=10 + + [Install] + WantedBy=multi-user.target + +Try to start it with + + sudo systemctl daemon-reload + sudo systemctl start socketcand.service + +And listen on UDP default port 42000 for discovery message. + + + can://192.168.1.221:29536 + +Note that it should say 'can0' and not 'vcan0'. +If everything ok so far, what is quite suprisingly, then run this command to activate service on boot. + + sudo systemctl enable socketcand.service + sudo reboot + +Check for discovery again. +Now you can connect to IP: raspberrypi.local on TCP port 29536 (default) to start working with remote CAN. Check protocol file for commands and its description. \ No newline at end of file diff --git a/socketcandcl.c b/socketcandcl.c index c78e976..0a08172 100644 --- a/socketcandcl.c +++ b/socketcandcl.c @@ -342,6 +342,25 @@ inline void state_connected() } } } + if (!strncmp("< rtr ", buf, 6)) { + //send RTR frame only + sscanf(buf, "< %*s %x %*d.%*d %hhu >", &frame.can_id, &frame.can_dlc); + + frame.can_id |= CAN_RTR_FLAG; + char *s = buf + 6; + for (; ++s;) { + if (*s == ' ') { + break; + } + } + if ((s - buf - 7) > 4) + frame.can_id |= CAN_EFF_FLAG; + + ret = write(raw_socket, &frame, sizeof(struct can_frame)); + if (ret < sizeof(struct can_frame)) { + perror("Writing CAN frame to can socket\n"); + } + } } else { ret = read(server_socket, &buf, 0); if(ret == -1) { @@ -372,21 +391,26 @@ inline void state_connected() } else { if(frame.can_id & CAN_ERR_FLAG) { /* TODO implement */ - } else if(frame.can_id & CAN_RTR_FLAG) { - /* TODO implement */ } else { - int i; - if(frame.can_id & CAN_EFF_FLAG) { - ret = sprintf(buf, "< send %08X %d ", - frame.can_id & CAN_EFF_MASK, frame.can_dlc); + if (frame.can_id & CAN_RTR_FLAG) { + if (frame.can_id & CAN_EFF_FLAG) { + ret = sprintf(buf, "< sendrtr %08X %hhu >", frame.can_id & CAN_EFF_MASK, frame.can_dlc); + } else { + ret = sprintf(buf, "< sendrtr %03X %hhu >", frame.can_id & CAN_SFF_MASK, frame.can_dlc); + } } else { - ret = sprintf(buf, "< send %03X %d ", - frame.can_id & CAN_SFF_MASK, frame.can_dlc); - } - for(i=0; i"); + } - sprintf(buf+ret, " >"); const size_t len = strlen(buf); ret = send(server_socket, buf, len, 0); diff --git a/state_bcm.c b/state_bcm.c index 05a5f7c..89237a8 100644 --- a/state_bcm.c +++ b/state_bcm.c @@ -196,7 +196,24 @@ void state_bcm() { (struct sockaddr*)&caddr, sizeof(caddr)); } /* Add a send job */ - } else if(!strncmp("< add ", buf, 6)) { + } else if (!strncmp("< sendrtr ", buf, 10)) { + //send RTR frame only + items = sscanf(buf, "< %*s %x %hhu >", &msg.msg_head.can_id, &msg.frame.can_dlc); + if ((items < 2) || (msg.frame.can_dlc > CAN_MAX_DLEN)) { + PRINT_ERROR("Syntax error in sendrtr command\n") + return; + } + + msg.msg_head.can_id |= CAN_RTR_FLAG; + + if (element_length(buf, 2) == 8) + msg.msg_head.can_id |= CAN_EFF_FLAG; //extended + + if (!ioctl(sc, SIOCGIFINDEX, &ifr)) { + caddr.can_ifindex = ifr.ifr_ifindex; + sendto(sc, &msg, sizeof(msg), 0, (struct sockaddr*) &caddr, sizeof(caddr)); + } + } else if (!strncmp("< add ", buf, 6)) { items = sscanf(buf, "< %*s %lu %lu %x %hhu " "%hhx %hhx %hhx %hhx %hhx %hhx " "%hhx %hhx >", diff --git a/state_raw.c b/state_raw.c index 2c49975..c31e5a7 100644 --- a/state_raw.c +++ b/state_raw.c @@ -120,8 +120,13 @@ void state_raw() { canid_t class = frame.can_id & CAN_EFF_MASK; ret = sprintf(buf, "< error %03X %ld.%06ld >", class, tv.tv_sec, tv.tv_usec); send(client_socket, buf, strlen(buf), 0); - } else if(frame.can_id & CAN_RTR_FLAG) { - /* TODO implement */ + } else if (frame.can_id & CAN_RTR_FLAG) { + if (frame.can_id & CAN_EFF_FLAG) { + ret = sprintf(buf, "< rtr %08X %ld.%06ld %hhu >", frame.can_id & CAN_EFF_MASK, tv.tv_sec, tv.tv_usec, frame.can_dlc); + } else { + ret = sprintf(buf, "< rtr %03X %ld.%06ld %hhu >", frame.can_id & CAN_SFF_MASK, tv.tv_sec, tv.tv_usec, frame.can_dlc); + } + send(client_socket, buf, strlen(buf), 0); } else { if(frame.can_id & CAN_EFF_FLAG) { ret = sprintf(buf, "< frame %08X %ld.%06ld ", frame.can_id & CAN_EFF_MASK, tv.tv_sec, tv.tv_usec); @@ -187,6 +192,23 @@ void state_raw() { return; } + } else if (!strncmp("< sendrtr ", buf, 10)) { + //send RTR frame only + items = sscanf(buf, "< %*s %x %hhu >", &frame.can_id, &frame.can_dlc); + if ((items < 2) || (frame.can_dlc > CAN_MAX_DLEN)) { + PRINT_ERROR("Syntax error in sendrtr command\n") + return; + } + + frame.can_id |= CAN_RTR_FLAG; + + if (element_length(buf, 2) == 8) + frame.can_id |= CAN_EFF_FLAG; //extended + ret = send(raw_socket, &frame, sizeof(struct can_frame), 0); + if (ret == -1) { + state = STATE_SHUTDOWN; + return; + } } else { PRINT_ERROR("unknown command '%s'\n", buf); strcpy(buf, "< error unknown command >");