Saturday, April 2, 2022

[SOLVED] Python bytes buffer only giving out zeros even though data is being correctly received through SPI on Raspberry Pi

Issue

This is a follow up question from: href="https://stackoverflow.com/questions/71292480/class-typeerror-lp-c-long-instance-instead-of-list/71298738?noredirect=1#comment126036149_71298738"><class 'TypeError'>: LP_c_long instance instead of list but is a different issue so I am posting a new question here.

I am using ctypes to invoke a c function from python script. The c function which is being invoked is:

uint32_t crc32Word(uint32_t crc, const void *buffer, uint32_t size)

I have this python code:

import datetime
import os
import struct
import time
import pigpio
import spidev
import ctypes

lib = ctypes.CDLL('/home/pi/serial_communication/crc.so')
lib.crc32Word.argtypes = ctypes.c_uint32, ctypes.c_void_p, ctypes.c_uint32
lib.crc32Word.restype = ctypes.c_uint32

bus = 0
device = 0
spi = spidev.SpiDev()
spi.open(bus, device)
spi.max_speed_hz = 4000000
spi.mode = 0

pi.set_mode(12, pigpio.INPUT)

C=0
 
def output_file_path():
    return os.path.join(os.path.dirname(__file__),
               datetime.datetime.now().strftime("%dT%H.%M.%S") + ".csv")
 
def spi_process(gpio,level,tick):
    print("Detected")
    data = bytes([0]*1024)
    spi.xfer([0x02])
    with open(output_file_path(), 'w') as f:
        t1=datetime.datetime.now()
        for x in range(1):
            spi.xfer2(data)
            values = struct.unpack("<" +"I"*256, bytes(data))
            C = lib.crc32Word(0xffffffff,data,len(data))
            f.write("\n")
            f.write("\n".join([str(x) for x in values]))
        t2=datetime.datetime.now()
        print(t2-t1)
        print(C)

input("Press Enter to start the process ")
spi.xfer2([0x01])

cb1=pi.callback(INTERRUPT_GPIO, pigpio.RISING_EDGE, spi_process)

while True:
    time.sleep(1)

Previously, I initialized data as data = [0]*1024, so I was receiving some error as mentioned in the previous post. But the error was resolved by initializing data to bytes. Now the issue that I have is even though the correct data is received on Raspberry Pi (checked using logic analyzer), only 0s are stored in the file.

I also tried initializing data as arrays instead of lists using numpy library as below, but I receive an error saying: Tried code:

import numpy as np
 
#changed initialization of data to:
data= np.arange(1024) #also tried: np.zeros(1024,ctypes.c_uint8), also get same error

Error:

File "2crc_spi.py", line 48, in spi_process
   spi.xfer2(data)
TypeError: Non-Int/Long value in arguments: b5410b00

But data only receives a byte at a time so not sure where is the issue when using array.

Can someone please help? Thanks~

EDIT: Below is the original code that was working fine with the data collection and unpacking functions before I started integrating the CRC functionality:

import datetime
import os
import struct
import time
import pigpio
import spidev

bus = 0
device = 0
spi = spidev.SpiDev()
spi.open(bus, device)
spi.max_speed_hz = 4000000
spi.mode = 0

pi.set_mode(12, pigpio.INPUT)

a=0
 
def output_file_path():
    return os.path.join(os.path.dirname(__file__),
               datetime.datetime.now().strftime("%dT%H.%M.%S") + ".csv")
 
def spi_process(gpio,level,tick):
    print("Detected")
    data = [0]*2048
    spi.xfer([0x02])
    with open(output_file_path(), 'w') as f:
        t1=datetime.datetime.now()
        for x in range(1):
            spi.xfer2(data)
            values = struct.unpack("<" +"I"*256, bytes(data))
            f.write("\n")
            f.write("\n".join([str(x) for x in values]))
        t2=datetime.datetime.now()
        print(t2-t1)

input("Press Enter to start the process ")
spi.xfer2([0x01])

cb1=pi.callback(INTERRUPT_GPIO, pigpio.RISING_EDGE, spi_process)

while True:
   time.sleep(1)

Solution

As @Mark's suggested in comments, you would have to store the data into another variable/list, for example: recv = spi.xfer2(data). Then you would need to use this recv in your unpack function. Further, you could also use a python library called zlib instead of using a c library (there are other python libraries as well).

Another point, since zlib takes only bytes as input, you would need to convert recv into bytes (here recv is a list; check my code). I modified some of your code.

import datetime
import os
import struct
import time
import pigpio
import spidev
import zlib

bus = 0
device = 0
spi = spidev.SpiDev()
spi.open(bus, device)
spi.max_speed_hz = 4000000
spi.mode = 0

pi.set_mode(12, pigpio.INPUT)

C=0
 
def output_file_path():
    return os.path.join(os.path.dirname(__file__),
               datetime.datetime.now().strftime("%dT%H.%M.%S") + ".csv")
 
def spi_process(gpio,level,tick):
    print("Detected")
    data = bytes([0]*1024)
    spi.xfer2([0x02])
    with open(output_file_path(), 'w') as f:
        t1=datetime.datetime.now()
        for x in range(1):
            recv = spi.xfer2(data)
            values = struct.unpack("<" +"I"*256, bytes(recv))
            C = zlib.crc32(bytes(recv))
            f.write("\n")
            f.write("\n".join([str(x) for x in values]))
        t2=datetime.datetime.now()
        print(t2-t1)
        print(C)

input("Press Enter to start the process ")
spi.xfer2([0x01])

cb1=pi.callback(INTERRUPT_GPIO, pigpio.RISING_EDGE, spi_process)

while True:
    time.sleep(1)


Answered By - Gagan Batra
Answer Checked By - Mildred Charles (WPSolving Admin)