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 >");