Python Forum
PCI-interfacing ADDI-DATA APCI-1516
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
PCI-interfacing ADDI-DATA APCI-1516
#3
(Jan-10-2025, 03:20 PM)deanhystad Wrote: I think your logic is wrong. I would expect that turning an LED ON or OFF would be a single message, but your program sends a continuous stream of messages. I think the only time you need to create a thread is when state == on and frequency > 0, otherwise ToggleOutput should just send a Set or Reset output channel command. If you do create a thread to periodically blink the output, the thread should terminate when the blinking stops (frequency set to 0 or state to off).

You could create a thread for each output, but I think it makes more sense to make 1 thread that handles all the outputs. Better yet, use a periodic event instead of a bunch of threads. You really don't want any part of your program to sleep.

I would get rid of all the threads and create a timer "event" using the .after() command. This code creates a list of blinking lamps that is updated every millisecond. The lamps use a counter to decide when it is time to toggle the lamp. Since I don't have hardware I simulate the lamps with a label that blinks on and off.
import tkinter as tk
from tkinter import ttk
 
 
class Lamp(tk.Frame):
    """Controls for a lamp."""
    def __init__(self, parent, index, command=None):
        """Initialize lamp.
         
        Arguments:
            parent: My parent widget
            index: index of lamp I control.
            command: Command to execute when state or frequency changes.
        """
        super().__init__(parent, borderwidth=1)
        self.state = 'off'
        self.index = index
        self.value = 0
        self.frequency = 0
        self._command = command
        self._freq_count = 0
        self._counter = 0
      
        label = tk.Label(self, text=f"Lamp {index}")
        self.toggle_button = tk.Button(
            self, text="Off", width=3, command=self._toggle_state
        )
        self.display = tk.Label(self, text=" ", width=1)
        self.freq_input = tk.StringVar(self, "0")
        spinbox = ttk.Spinbox(
            self, textvariable=self.freq_input, from_=0, to=500, command=self._frequency_changed
        )
        # Callback for entering text in the spinbox.
        spinbox.bind('<Return>', self._frequency_changed)
        spinbox.bind('<FocusOut>', self._frequency_changed)
 
        label.grid(row=0, column=0, sticky='news')
        self.display.grid(row=0, column=1, sticky="news")
        self.toggle_button.grid(row=1, column=0, columnspan=2, sticky='news')
        spinbox.grid(row=2, column=0, columnspan=2, sticky='news')
 
    def blinking(self):
        """Return True if this lamp is blinking."""
        return self.state == "on" and self.frequency > 0
 
    def blink(self):
        """Update the lamp."""
        self._counter = self._counter - 1
        if self._counter <= 0:
            self._set_value(int(not self.value))
            self._counter = self._freq_count
 
    def __str__(self):
        return f"Lamp {self.index}, state={self.state}, frequency={self.frequency}"
 
    def __repr__(self):
        return f"<{self}>"
 
    def _set_value(self, value):
        """Turn lamp on/off."""
        self.value = value
        self.display["text"] = "0" if value else " "  # Replace with call to Set or Reset output channel.
 
    def _toggle_state(self):
        """Toggle the lamp state between on and off."""
        if self.state == 'off':
            self.state = 'on'
            self.toggle_button.configure(text="On")
            self._counter = self.frequency
            self._set_value(1)
        else:
            self.state = 'off'
            self.toggle_button.configure(text="Off")
            self._set_value(0)
        if self._command is not None:
            self._command(self)
 
    def _frequency_changed(self, *_):
        """Called when new value entered for frequency."""
        try:
            self.frequency = max(0, min(500, int(self.freq_input.get())))
        except (ValueError):
            self.frequency = 0
        self.freq_input.set(self.frequency)
        self._freq_count = 0 if self.frequency == 0 else 1000 // self.frequency
        self._counter = self._freq_count
        if self.frequency == 0:
            self._set_value(int(self.state == "on"))
        if self._command is not None:
            self._command(self)
 
 
class UserInterface(tk.Tk):
    """Gui for controlling lamps."""
    def __init__(self):
        super().__init__()
        self._lamps = []
        for i in range(8):
            lamp = Lamp(self, i, command=self._lamp_changed)
            lamp.grid(row=i // 4, column=i % 4, sticky='news')
            self._lamps.append(lamp)
        self._blinking_lamps = []
 
    def _lamp_changed(self, lamp):
        """Called when lamp state or frequency changed."""
        print(lamp)
        if lamp.blinking():
            if lamp not in self._blinking_lamps:
                self._blinking_lamps.append(lamp)
                if len(self._blinking_lamps) == 1:
                    self._blink()
        elif lamp in self._blinking_lamps:
            self._blinking_lamps.remove(lamp)
        print(self._blinking_lamps)
 
    def _blink(self):
        """Update the blinking lamps."""
        if self._blinking_lamps:
            for lamp in self._blinking_lamps:
                lamp.blink()
            self.after(1, self._blink)
 
 
UserInterface().mainloop()


Heyo and thanks for your answer.
I don't think this is a problem. It could be a problem to continuosly set the output if the desired frequency is 0Hz, but it didn't look like it yet.

You might've seen that I even print out each response, the output is always 0, so the card accepts the command and responds with 0 (no error).

Another point that takes my focus off of my code is that even the example executables that come with the driver pack can't get the card to set or reset any lights.


We've tested the driver examples on a different setup (Win 7, 32 bit, APCI1500) and it worked. I do NOT think it has to do with the card as both of my APCI1516s don't work, rather than it being the operating system.
The driver pack I download is the multiarchitecture driver pack for 64 and 32 it systems, but as of now I am at a point where I think it has to do with bit-depth.

Originally the card was intended for operation in 32bit systems, could it be that it simply isn't made for 64bit operation?
Reply


Messages In This Thread
RE: PCI-interfacing ADDI-DATA APCI-1516 - by Lux_Aitherros - Jan-13-2025, 11:43 AM

Possibly Related Threads…
Thread Author Replies Views Last Post
  Media Pipe Python Interfacing with MATLAB cmcreecc 1 1,074 May-30-2024, 07:23 AM
Last Post: TrentErnser
  Interfacing from Python to GUI HMartins 7 3,289 Apr-23-2023, 06:06 PM
Last Post: HMartins
  Thoughts on interfacing with a QR code reader that outputs keystrokes? wrybread 1 2,220 Oct-08-2021, 03:44 PM
Last Post: bowlofred
  Interfacing with a USB game controller barryjo 2 11,217 Oct-31-2016, 08:21 PM
Last Post: barryjo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020