Hi,
I while a ago I was looking for a way to use Socketcan with Python.
The main problem is that Python's socketmodule lacks PF_CAN support.
After my initial posting about Python and Socketcan I got several
requests from others that would like to use Socketcan under Python.
So here comes a patch against the Python 2.6.5 sources and a little
sample script that demonstrates sending/receiving and some sockopt settings.
To build Python with this patch follow these steps:
1) Get and patch python 2.6.5 sources.
2) Call autoconf and autoheader
3) configure && make && make install
Have fun.
Matthias
socketcan_exmaple.py:
import struct
import socket
import string
def dump(s):
return ' '.join(["%02X" % ord(x) for x in s])
# return tuple (id, dlc, data)
def unpack_can_frame(can_frame):
# attention: 'data' is 8-byte-aligned
id, dlca, data = struct.unpack("I4s8s", can_frame)
dlc = ord(dlca[0])
return id, dlc, data[:dlc]
# pretty print can_frame struct
def dump_can_frame(can_frame):
id, dlc, data = unpack_can_frame(can_frame)
print "id:%08x, dlc:%d, data:%s" % (id, dlc, dump(data))
# pretty print can_frame struct in the socketcan way
def dump_can_frame_sc(can_frame):
id, dlc, data = unpack_can_frame(can_frame)
s_data = ''.join(["%02X" % ord(x) for x in data])
if (id & socket.CAN_RTR_FLAG):
s_data = "R"
id = id & ~socket.CAN_RTR_FLAG
if (id & socket.CAN_EFF_FLAG):
id = id & ~socket.CAN_EFF_FLAG
print "%08x#%s" % (id, s_data)
else:
print "%03x#%s" % (id, s_data)
# build packed can_frame struct from id, dlc and data
def build_can_frame(id, dlc, data):
fill = "\0\0\0\0\0\0\0\0"
dlca = chr(dlc) + "\0\0\0"
x = struct.pack("i4s%ds%ds" % (dlc, 8 - dlc),
id, dlca, data[:dlc], fill[:8-dlc])
return x
# build packed can_frame struct from socketcan text representation
def build_can_frame_sc(text):
s_id, s_data = string.split(text, '#')
id = int(s_id, 16)
if (len(s_data) == 1) and (s_data[0] == "R"):
id |= socket.CAN_RTR_FLAG;
if len(s_id) == 8:
id |= socket.CAN_EFF_FLAG;
dlc = len(s_data) >> 1
data = ''.join(["%c" % int(s_data[x*2:(x+1)*2],16) for x in range(dlc)])
return build_can_frame(id, dlc, data)
if __name__=='__main__':
# create CAN socket
s = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
# setup id filter
id = 0
mask = 0
s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER,
struct.pack("II", id, mask))
# enable/disable loopback
loopback = 0
s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_LOOPBACK,
struct.pack("I", loopback))
# bind to interface "canX" or "any")
# tuple is (interface, reserved(can_addr))
s.bind(("can0",))
while 1:
cf, addr = s.recvfrom(16)
print addr
dump_can_frame(cf)
dump_can_frame_sc(cf)
# send echo
try:
s.send(cf)
except socket.error:
print "Error sending CAN frame"
# test 1
try:
cf = build_can_frame(0, 8, "\x11\x22\x33\x44\x55\x66\x77\x88")
dump_can_frame(cf)
dump_can_frame_sc(cf)
s.send(cf)
except socket.error:
print "Error sending CAN frame"
# test 2
try:
cf = build_can_frame_sc("12345678#11223344556677")
dump_can_frame(cf)
dump_can_frame_sc(cf)
s.send(cf)
except socket.error:
print "Error sending CAN frame"
# test 2
try:
cf = build_can_frame_sc("123#12345678")
dump_can_frame(cf)
dump_can_frame_sc(cf)
s.send(cf)
except socket.error:
print "Error sending CAN frame"
diff -Nwru Python-2.6.5-orig/configure.in Python-2.6.5-socketcan/configure.in
--- Python-2.6.5-orig/configure.in 2010-03-09 22:47:28.000000000 +0100
+++ Python-2.6.5-socketcan/configure.in 2010-07-28 14:20:20.000000000 +0200
@@ -1341,6 +1341,13 @@
#endif
])
+# On Linux, can.h and can/raw.h require sys/socket.h
+AC_CHECK_HEADERS(linux/can.h linux/can/raw.h,,,[
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+])
+
# checks for typedefs
was_it_defined=no
AC_MSG_CHECKING(for clock_t in time.h)
diff -Nwru Python-2.6.5-orig/Modules/socketmodule.c
Python-2.6.5-socketcan/Modules/socketmodule.c
--- Python-2.6.5-orig/Modules/socketmodule.c 2010-02-04 21:26:34.000000000
+0100
+++ Python-2.6.5-socketcan/Modules/socketmodule.c 2010-07-28
14:20:30.000000000 +0200
@@ -1151,6 +1151,25 @@
}
#endif
+#ifdef HAVE_LINUX_CAN_H
+ case AF_CAN:
+ {
+ struct sockaddr_can *a = (struct sockaddr_can *)addr;
+ char *ifname = "";
+ struct ifreq ifr;
+ /* need to look up interface name give index */
+ if (a->can_ifindex) {
+ ifr.ifr_ifindex = a->can_ifindex;
+ if (ioctl(sockfd, SIOCGIFNAME, &ifr) == 0)
+ ifname = ifr.ifr_name;
+ }
+
+ return Py_BuildValue("sh",
+ ifname,
+ a->can_family);
+ }
+#endif
+
/* More cases here... */
default:
@@ -1486,6 +1505,43 @@
}
#endif
+#ifdef HAVE_LINUX_CAN_H
+ case AF_CAN:
+ switch (s->sock_proto) {
+ case CAN_RAW:
+ {
+ struct sockaddr_can* addr;
+ char *interfaceName;
+ struct ifreq ifr;
+ addr = (struct sockaddr_can *)addr_ret;
+
+ if (!PyArg_ParseTuple(args, "s", &interfaceName))
+ return 0;
+
+ if (!strcmp(interfaceName, "any")) {
+ ifr.ifr_ifindex = 0;
+ } else {
+ strncpy(ifr.ifr_name, interfaceName,
+ sizeof(ifr.ifr_name));
+ ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0';
+ if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) {
+ s->errorhandler();
+ return 0;
+ }
+ }
+
+ addr->can_family = AF_CAN;
+ addr->can_ifindex = ifr.ifr_ifindex;
+
+ *len_ret = sizeof(*addr);
+ return 1;
+ }
+ default:
+ PyErr_SetString(socket_error, "getsockaddrarg:
unsupported CAN protocol");
+ return 0;
+ }
+#endif
+
/* More cases here... */
default:
@@ -1579,6 +1635,14 @@
}
#endif
+#ifdef HAVE_LINUX_CAN_H
+ case AF_CAN:
+ {
+ *len_ret = sizeof (struct sockaddr_can);
+ return 1;
+ }
+#endif
+
/* More cases here... */
default:
@@ -4584,6 +4648,14 @@
PyModule_AddStringConstant(m, "BDADDR_ANY", "00:00:00:00:00:00");
PyModule_AddStringConstant(m, "BDADDR_LOCAL", "00:00:00:FF:FF:FF");
#endif
+#ifdef AF_CAN
+ /* Controller Area Network */
+ PyModule_AddIntConstant(m, "AF_CAN", AF_CAN);
+#endif
+#ifdef PF_CAN
+ /* Controller Area Network */
+ PyModule_AddIntConstant(m, "PF_CAN", PF_CAN);
+#endif
#ifdef HAVE_NETPACKET_PACKET_H
PyModule_AddIntConstant(m, "AF_PACKET", AF_PACKET);
@@ -4785,6 +4857,29 @@
#else
PyModule_AddIntConstant(m, "SOL_UDP", 17);
#endif
+#ifdef SOL_CAN_BASE
+ PyModule_AddIntConstant(m, "SOL_CAN_BASE", SOL_CAN_BASE);
+#endif
+#ifdef SOL_CAN_RAW
+ PyModule_AddIntConstant(m, "SOL_CAN_RAW", SOL_CAN_RAW);
+ PyModule_AddIntConstant(m, "CAN_RAW", CAN_RAW);
+#endif
+#ifdef HAVE_LINUX_CAN_H
+ PyModule_AddIntConstant(m, "CAN_EFF_FLAG", CAN_EFF_FLAG);
+ PyModule_AddIntConstant(m, "CAN_RTR_FLAG", CAN_RTR_FLAG);
+ PyModule_AddIntConstant(m, "CAN_ERR_FLAG", CAN_ERR_FLAG);
+
+ PyModule_AddIntConstant(m, "CAN_SFF_MASK", CAN_SFF_MASK);
+ PyModule_AddIntConstant(m, "CAN_EFF_MASK", CAN_EFF_MASK);
+ PyModule_AddIntConstant(m, "CAN_ERR_MASK", CAN_ERR_MASK);
+#endif
+#ifdef HAVE_LINUX_CAN_RAW_H
+ PyModule_AddIntConstant(m, "CAN_RAW_FILTER", CAN_RAW_FILTER);
+ PyModule_AddIntConstant(m, "CAN_RAW_ERR_FILTER", CAN_RAW_ERR_FILTER);
+ PyModule_AddIntConstant(m, "CAN_RAW_LOOPBACK", CAN_RAW_LOOPBACK);
+ PyModule_AddIntConstant(m, "CAN_RAW_RECV_OWN_MSGS",
CAN_RAW_RECV_OWN_MSGS);
+#endif
+
#ifdef IPPROTO_IP
PyModule_AddIntConstant(m, "IPPROTO_IP", IPPROTO_IP);
#else
diff -Nwru Python-2.6.5-orig/Modules/socketmodule.h
Python-2.6.5-socketcan/Modules/socketmodule.h
--- Python-2.6.5-orig/Modules/socketmodule.h 2008-06-14 10:36:07.000000000
+0200
+++ Python-2.6.5-socketcan/Modules/socketmodule.h 2010-07-28
14:20:30.000000000 +0200
@@ -69,6 +69,20 @@
# include <linux/tipc.h>
#endif
+#ifdef HAVE_LINUX_CAN_H
+#include <linux/can.h>
+#ifndef PF_CAN
+# define PF_CAN 29
+#endif
+#ifndef AF_CAN
+# define AF_CAN PF_CAN
+#endif
+#endif
+
+#ifdef HAVE_LINUX_CAN_RAW_H
+#include <linux/can/raw.h>
+#endif
+
#ifndef Py__SOCKET_H
#define Py__SOCKET_H
#ifdef __cplusplus
@@ -114,6 +128,9 @@
#ifdef HAVE_NETPACKET_PACKET_H
struct sockaddr_ll ll;
#endif
+#ifdef HAVE_LINUX_CAN_H
+ struct sockaddr_can* can;
+#endif
} sock_addr_t;
/* The object holding a socket. It holds some extra information,
_______________________________________________
Socketcan-users mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-users