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

Reply via email to