Python win32 event in different processes

The free CAN Software API (Application Programming Interface) for Windows®
Post Reply
msalz
Posts: 6
Joined: Wed 20. May 2020, 16:17

Python win32 event in different processes

Post by msalz » Fri 3. Jul 2020, 10:48

Hello,

a Python script is reading frames per event using win32.event according to the PCANBasicExample.py example. The function works properly according to the following scheme: Several PCANs are connected to the PC and a PEAK with a certain ID is searched and selected.

Code: Select all

	...
	match = False
        result = self.m_objPCANBasic.GetValue(PCAN_NONEBUS, PCAN_ATTACHED_CHANNELS)
        if(result[0] == PCAN_ERROR_OK):
            for channel in result[1]:
                if channel.channel_condition & PCAN_CHANNEL_OCCUPIED: continue
                elif  channel.channel_condition & PCAN_CHANNEL_AVAILABLE:
                    if channel.channel_handle < 0x100:
                        devDevice = TPCANDevice(channel.channel_handle >> 4)
                        byChannel = channel.channel_handle & 0xF
                    else:
                        devDevice = TPCANDevice(channel.channel_handle >> 8)
                        byChannel = channel.channel_handle & 0xFF

                    if channel.device_id == self.device_id:
                        self.m_PcanHandle_write = channel.channel_handle
                        self.m_PcanHandle_read = self.m_PcanHandle_write + 1
                        match = True
                        break

        if not match: return False
        self.m_ReceiveEvent = win32event.CreateEvent(None, 0, 0, None)
        ...
Further in the code a thread is started for reading.

Code: Select all

	...
	self.m_ReadThread = threading.Thread(None, self.CANReadThreadFunc)
        self.m_ReadThread.start()
        ...
Here the read thread is shown. If an event exists, the message queue is read with ReadMessages().

Code: Select all

	...
	stsResult = self.m_objPCANBasic.SetValue(self.m_PcanHandle_read, PCAN_RECEIVE_EVENT, self.m_ReceiveEvent)
 
        if stsResult != PCAN_ERROR_OK:
            print ("Error: " + self.GetFormatedError(stsResult))
        else:
            self.event_start_write.set()
            endTimestamp = millis() + self.test.delay
            self.count = 0
            while True:
                if win32event.WaitForSingleObject(self.m_ReceiveEvent, self.test.delay) == win32event.WAIT_OBJECT_0:
                    if not self.max_delay:
                        if self.ReadMessages(): break
                    else:
                        self.ReadMessages()
                if millis() > endTimestamp: break

            self.m_objPCANBasic.SetValue(self.m_PcanHandle_read, PCAN_RECEIVE_EVENT, 0)
        ...
This code works fine with every PEAK on a single call (process). As soon as I make a second script call parallel to the first call (two processes in parallel, each call is assigned a PEAK ID, i.e. the processes use a different HW), the first call aborts with an error:
stsResult = self.m_objPCANBasic.SetValue(self.m_PcanHandle_read, PCAN_RECEIVE_EVENT, self.m_ReceiveEvent)
returns the error code PCAN_ERROR_ILLPARAMVAL 0x08000

Do the events in the different processes influence each other?
(At first I did not use an event handler for reading, i.e. I used polling. So the parallel operation worked. Only after switching to the event handler does the problem occur)

Thanks,
Martin

K.Wagner
Software Development
Software Development
Posts: 732
Joined: Wed 22. Sep 2010, 13:36

Re: Python win32 event in different processes

Post by K.Wagner » Fri 3. Jul 2020, 14:10

Hello,
msalz wrote:
Fri 3. Jul 2020, 10:48
Do the events in the different processes influence each other?
Actually not. PCAN-Basic manages things per connected channel, this is, you can set one read-event per initialized channel. What you want to do is not other than launching our sample twice and setting in both instances the option "reading using an event". In this case, each process will create an event, and configure the initialized channel with it (just tested this and it works). Also modifying the sample to initialize 2 channels and to set the same event handler to both works within the sample code.

Try including some debug data to your code to inspect the content of the self.m_ReceiveEvent when setting the event. A typical case to get the error ILLPARAMVAL is when the passed parameter value is NULL.
Best regards,
Keneth

msalz
Posts: 6
Joined: Wed 20. May 2020, 16:17

Re: Python win32 event in different processes

Post by msalz » Mon 6. Jul 2020, 11:19

Hello,

Code: Select all

print(self.m_ReceiveEvent)
returns

Code: Select all

<PyHANDLE:800>
each process will create an event, and configure the initialized channel with it (just tested this and it works)
Can you please send me your example code?


Thanks

K.Wagner
Software Development
Software Development
Posts: 732
Joined: Wed 22. Sep 2010, 13:36

Re: Python win32 event in different processes

Post by K.Wagner » Mon 6. Jul 2020, 12:49

Hello,

the test I made was done with our standard sample which is delivered with the PCAN-Basic package. It has implemented reading using events:
PythonMain.PNG
PythonMain.PNG (35.27 KiB) Viewed 172 times
I also wrote a simple sample which has the same behavior:
Pyhton.PNG
Pyhton.PNG (42.03 KiB) Viewed 172 times
the code used is this:

Code: Select all


from PCANBasic import *        ## PCAN-Basic library import
import threading               ## Threading-based Timer library
import win32event              ## Windows Events

# Instanciating the DLL
PCANBasic_Object = PCANBasic()

# Constants - adjust these as required

# Globals
g_pcanHandle = PCAN_NONEBUS
g_Terminated = False
g_readThread = None
g_receiveEventObject = None

def ConfigureChannel(channelToConnect):
    global g_receiveEventObject

    result = PCANBasic_Object.Initialize(channelToConnect, PCAN_BAUD_500K)
    if (result == PCAN_ERROR_OK):
        g_receiveEventObject = win32event.CreateEvent(None, 0, 0, None)
        # Configures the Receive-Event. 
        #
        result = PCANBasic_Object.SetValue(channelToConnect, PCAN_RECEIVE_EVENT, g_receiveEventObject)
        if(result != PCAN_ERROR_OK):
            print("Error configuring RECEIVE EVENT\n")

    return result == PCAN_ERROR_OK

def InitializeSample():    
    global g_Terminated
    global g_readThread
    global g_pcanHandle 

    if (ConfigureChannel(PCAN_USBBUS1)):
        g_pcanHandle = PCAN_USBBUS1
    else:
        if (ConfigureChannel(PCAN_USBBUS2)):
            g_pcanHandle = PCAN_USBBUS2
    
    if (g_pcanHandle == PCAN_NONEBUS):
        return False

    print("Channel " + hex(g_pcanHandle.value) + " initialized")
    g_readThread =  threading.Thread(None, CANReadThreadFunc)
    g_readThread.start()

    return True

def ExitHandler():
    PCANBasic_Object.Uninitialize(PCAN_NONEBUS)
    print("All channels removed\n")


def CANReadThreadFunc():
    global g_Terminated
    global g_pcanHandle
    global g_receiveEventObject

    try:        
        g_Terminated = False
        result = PCAN_ERROR_OK

        print("Starting to read....")
               
        while not g_Terminated:
            if win32event.WaitForSingleObject(g_receiveEventObject, 1000) == win32event.WAIT_OBJECT_0:
                ReadMessages()
            else:
                print ("......Queue empty")  

        PCANBasic_Object.SetValue(g_pcanHandle, PCAN_RECEIVE_EVENT, 0)
    except:
        print ("Error occurred while processing CAN data")  


def ReadMessages():
    global g_pcanHandle

    result = PCANBasic_Object.Read(g_pcanHandle)

    if result[0] == PCAN_ERROR_OK:
        print("message received!")
            
    return result[0]    


def main():
    global g_Terminated
    global g_readThread

    print("PCANBasic-Python test")
    print("startup..\n\n", end = "")

    if (InitializeSample()):
        option = -1
        print("\nHit any key at any moment to finalyse the test...\n\n")        
        input()

        g_Terminated = True
        g_readThread.join()
        ExitHandler()

main()
Best regards,
Keneth

Post Reply