8000 Fixing #196 by felixdivo · Pull Request #246 · hardbyte/python-can · GitHub
[go: up one dir, main page]

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

Filter b 8000 y extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion can/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
'virtual': ('can.interfaces.virtual', 'VirtualBus'),
'neovi': ('can.interfaces.ics_neovi', 'NeoViBus'),
'vector': ('can.interfaces.vector', 'VectorBus'),
'slcan': ('can.interfaces.slcan', 'slcanBus')
'slcan': ('can.interfaces.slcan', 'slcanBus'),
'canal': ('can.interfaces.canal', 'CanalBus'),
}


Expand Down
5 changes: 3 additions & 2 deletions can/interfaces/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# -*- coding: utf-8 -*-

"""
Interfaces contain low level implementations that interact with CAN hardware.
"""

from pkg_resources import iter_entry_points

VALID_INTERFACES = set(['kvaser', 'serial', 'pcan', 'socketcan_native',
'socketcan_ctypes', 'socketcan', 'usb2can', 'ixxat',
'nican', 'iscan', 'vector', 'virtual', 'neovi',
'slcan'])

'slcan', 'canal'])

VALID_INTERFACES.update(set([
interface.name for interface in iter_entry_points('python_can.interface')
Expand Down
2 changes: 2 additions & 0 deletions can/interfaces/canal/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from can.interfaces.canal.canalInterface import CanalBus
from can.interfaces.canal.canal_wrapper import CanalWrapper
196 changes: 196 additions & 0 deletions can/interfaces/canal/canalInterface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# this interface is for windows only, otherwise use socketCAN

import logging

from can import BusABC, Message
from can.interfaces.canal.canal_wrapper import *

bootTimeEpoch = 0
try:
import uptime
import datetime

bootTimeEpoch = (uptime.boottime() - datetime.datetime.utcfromtimestamp(0)).total_seconds()
except:
bootTimeEpoch = 0

# Set up logging
log = logging.getLogger('can.canal')


def format_connection_string(deviceID, baudrate='500'):
"""setup the string for the device

config = deviceID + '; ' + baudrate
"""
return "%s; %s" % (deviceID, baudrate)


def message_convert_tx(msg):
messagetx = CanalMsg()

length = len(msg.data)
messagetx.sizeData = length

messagetx.id = msg.arbitration_id

for i in range(length):
messagetx.data[i] = msg.data[i]

messagetx.flags = 0x80000000

if msg.is_error_frame:
messagetx.flags |= IS_ERROR_FRAME

if msg.is_remote_frame:
messagetx.flags |= IS_REMOTE_FRAME

if msg.id_type:
messagetx.flags |= IS_ID_TYPE

return messagetx


def message_convert_rx(messagerx):
"""convert the message from the CANAL type to pythoncan type"""
ID_TYPE = bool(messagerx.flags & IS_ID_TYPE)
REMOTE_FRAME = bool(messagerx.flags & IS_REMOTE_FRAME)
ERROR_FRAME = bool(messagerx.flags & IS_ERROR_FRAME)

msgrx = Message(timestamp=messagerx.timestamp / 1000.0,
is_remote_frame=REMOTE_FRAME,
extended_id=ID_TYPE,
is_error_frame=ERROR_FRAME,
arbitration_id=messagerx.id,
dlc=messagerx.si 8000 zeData,
data=messagerx.data[:messagerx.sizeData]
)

return msgrx


class CanalBus(BusABC):
"""Interface to a CANAL Bus.

Note the interface doesn't implement set_filters, or flush_tx_buffer methods.

:param str channel:
The device's serial number. If not provided, Windows Management Instrumentation
will be used to identify the first such device. The *kwarg* `serial` may also be
used.

:param str dll:
dll with CANAL API to load

:param int bitrate:
Bitrate of channel in bit/s. Values will be limited to a maximum of 1000 Kb/s.
Default is 500 Kbs

:param str serial (optional)
device serial to use for the CANAL open call

:param str serialMatcher (optional)
search string for automatic detection of the device serial

:param int flags:
Flags to directly pass to open function of the CANAL abstraction layer.
"""

def __init__(self, channel, *args, **kwargs):

# TODO force specifying dll
if 'dll' in kwargs:
dll = kwargs["dll"]
else:
raise Exception("please specify a CANAL dll to load, e.g. 'usb2can.dll'")

self.can = CanalWrapper(dll)

# set flags on the connection
if 'flags' in kwargs:
enable_flags = kwargs["flags"]

else:
enable_flags = 0x00000008

# code to get the serial number of the device
if 'serial' in kwargs:
deviceID = kwargs["serial"]
elif channel is not None:
deviceID = channel
else:
# autodetect device
from can.interfaces.canal.serial_selector import serial
if 'serialMatcher' in kwargs:
deviceID = serial(kwargs["serialMatcher"])
else:
deviceID = serial()

if not deviceID:
raise can.CanError("Device ID could not be autodetected")

self.channel_info = "CANAL device " + deviceID

# set baudrate in kb/s from bitrate
# (eg:500000 bitrate must be 500)
if 'bitrate' in kwargs:
br = kwargs["bitrate"]

# max rate is 1000 kbps
baudrate = max(1000, int(br/1000))
# set default value
else:
baudrate = 500

connector = format_connection_string(deviceID, baudrate)

self.handle = self.can.open(connector, enable_flags)
# print "ostemad"


def send(self, msg, timeout=None):
tx = message_convert_tx(msg)

if timeout:
status = self.can.blocking_send(self.handle, byref(tx), int(timeout * 1000))
else:
status = self.can.send(self.handle, byref(tx))

if status != 0:
raise can.CanError("could not send message: status == {}".format(status))

def recv(self, timeout=None):

messagerx = CanalMsg()

if timeout == 0:
status = self.can.receive(self.handle, byref(messagerx))

else:
time = 0 if timeout is None else int(timeout * 1000)
status = self.can.blocking_receive(self.handle, byref(messagerx), time)

if status == 0:
# success
return message_convert_rx(messagerx)

elif status == 19:
# CANAL_ERROR_RCV_EMPTY
log.warn("recv: status: CANAL_ERROR_RCV_EMPTY")
return None

elif status == 32:
# CANAL_ERROR_TIMEOUT
log.warn("recv: status: CANAL_ERROR_TIMEOUT")
return None

else:
# another error
raise can.CanError("could not receive message: status == {}".format(status))

def shutdown(self):
"""Shut down the device safely"""
status = self.can.close(self.handle)

if status != 0:
raise can.CanError("could not shut down bus: status == {}".format(status))
151 changes: 151 additions & 0 deletions can/interfaces/canal/canal_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# This wrapper is for windows or direct access via CANAL API. Socket CAN is recommended under Unix/Linux systems
import can
from ctypes import *
from struct import *
import logging

log = logging.getLogger('can.canal')

# type definitions
flags = c_ulong
pConfigureStr = c_char_p
handle = c_long
timeout = c_ulong
filter = c_ulong

# flags mappings
IS_ERROR_FRAME = 4
IS_REMOTE_FRAME = 2
IS_ID_TYPE = 1


class CanalStatistics(Structure):
_fields_ = [('ReceiveFrams', c_ulong),
('TransmistFrams', c_ulong),
('ReceiveData', c_ulong),
('TransmitData', c_ulong),
('Overruns', c_ulong),
('BusWarnings', c_ulong),
('BusOff', c_ulong)]


stat = CanalStatistics


class CanalStatus(Structure):
_fields_ = [('channel_status', c_ulong),
('lasterrorcode', c_ulong),
('lasterrorsubcode', c_ulong),
('lasterrorstr', c_byte * 80)]


# data type for the CAN Message
class CanalMsg(Structure):
_fields_ = [('flags', c_ulong),
('obid', c_ulong),
('id', c_ulong),
('sizeData', c_ubyte),
('data', c_ubyte * 8),
('timestamp', c_ulong)]


class CanalWrapper:
"""A low level wrapper around the CANAL library.
"""
def __init__(self, dll):
self.__m_dllBasic = windll.LoadLibrary(dll)

if self.__m_dllBasic is None:
log.warning('DLL failed to load')

def open(self, pConfigureStr, flags):
try:
# unicode is not good
pConfigureStr = pConfigureStr.encode('ascii', 'ignore')
res = self.__m_dllBasic.CanalOpen(pConfigureStr, flags)
if res == 0:
raise can.CanError("CanalOpen failed, configure string: " + pConfigureStr)
return res
except:
log.warning('Failed to open')
raise

def close(self, handle):
try:
res = self.__m_dllBasic.CanalClose(handle)
return res
except:
log.warning('Failed to close')
raise

def send(self, handle, msg):
try:
res = self.__m_dllBasic.CanalSend(handle, msg)
return res
except:
log.warning('Sending error')
raise can.CanError("Failed to transmit frame")

def receive(self, handle, msg):
try:
res = self.__m_dllBasic.CanalReceive(handle, msg)
return res
except:
log.warning('Receive error')
raise

def blocking_send(self, handle, msg, timeout):
try:
res = self.__m_dllBasic.CanalBlockingSend(handle, msg, timeout)
return res
except:
log.warning('Blocking send error')
raise

def blocking_receive(self, handle, msg, timeout):
try:
res = self.__m_dllBasic.CanalBlockingReceive(handle, msg, timeout)
return res
except:
log.warning('Blocking Receive Failed')
raise

def get_status(self, handle, CanalStatus):
try:
res = self.__m_dllBasic.CanalGetStatus(handle, CanalStatus)
return res
except:
log.warning('Get status failed')
raise

def get_statistics(self, handle, CanalStatistics):
try:
res = self.__m_dllBasic.CanalGetStatistics(handle, CanalStatistics)
return res
except:
log.warning('Get Statistics failed')
raise

def get_version(self):
try:
res = self.__m_dllBasic.CanalGetVersion()
return res
except:
log.warning('Failed to get version info')
raise

def get_library_version(self):
try:
res = self.__m_dllBasic.CanalGetDllVersion()
return res
except:
log.warning('Failed to get DLL version')
raise

def get_vendor_string(self):
try:
res = self.__m_dllBasic.CanalGetVendorString()
return res
except:
log.warning('Failed to get vendor string')
raise
Loading
0