Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions doc/protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'.

Expand Down Expand Up @@ -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.

Expand Down
77 changes: 77 additions & 0 deletions doc/raspberrypi.md
Original file line number Diff line number Diff line change
@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no sudo for those above needed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for ssh needed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or for sd card access. i dont know, other way it throws errors

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, only use sudo make install all others don't need root permission.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see where the problem is. Don't change to /boot. You can directly start the git clone in your home directory.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't do this in /boot

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why s that? its easy to copypaste files from my windows machine

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under Linux /boot is for booting the system. A mistake there might lead to an unbootable system. This is why normal users don't have write permission there. Your home directory is where you can and should do your things.


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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please name the file [email protected]


Replace content with this rescription:

[Unit]
Description=CAN ethernet
After=server.service multi-user.target
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After=multi-user.target and WantedBy=multi-user.target looks wrong

What about:

After=network.target
After=sys-subsystem-net-devices-%i.device
BindsTo=sys-subsystem-net-devices-%i.device


[Service]
ExecStart=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need the empty line? What about adding the .service file to the git repo?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have no idea! its a linux magic

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need that empty line.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in this case this thing gonna yell at me that im passing arguments in excutable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it say exactly?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Service has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you get this error message you might have a drop-in file in /etc/systemd/system/socketcand.service.d/, which has an ExecStart= aswell. You only want /etc/systemd/system/socketcand.service (or /etc/systemd/system/[email protected], see other comment).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what makes my option more noob proof.
how normal user should know all this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proper instructions are a good starting point to learn more, if someone is interested.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can update it in a commit

ExecStart=-/usr/local/bin/socketcand -i can0
Copy link
Member

@marckleinebudde marckleinebudde Oct 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use %I instead of can0

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Man i described the way it worked. it took me half day long to make it work. i dont want to try over again

Restart=always
TimeoutSec=10

[Install]
WantedBy=multi-user.target

Try to start it with

sudo systemctl daemon-reload
sudo systemctl start socketcand.service
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sudo systemctl start [email protected]


And listen on UDP default port 42000 for discovery message.

<CANBeacon name="raspberrypi" type="SocketCAN" description="socketcand">
<URL>can://192.168.1.221:29536</URL><Bus name="can0"/></CANBeacon>

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
Copy link
Member

@marckleinebudde marckleinebudde Oct 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sudo systemctl enable [email protected]

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.
48 changes: 36 additions & 12 deletions socketcandcl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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<frame.can_dlc; i++) {
ret += sprintf(buf+ret, "%02x ", frame.data[i]);
int i;
if (frame.can_id & CAN_EFF_FLAG) {
ret = sprintf(buf, "< send %08X %hhu ", frame.can_id & CAN_EFF_MASK, frame.can_dlc);
} else {
ret = sprintf(buf, "< send %03X %hhu ", frame.can_id & CAN_SFF_MASK, frame.can_dlc);
}
for (i = 0; i < frame.can_dlc; i++) {
ret += sprintf(buf + ret, "%02x ", frame.data[i]);
}
sprintf(buf + ret, " >");

}
sprintf(buf+ret, " >");

const size_t len = strlen(buf);
ret = send(server_socket, buf, len, 0);
Expand Down
19 changes: 18 additions & 1 deletion state_bcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 >",
Expand Down
26 changes: 24 additions & 2 deletions state_raw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 >");
Expand Down