Automotive and Embedded Networks

cancel
Showing results for 
Search instead for 
Did you mean: 

Python calling nican.dll issues

Solved!
Go to solution

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

Message 1 of 7
(8,514 Views)

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.

0 Kudos
Message 2 of 7
(8,500 Views)

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


Message 3 of 7
(8,466 Views)

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:

Message 4 of 7
(8,465 Views)
Solution
Accepted by topic author medendoc

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.

Message 5 of 7
(8,443 Views)

"CAN_NAME = c_char_p("CAN0")" why this sentence can not run correct?

and if I use "CAN_NAME = 'CAN0" instead, ncConfig returns -1074388989

0 Kudos
Message 6 of 7
(3,038 Views)

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

Senior Technical Support Engineer | CLD CTA | NI


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

0 Kudos
Message 7 of 7
(2,847 Views)