06-07-2012 10:50 AM
Hello all,
I have a feeling this questions will be left unanswered, but I will ask anyway.
For a project, I am required to use Python2.7 to receive CAN frames from a CAN bus. All I need to do is monitor all CAN traffic on the bus, I will not need to send any frames. I have searched (and searched and searched) for some sort of solution to this, but have found none. Heres the code I have so far:
#CAN test using Python
from ctypes import *
from array import *
#Load the DLL
CANdll = cdll.LoadLibrary("NICAN.dll")
canName = c_char_p("CAN0")
canNumAttr = c_ulong(8)
# Define Constants
NC_TRUE = c_ulong(1)
NC_TRUE = c_ulong(0)
NC_CAN_MASK_STD_DONTCARE = c_ulong(0x00000000)
NC_CAN_MASK_XTD_DONTCARE = c_ulong(0x00000000)
## Values taken from nican.h
##NC_ATTR_BAUD_RATE = c_ulong(0x80000007)
##NC_ATTR_START_ON_OPEN = c_ulong(0x80000006)
##NC_ATTR_READ_Q_LEN = c_ulong(0x80000013)
##NC_ATTR_WRITE_Q_LEN = c_ulong(0x80000014)
##NC_ATTR_CAN_COMP_STD = c_ulong(0x80010001)
##NC_ATTR_CAN_MASK_STD = c_ulong(0x80010002)
##NC_ATTR_CAN_COMP_XTD = c_ulong(0x80010003)
##NC_ATTR_CAN_MASK_XTD = c_ulong(0x80010004)
# instantiate the array
canAttrIdList = (c_ulong*8)()
# Fill array values
canAttrIdList[0] = c_ulong(0x80000007)
canAttrIdList[1] = c_ulong(0x80000006)
canAttrIdList[2] = c_ulong(0x80000013)
canAttrIdList[3] = c_ulong(0x80000014)
canAttrIdList[4] = c_ulong(0x80010001)
canAttrIdList[5] = c_ulong(0x80010002)
canAttrIdList[6] = c_ulong(0x80010003)
canAttrIdList[7] = c_ulong(0x80010004)
##NC_ATTR_BAUD_RATE = 500000
##NC_ATTR_START_ON_OPEN = NC_TRUE
##NC_ATTR_READ_Q_LEN = 100
##NC_ATTR_WRITE_Q_LEN = 0
##NC_ATTR_CAN_COMP_STD = 0
##NC_ATTR_CAN_MASK_STD = NC_CAN_MASK_STD_DONTCARE
##NC_ATTR_CAN_COMP_XTD = 0
##NC_ATTR_CAN_MASK_XTD = NC_CAN_MASK_XTD_DONTCARE
# instantiate array
canAttrValueList = (c_ulong * 8)()
# Fill array values
canAttrValueList[0] = 500000
canAttrValueList[1] = NC_TRUE
canAttrValueList[2] = 100
canAttrValueList[3] = 0
canAttrValueList[4] = 0
canAttrValueList[5] = NC_CAN_MASK_STD_DONTCARE
canAttrValueList[6] = 0
canAttrValueList[7] = NC_CAN_MASK_XTD_DONTCARE
returnValue = CANdll.ncConfig(canName, canNumAttr, canAttrIdList, canAttrValueList)
##END OF CODE
Which results in this error:
Traceback (most recent call last):
File "C:\Users\Chadwick\Dropbox\Senior Project\CAN\NI-CAN\ITB CAN\test.py", line 63, in <module>
returnValue = CANdll.ncConfig(canName, canNumAttr, canAttrIdList, canAttrValueList)
ValueError: Procedure called with not enough arguments (16 bytes missing) or wrong calling convention
It appears that I am not calling the function properly.
Yes, I understand NI does not support Python. However, any help with this is appreciated.
Thank you
Solved! Go to Solution.
06-08-2012 02:19 PM
Hey medendoc,
Unfortunately, as you've already mentioned, the CAN driver isn't supported by Python. Therefore, even if you've used the proper sequence of commands, it's possible that the code will still not execute as it hasn't been fully tested.
--Ryan S.
06-28-2012 11:37 AM
I understand that NI does not support Python directly as a developement code. However, if anyone has tried this I could use help.
The following code allows me to receive 1 proper CAN frame (correct ID, length, and data) followed by garbage information. Any help is appreciated.
A direct question is: for the "ncReadMult" funciton, what value needs to be sent as "DataSize"? (refering to the NI-CAN Hardware and Software Manual pg 577). As far as I can tell, it needs the "size of the array pointed to by DataPtr (in bytes)." Which should be 176 (Timestamp is 64 bits, ArbID is 32, FrameType is 8, DataLength is 8, and Data is an 8 array of 8 bits.).
from ctypes import *
from array import *
import sys
import struct
import time
#Load the DLL
CANdll = windll.LoadLibrary("NICAN.dll")
## RELEVANT C HEADER INFO
## typedef NCTYPE_INT32 NCTYPE_STATUS;
## typedef NCTYPE_UINT32 NCTYPE_OBJH;
## copied from nican.h
##typedef struct {
## NCTYPE_ABS_TIME Timestamp;
## NCTYPE_CAN_ARBID ArbitrationId;
## NCTYPE_UINT8 FrameType;
## NCTYPE_UINT8 DataLength;
## NCTYPE_UINT8 Data[8];
##} NCTYPE_CAN_STRUCT;
class CAN_STRUCT(Structure):
_fields_ = [("Timestamp", c_ulonglong),
("ArbitrationId", c_ulong),
("FrameType", c_ubyte),
("DataLength", c_ubyte),
("Data", c_ubyte*8)]
CAN_receive_buffer = (CAN_STRUCT*100)()
Status = c_long(0)
CAN_HANDLE = c_ulong(0)
##CAN_data_size = c_ulong(sys.getsizeof(CAN_receive_buffer))
CAN_data_size = c_ulong(100)
print CAN_data_size.value
CAN_received_size = c_ulong(1)
CAN_NAME = c_char_p("CAN0")
canNumAttr = c_ulong(8)
# Define Constants
NC_TRUE = c_ulong(1)
NC_TRUE = c_ulong(0)
NC_CAN_MASK_STD_DONTCARE = c_ulong(0x00000000)
NC_CAN_MASK_XTD_DONTCARE = c_ulong(0x00000000)
## Values taken from nican.h
##NC_ATTR_BAUD_RATE = c_ulong(0x80000007)
##NC_ATTR_START_ON_OPEN = c_ulong(0x80000006)
##NC_ATTR_READ_Q_LEN = c_ulong(0x80000013)
##NC_ATTR_WRITE_Q_LEN = c_ulong(0x80000014)
##NC_ATTR_CAN_COMP_STD = c_ulong(0x80010001)
##NC_ATTR_CAN_MASK_STD = c_ulong(0x80010002)
##NC_ATTR_CAN_COMP_XTD = c_ulong(0x80010003)
##NC_ATTR_CAN_MASK_XTD = c_ulong(0x80010004)
# instantiate the array
canAttrIdList = (c_ulong*8)()
# Fill array values
canAttrIdList[0] = c_ulong(0x80000007)
canAttrIdList[1] = c_ulong(0x80000006)
canAttrIdList[2] = c_ulong(0x80000013)
canAttrIdList[3] = c_ulong(0x80000014)
canAttrIdList[4] = c_ulong(0x80010001)
canAttrIdList[5] = c_ulong(0x80010002)
canAttrIdList[6] = c_ulong(0x80010003)
canAttrIdList[7] = c_ulong(0x80010004)
##NC_ATTR_BAUD_RATE = 500000
##NC_ATTR_START_ON_OPEN = NC_TRUE
##NC_ATTR_READ_Q_LEN = 100
##NC_ATTR_WRITE_Q_LEN = 0
##NC_ATTR_CAN_COMP_STD = 0
##NC_ATTR_CAN_MASK_STD = NC_CAN_MASK_STD_DONTCARE
##NC_ATTR_CAN_COMP_XTD = 0
##NC_ATTR_CAN_MASK_XTD = NC_CAN_MASK_XTD_DONTCARE
# instantiate array
canAttrValueList = (c_ulong * 8)()
# Fill array values
canAttrValueList[0] = 500000
canAttrValueList[1] = NC_TRUE
canAttrValueList[2] = 100
canAttrValueList[3] = 0
canAttrValueList[4] = 0
canAttrValueList[5] = NC_CAN_MASK_STD_DONTCARE
canAttrValueList[6] = 0
canAttrValueList[7] = NC_CAN_MASK_XTD_DONTCARE
#ncConfig = CANdll.ncConfig
# Configure the CAN hardware
Status = CANdll.ncConfig(CAN_NAME, canNumAttr, canAttrIdList, canAttrValueList)
if Status != 0:
print "Error on 'ncConfig'"
print Status
Status = CANdll.ncOpenObject(CAN_NAME, byref(CAN_HANDLE))
if Status != 0:
print "Error on 'ncOpenObject'"
print Status
print CAN_HANDLE.value
time.sleep(1)
try:
Status = CANdll.ncAction(CAN_HANDLE, c_ulong(0x80000001), 0)
if Status != 0:
print "Error on 'ncAction:start'"
print Status
print CAN_HANDLE.value
i=0
string = "Data: "
while i < 5:
Status = CANdll.ncReadMult(CAN_HANDLE, CAN_data_size,
byref(CAN_receive_buffer),
byref(CAN_received_size))
print "CAN_received_size: %d" % CAN_received_size.value
if Status != 0:
print "Error on 'ncReadMult'"
print Status
print CAN_HANDLE.value
#for n in range(0,CAN_received_size.value):
for n in range(0,5):
print "Timestamp: %d" % CAN_receive_buffer[n].Timestamp
print "Data Length: %d" % CAN_receive_buffer[n].DataLength
print "ArbitrationID: %X" % CAN_receive_buffer[n].ArbitrationId
for j in range(0,CAN_receive_buffer[n].DataLength):
string = string + "%d " % (CAN_receive_buffer[n].Data[j])
print string
string = "Data: " #reset the string
print " "
time.sleep(1)
i += 1
## ALWAYS CALL LAST
finally:
Status = CANdll.ncCloseObject(CAN_HANDLE)
if Status != 0:
print "Error on 'ncCloseObject'"
print Status
06-28-2012 11:39 AM
I expect: ArbID of 230, data length 1, and data of 11. (verified using the bus monitor).
The output:
CAN_received_size: 88
Timestamp: 129853745842490707
Data Length: 1
ArbitrationID: 230
Data: 11
Timestamp: 157627968368884147
Data Length: 1
ArbitrationID: 1000000
Data: 70
Timestamp: 2405211919691
Data Length: 0
ArbitrationID: 10B0100
Data:
Timestamp: 72057594074628557
Data Length: 1
ArbitrationID: 46010B
Data: 70
Timestamp: 0
Data Length: 0
ArbitrationID: 0
Data:
07-11-2012 03:38 PM
This is working code. I have to poll the hardware for how many waiting frames there are, then read them individually as I am having no luck using ncReadMult. If anyone needs to do this, here is a starting point.
/thread
from ctypes import *
from array import *
import sys
import struct
import time
#Load the DLL
CANdll = windll.LoadLibrary("NICAN.dll")
NC_ST_READ_AVAIL = c_ulong(0x00000001)
NC_ATTR_READ_PENDING = c_ulong(0x80000011)
## RELEVANT C HEADER INFO
## typedef NCTYPE_INT32 NCTYPE_STATUS;
## typedef NCTYPE_UINT32 NCTYPE_OBJH;
##typedef struct {
## NCTYPE_ABS_TIME Timestamp;
## NCTYPE_CAN_ARBID ArbitrationId;
## NCTYPE_UINT8 FrameType;
## NCTYPE_UINT8 DataLength;
## NCTYPE_UINT8 Data[8];
##} NCTYPE_CAN_STRUCT;
class CAN_STRUCT(Structure):
_fields_ = [("Timestamp", c_ulonglong),
("ArbitrationId", c_ulong),
("FrameType", c_ubyte),
("DataLength", c_ubyte),
("Data", c_ubyte * 8)]
CAN_receive_buffer = (CAN_STRUCT*1000)()
Status = c_long(0)
CAN_HANDLE = c_ulong(0)
##CAN_data_size = c_ulong(sys.getsizeof(CAN_receive_buffer))
CAN_data_size = c_ulong(17600)
CAN_received_size = c_ulong(1)
CAN_NAME = c_char_p("CAN0")
canNumAttr = c_ulong(8)
# Define Constants
NC_TRUE = c_ulong(1)
NC_FALSE = c_ulong(0)
NC_CAN_MASK_STD_DONTCARE = c_ulong(0x00000000)
NC_CAN_MASK_XTD_DONTCARE = c_ulong(0x00000000)
## Values taken from nican.h
##NC_ATTR_BAUD_RATE = c_ulong(0x80000007)
##NC_ATTR_START_ON_OPEN = c_ulong(0x80000006)
##NC_ATTR_READ_Q_LEN = c_ulong(0x80000013)
##NC_ATTR_WRITE_Q_LEN = c_ulong(0x80000014)
##NC_ATTR_CAN_COMP_STD = c_ulong(0x80010001)
##NC_ATTR_CAN_MASK_STD = c_ulong(0x80010002)
##NC_ATTR_CAN_COMP_XTD = c_ulong(0x80010003)
##NC_ATTR_CAN_MASK_XTD = c_ulong(0x80010004)
#NC_ATTR_LISTEN_ONLY 0x80010010
# instantiate the array
canAttrIdList = (c_ulong*9)()
# Fill array values
canAttrIdList[0] = c_ulong(0x80000007)
canAttrIdList[1] = c_ulong(0x80000006)
canAttrIdList[2] = c_ulong(0x80000013)
canAttrIdList[3] = c_ulong(0x80000014)
canAttrIdList[4] = c_ulong(0x80010001)
canAttrIdList[5] = c_ulong(0x80010002)
canAttrIdList[6] = c_ulong(0x80010003)
canAttrIdList[7] = c_ulong(0x80010004)
canAttrIdList[8] = c_ulong(0x80010010)
##NC_ATTR_BAUD_RATE = 500000
##NC_ATTR_LISTEN_ONLY = NC_TRUE
##NC_ATTR_READ_Q_LEN = 100
##NC_ATTR_WRITE_Q_LEN = 0
##NC_ATTR_CAN_COMP_STD = 0
##NC_ATTR_CAN_MASK_STD = NC_CAN_MASK_STD_DONTCARE
##NC_ATTR_CAN_COMP_XTD = 0
##NC_ATTR_CAN_MASK_XTD = NC_CAN_MASK_XTD_DONTCARE
# instantiate array
canAttrValueList = (c_ulong * 9)()
# Fill array values
canAttrValueList[0] = 500000
canAttrValueList[1] = NC_TRUE
canAttrValueList[2] = 100
canAttrValueList[3] = 0
canAttrValueList[4] = 0
canAttrValueList[5] = NC_CAN_MASK_STD_DONTCARE
canAttrValueList[6] = 0
canAttrValueList[7] = NC_CAN_MASK_XTD_DONTCARE
canAttrValueList[8] = NC_FALSE
# Configure the CAN hardware
Status = CANdll.ncConfig(CAN_NAME, canNumAttr, canAttrIdList, canAttrValueList)
if Status != 0:
print "Error on 'ncConfig'"
print Status
Status = CANdll.ncOpenObject(CAN_NAME, byref(CAN_HANDLE))
if Status != 0:
print "Error on 'ncOpenObject'"
print Status
print CAN_HANDLE.value
time.sleep(1)
try:
Status = CANdll.ncAction(CAN_HANDLE, c_ulong(0x80000001), 0)
if Status != 0:
print "Error on 'ncAction:start'"
print Status
print CAN_HANDLE.value
i=0
##string = "Data: "
string = ""
pending_CAN_frames = c_ulong(0)
while i < 100:
Status = CANdll.ncGetAttribute(CAN_HANDLE, NC_ATTR_READ_PENDING,
32, byref(pending_CAN_frames))
print "Pending CAN frames: %d" % pending_CAN_frames.value
if Status != 0:
print "Error on 'ncGetAttribute'"
print Status
for n in range(0, pending_CAN_frames.value):
Status = CANdll.ncRead(CAN_HANDLE, CAN_data_size,
byref(CAN_receive_buffer[n]))
for n in range(0,pending_CAN_frames.value):
for j in range(0,CAN_receive_buffer[n].DataLength):
string = string + "%X " % (CAN_receive_buffer[n].Data[j])
print "%X\t%d\t%s" % (CAN_receive_buffer[n].ArbitrationId, CAN_receive_buffer[n].DataLength, string)
string = "" #reset the string
i += 1
## ALWAYS CALL LAST
finally:
Status = CANdll.ncCloseObject(CAN_HANDLE)
if Status != 0:
print "Error on 'ncCloseObject'"
print Status
/thread
I hope this helps someone in the future.
06-22-2019 12:28 AM
"CAN_NAME = c_char_p("CAN0")" why this sentence can not run correct?
and if I use "CAN_NAME = 'CAN0" instead, ncConfig returns -1074388989
08-08-2019 03:45 AM
Hi Garrick,
NI-XNET Python API is available now. If you are using NI-XNET device, please get the driver and documentation from here: https://github.com/ni/nixnet-python
DISCLAIMER: The attached Code is provided As Is. It has not been tested or validated as a product, for use in a deployed application or system, or for use in hazardous environments. You assume all risks for use of the Code and use of the Code is subject to the Sample Code License Terms which can be found at: http://ni.com/samplecodelicense