Skip to content

Commit

Permalink
new python bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
rscada committed Jun 25, 2012
1 parent 1e5af4b commit 4bd9ff2
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 25 deletions.
22 changes: 2 additions & 20 deletions bin/rs-canopen-dump.c
Expand Up @@ -36,8 +36,6 @@
int
main(int argc, char **argv)
{
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame can_frame;
canopen_frame_t canopen_frame;
int sock, bytes_read;
Expand All @@ -49,30 +47,14 @@ main(int argc, char **argv)
}

/* Create the socket */
if ((sock = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
if ((sock = can_socket_open(argv[1])) < 0)
{
fprintf(stderr, "Error: Failed to create socket.\n");
return -1;
}

/* Locate the interface you wish to use */
strcpy(ifr.ifr_name, argv[1]);
ioctl(sock, SIOCGIFINDEX, &ifr); /* ifr.ifr_ifindex gets filled
* with that device's index */
// XXX add check
printf("sizeof can_frame = %d\n", sizeof(struct can_frame));

/* Select that CAN interface, and bind the socket to it. */
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(sock, (struct sockaddr*)&addr, sizeof(addr)); // XXX Add check

/* Send a message to the CAN bus * /
frame.can_id = 0x123;
strcpy(frame.data, "foo");
frame.can_dlc = strlen(frame.data);
int bytes_sent = write(sock, &frame, sizeof(frame));
*/

while (1)
{

Expand Down
4 changes: 2 additions & 2 deletions canopen/Makefile.am
Expand Up @@ -13,7 +13,7 @@ VERSION = @VERSION@

AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)

pkginclude_HEADERS = canopen.h canopen-com.h
pkginclude_HEADERS = canopen.h canopen-com.h can-if.h
lib_LTLIBRARIES = libcanopen.la
libcanopen_la_SOURCES = canopen.c canopen-com.c
libcanopen_la_SOURCES = canopen.c canopen-com.c can-if.c

7 changes: 4 additions & 3 deletions canopen/Makefile.in
Expand Up @@ -89,7 +89,7 @@ am__uninstall_files_from_dir = { \
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgincludedir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
libcanopen_la_LIBADD =
am_libcanopen_la_OBJECTS = canopen.lo canopen-com.lo
am_libcanopen_la_OBJECTS = canopen.lo canopen-com.lo can-if.lo
libcanopen_la_OBJECTS = $(am_libcanopen_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
Expand Down Expand Up @@ -224,9 +224,9 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)
pkginclude_HEADERS = canopen.h canopen-com.h
pkginclude_HEADERS = canopen.h canopen-com.h can-if.h
lib_LTLIBRARIES = libcanopen.la
libcanopen_la_SOURCES = canopen.c canopen-com.c
libcanopen_la_SOURCES = canopen.c canopen-com.c can-if.c
all: all-am

.SUFFIXES:
Expand Down Expand Up @@ -301,6 +301,7 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c

@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/can-if.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/canopen-com.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/canopen.Plo@am__quote@

Expand Down
70 changes: 70 additions & 0 deletions canopen/can-if.c
@@ -0,0 +1,70 @@
//------------------------------------------------------------------------------
// Copyright (C) 2012, Robert Johansson <rob@raditex.nu>, Raditex Control AB
// All rights reserved.
//
// This file is part of the rSCADA system.
//
// rSCADA
// http://www.rSCADA.se
// info@rscada.se
//
//------------------------------------------------------------------------------

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>

#include <linux/can.h>
#include <linux/can/raw.h>

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdint.h>
#include <stdlib.h>

#include <canopen/can-if.h>

int
can_socket_open(char *interface)
{
struct sockaddr_can addr;
struct ifreq ifr;
int sock, bytes_read;

/* Create the socket */
if ((sock = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
{
fprintf(stderr, "Error: Failed to create socket.\n");
return -1;
}

/* Locate the interface you wish to use */
strcpy(ifr.ifr_name, interface);
ioctl(sock, SIOCGIFINDEX, &ifr); /* ifr.ifr_ifindex gets filled
* with that device's index */
// XXX add check

/* Select that CAN interface, and bind the socket to it. */
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(sock, (struct sockaddr*)&addr, sizeof(addr)); // XXX Add check

/* Send a message to the CAN bus * /
frame.can_id = 0x123;
strcpy(frame.data, "foo");
frame.can_dlc = strlen(frame.data);
int bytes_sent = write(sock, &frame, sizeof(frame));
*/

return sock;
}


int
can_socket_close(int socket)
{
return close(socket);
}
35 changes: 35 additions & 0 deletions canopen/can-if.h
@@ -0,0 +1,35 @@
//------------------------------------------------------------------------------
// Copyright (C) 2012, Robert Johansson <rob@raditex.nu>, Raditex Control AB
// All rights reserved.
//
// This file is part of the rSCADA system.
//
// rSCADA
// http://www.rSCADA.se
// info@rscada.se
//
//------------------------------------------------------------------------------

//
// CANopen communication routines and data types.
//

#ifndef _CAN_IF_H_
#define _CAN_IF_H_

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>

#include <linux/can.h>
#include <linux/can/raw.h>

#include <string.h>
#include <stdint.h>

int can_socket_open();
int can_socket_close(int socket);

#endif /* _CAN_IF_H */
12 changes: 12 additions & 0 deletions libcanopen.pc
@@ -0,0 +1,12 @@
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: libcanopen
Description: Open source CANopen library for Linux SocketCAN.
Requires:
Version: 0.1.0
URL: http://www.rscada.se/libcanopen/
Libs: -L${libdir} -lcanopen
Cflags: -I${includedir}
40 changes: 40 additions & 0 deletions python/canopen-dump.py
@@ -0,0 +1,40 @@
#!/usr/bin/python
# ------------------------------------------------------------------------------
# Copyright (C) 2012, Robert Johansson <rob@raditex.nu>, Raditex Control AB
# All rights reserved.
#
# This file is part of the rSCADA system.
#
# rSCADA
# http://www.rSCADA.se
# info@rscada.se
# ------------------------------------------------------------------------------

"""
Read CAN frame, parse into CANopen frame, and dump to STDOUT.
"""

from pyCANopen import *

canopen = CANopen()

while True:
canopen_frame = canopen.read_frame()
if canopen_frame:
print canopen_frame
else:
print("CANopen Frame parse error")

#while True:
# can_frame = canopen.read_can_frame()
# if can_frame:
# print can_frame
# else:
# print("CAN Frame parse error")
# continue
# canopen_frame = canopen.parse_can_frame(can_frame)
# if canopen_frame:
# print canopen_frame
# else:
# print("CANopen Frame parse error")

31 changes: 31 additions & 0 deletions python/canopen-node-info.py
@@ -0,0 +1,31 @@
#!/usr/bin/python
# ------------------------------------------------------------------------------
# Copyright (C) 2012, Robert Johansson <rob@raditex.nu>, Raditex Control AB
# All rights reserved.
#
# This file is part of the rSCADA system.
#
# rSCADA
# http://www.rSCADA.se
# info@rscada.se
# ------------------------------------------------------------------------------

"""
Read node info from a CANopen node
"""

from pyCANopen import *

canopen = CANopen()

node = 5

value = canopen.SDOUploadExp(node, 0x1018, 0x01)
print("Vendor ID = 0x%.8X\n" % value)

value = canopen.SDOUploadExp(node, 0x1018, 0x02)
print("Product ID = 0x%.8X\n" % value)

value = canopen.SDOUploadExp(node, 0x1018, 0x03)
print("Software Ver = 0x%.8X\n" % value)

120 changes: 120 additions & 0 deletions python/pyCANopen.py
@@ -0,0 +1,120 @@
#!/usr/bin/python
# ------------------------------------------------------------------------------
# Copyright (C) 2012, Robert Johansson <rob@raditex.nu>, Raditex Control AB
# All rights reserved.
#
# This file is part of the rSCADA system.
#
# rSCADA
# http://www.rSCADA.se
# info@rscada.se
# ------------------------------------------------------------------------------

"""
Python bindings for rSCADA libCANopen.
"""

from ctypes import *

libcanopen = cdll.LoadLibrary('libcanopen.so')
libc = cdll.LoadLibrary('libc.so.6')

class CANFrame(Structure):
_fields_ = [("can_id", c_uint32),
("can_dlc", c_uint8),
("align", c_uint8 * 3), # hardcoded alignment to match C struct
("data", c_uint8 * 8)]

def __str__(self):
data_str = " ".join(["%.2x" % (x,) for x in self.data])
return "CAN Frame: ID=%.2x DLC=%.2x DATA=[%s]" % (self.can_id, self.can_dlc, data_str)

class CANopenFrame(Structure):
_fields_ = [("rtr", c_uint8),
("function_code", c_uint8),
("type", c_uint8),
("id", c_uint32),
("data", c_uint8 * 8), # should be a union...
("data_len", c_uint8)]

def __str__(self):
data_str = " ".join(["%.2x" % (x,) for x in self.data])
return "CANopen Frame: RTR=%d FC=0x%.2x ID=0x%.2x [len=%d] %s" % (self.rtr, self.function_code, self.id, self.data_len, data_str)

class CANopen:

def __init__(self, interface="can0"):
"""
Constructor for CANopen class. Optionally takes an interface
name for which to bind a socket to. Defaults to interface "can0"
"""
self.sock = libcanopen.can_socket_open(interface)

def open(self, interface):
"""
Open a new socket. If open socket already exist, close it first.
"""
if self.sock:
self.close()
self.sock = libcanopen.can_socket_open(interface)

def close(self):
"""
Close the socket associated with this class instance.
"""
if self.sock:
libcanopen.can_socket_close(self.sock)
self.sock = None

def read_can_frame(self):
"""
Low-level function: Read a CAN frame from socket.
"""
if self.sock:
can_frame = CANFrame()
if libc.read(self.sock, byref(can_frame), c_int(16)) != 16:
raise "CAN frame read error"
return can_frame
else:
raise "CAN fram read error: socket not connected"

def parse_can_frame(self, can_frame):
"""
Low level function: Parse a given CAN frame into CANopen frame
"""
canopen_frame = CANopenFrame()
if libcanopen.canopen_frame_parse(byref(canopen_frame), byref(can_frame)) == 0:
return canopen_frame
else:
raise "CANopen Frame parse error"

def read_frame(self):
"""
Read a CANopen frame from socket. First read a CAN frame, then parse
into a CANopen frame and return it.
"""
can_frame = self.read_can_frame()
if not can_frame:
raise "CAN Frame read error"

canopen_frame = self.parse_can_frame(can_frame)
if not canopen_frame:
raise "CANopen Frame parse error"

return canopen_frame


#---------------------------------------------------------------------------
# SDO related functions
#

def SDOUploadExp(self, node, index, subindex):
"""
Expediated SDO upload
"""
res = c_uint32()
libcanopen.canopen_sdo_upload_exp(self.sock, c_uint8(node), c_uint16(index), c_uint8(subindex), byref(res))
return res.value



0 comments on commit 4bd9ff2

Please sign in to comment.