Python win32 event in different processes

The free CAN Software API (Application Programming Interface) for Windows®
Locked
msalz
Posts: 8
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: 1080
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: 8
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: 1080
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 8021 times
I also wrote a simple sample which has the same behavior:
Pyhton.PNG
Pyhton.PNG (42.03 KiB) Viewed 8021 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

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

Re: Python win32 event in different processes

Post by msalz » Wed 19. Aug 2020, 07:28

Hello,

your script works. But the difference to my application is that I have hard time limits.
In my case I have 2 PEAK PRO FD USB. With the 1st PEAK a frame is sent on the bus on channel 1 and read with the 2nd channel back. Afterwards another bus participant sends his answer to the request. Only if the answer comes within a time window (e.g. 10ms), the "test" is successful. The script works fine, if I do not execute anything else than this script.

If I use the 2nd PEAK in parallel with the following script, the software on PEAK 1 aborts after a few seconds, i.e. PEAK 1 is affected by executing an init and uninit on PEAK 2:

Code: Select all

from PCANBasic import *
import time

PCANBasic_Object = PCANBasic()


def ConfigureChannel(channelToConnect):
    result = PCANBasic_Object.Initialize(channelToConnect, PCAN_BAUD_250K)
    return result == PCAN_ERROR_OK


if __name__ == "__main__":
    while True:
        print("Initialize")
        ConfigureChannel(PCAN_USBBUS3)
        ConfigureChannel(PCAN_USBBUS4)
        PCANBasic_Object.Uninitialize(PCAN_USBBUS3)
        PCANBasic_Object.Uninitialize(PCAN_USBBUS4)

Each PEAK has its own CAN bus, i.e. the bus is isolated from each other. The PEAKs are connected to the same PC.

PEAK1: Firmware-Version: 2.2.1, Driver-Version: 4.2.1
PEAK2: Firmware-Version: 2.1.0, Driver-Version: 4.2.1


Thanks,
Martin

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

Re: Python win32 event in different processes

Post by K.Wagner » Wed 19. Aug 2020, 10:07

Hello,

please note that you are using devices with very old firmware versions. Eight releases have been done since version 2.1.0. You find instructions on how to update these in the document PEAK USB CAN Interfaces - Firmware Update. Note that you need a Windows 7 system in order to update a device with Firmware version less than or equal to 2.2.1 (check page 5).

If you need further assistance on updating, please contact us per email: support[at]peak-system.com
Best regards,
Keneth

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

Re: Python win32 event in different processes

Post by K.Wagner » Wed 19. Aug 2020, 10:27

Hello,
msalz wrote:
Wed 19. Aug 2020, 07:28
your script works. But the difference to my application is that I have hard time limits.
Windows is not a real time system. The resolution of a timer in Windows about 16 milliseconds. If you need more accuracy, you need to use performance timer, as described in this post. In order to check how to do this under python, please check a python forum. In this case you could use a timer instead of events, if it is easier for you.
msalz wrote:
Wed 19. Aug 2020, 07:28
Only if the answer comes within a time window (e.g. 10ms), the "test" is successful. The script works fine, if I do not execute anything else than this script.
Not sure to understand. Means this that if you do other processing you have problem to read? If yes, please check your code. You should have the reading in a different thread and have this synchronized well. When using an Event you read the message asap, so if it is coming öater than expected then the problem is not on getting the message but in the node sending it or somewhere else.
msalz wrote:
Wed 19. Aug 2020, 07:28
If I use the 2nd PEAK in parallel with the following script, the software on PEAK 1 aborts after a few seconds, i.e. PEAK 1 is affected by executing an init and uninit on PEAK 2:
I have already demonstrated, that several channels coexist when communicating in the same network. Please check/debug the channel handles being used, i.e. being uninitialized. As long as the devices are attached to the PC they don't change their handles. Operations within the API and the device driver are separated by handle, so it cannot be, that one device cause other device to be disconnected or something like that. Also note that using PCANBasic.Uninitialize(PCAN_NONEBUS) causes the disconnection of all channels connected before.

Question: are those devices connected to a USB-switch? note that if so, the switch should be powered, otherwise unwanted problems (like unwanted unplug events) may occur.
Best regards,
Keneth

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

Re: Python win32 event in different processes

Post by msalz » Tue 25. Aug 2020, 16:24

Hello,
Question: are those devices connected to a USB-switch? note that if so, the switch should be powered, otherwise unwanted problems (like unwanted unplug events) may occur.
Yes, the PEAKs are connected to a docking station on the PC via an active USB hub. After the devices were connected directly without a hub, the problem does not occur anymore.



Thanks,
Martin

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

Re: Python win32 event in different processes

Post by K.Wagner » Mon 31. Aug 2020, 10:00

As the manual states, USB hubs should be avoided, or use those that are self powered.

Closed.
Best regards,
Keneth

Locked