Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
316 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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") | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
|
||
|
||
|