LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

New to LabVIEW — ADLINK PCIe-7396 relay tester: file dialog on every save, plus general design advice

Solved!
Go to solution

SNIPPETS 1.png

825206-12.PNG

825206-13.PNG

  

Background

I'm an intern with about one month of LabVIEW experience and I've been handed a relay test project on my own, so I'm learning as I go. Apologies in advance if some of this is basic — I'd rather ask than keep guessing.

Hardware: ADLINK PCIe-7396, 12 ports × 8 channels, driving relays. LabVIEW version: [fill in — e.g. 2019 32-bit] Driver: ADL7396— ADLINK DAQ version]

What the VI does

Single VI, tab control with two pages:

Tab 1 – Operator Dashboard: port selector (0–11), DI/DO direction, an 8-box boolean control array that writes to the selected port, and 12 read-back indicator arrays.
Tab 2 – Engineer Settings: card identity, error display, write/read counters, and a sequential LED walk test.

Channel names are stored in a tab-separated text file, 12 rows × 8 columns, where the row number is the port number. Selecting a different port should load that row's names into the display.

Problem 1 — File dialog appears every time I save port names

When the operator edits a channel name, my save code runs and LabVIEW pops the "save as" dialog asking where to put PortNames.txt, every single time. I want it to write silently to a fixed location next to the VI.

I build the path with Current VI's Path → Strip Path → Build Path, wrapped in a small subVI. Is the dialog appearing because the path isn't reaching the write VI's file path input, or is there something else that triggers it? And is putting the file next to the VI the right approach, or should this live somewhere else once the app is built into an EXE?

Problem 2 — Reading the file back when the port selection changes

I'd like the channel names to reload from the text file whenever the port number changes. Right now I write to the file but I'm not confident about the read-back path, and I sometimes end up with blank rows or an off-by-one row.

Is Read Delimited Spreadsheet → Index Array (row = port number) the normal way to do this, or is there a better pattern for small per-port config like this? Would a config INI file or a TDMS file be a more appropriate choice than a plain text file?

Problem 3 — Counting successful vs failed writes

I want a running count of successful and failed writes and reads, shown on the engineer tab, so I can tell whether my code is actually reaching the card. My understanding is: take the error cluster out of the Digital Output VI, unbundle the status boolean, invert it, convert to 0/1, and accumulate in a shift register.

Does that hold up in practice? Some driver calls seem to return no error even when nothing physically moves, so I'm not sure an error-free call really proves a successful write. Is there a more reliable success criterion — reading the port back and comparing to what was commanded, for example?

Problem 4 — Serial number entry without a barcode scanner

I was considering a barcode scanner for unit serial numbers, but I may not get one. For manual entry, what do people use to stop typos — a format mask, Match Pattern validation, a checksum on the serial itself? I'd like the logged serial to be trustworthy since it's the only link between a test result and a physical unit.

Problem 5 — General design review

Broader questions from someone still finding their footing:

My code is currently one large block diagram with several sections side by side. At what point should this be split into subVIs, and what's a sensible way to divide it?
For a tab-based operator/engineer split, is an event structure with a single While loop the standard approach, or should the two tabs run as separate parallel loops?
I have hardcoded channel constants in a few places that pin operations to one port regardless of the selector. What's the usual way to make the channel follow a front-panel control on ADLINK cards — a control wired in, or indexing a handle array?
Is there a recommended way to gate access to an engineer tab (password, key switch, page Disabled property)?
Problem 6 — Example code

Can anyone point me at a reference example of a simple hardware test panel that reads and writes a per-port configuration file? Something I can read through and learn the structure from would help more than another isolated snippet. NI Example Finder entries or community posts both welcome.

Thanks for any guidance. Happy to post screenshots of the block diagram if that helps — I know a description only goes so far.

0 Kudos
Message 1 of 3
(529 Views)
Solution
Accepted by topic author FineSoFine

Hi Fine,

 


@FineSoFine wrote:

Problem 1 — File dialog appears every time I save port names

When the operator edits a channel name, my save code runs and LabVIEW pops the "save as" dialog asking where to put PortNames.txt, every single time. I want it to write silently to a fixed location next to the VI.

I build the path with Current VI's Path → Strip Path → Build Path, wrapped in a small subVI. Is the dialog appearing because the path isn't reaching the write VI's file path input, or is there something else that triggers it? And is putting the file next to the VI the right approach, or should this live somewhere else once the app is built into an EXE?


  • Yes, the dialog appears because you don't wire the path to the WriteDelimitedFile function.
  • Placing files next to the VI is most often incorrect! This will get into trouble once you create executables because typically the user has no write access in the executable folder…
    Use the GetSystemDirectory function to select a "good" folder for data saving. Typically the UserDocuments is a good place!

@FineSoFine wrote:

Problem 2 — Reading the file back when the port selection changes

I'd like the channel names to reload from the text file whenever the port number changes. Right now I write to the file but I'm not confident about the read-back path, and I sometimes end up with blank rows or an off-by-one row.

Is Read Delimited Spreadsheet → Index Array (row = port number) the normal way to do this, or is there a better pattern for small per-port config like this? Would a config INI file or a TDMS file be a more appropriate choice than a plain text file?


When it comes to "per port config" I would consider an INI file instead, using the port number/name as a section key…

 


@FineSoFine wrote:

Problem 3 — Counting successful vs failed writes

I want a running count of successful and failed writes and reads, shown on the engineer tab, so I can tell whether my code is actually reaching the card. My understanding is: take the error cluster out of the Digital Output VI, unbundle the status boolean, invert it, convert to 0/1, and accumulate in a shift register.

Does that hold up in practice? Some driver calls seem to return no error even when nothing physically moves, so I'm not sure an error-free call really proves a successful write. Is there a more reliable success criterion — reading the port back and comparing to what was commanded, for example?


Typically an "error-free call" should be good enough to signal a successful operation - depending on the quality of your device and driver…

 


@FineSoFine wrote:

Problem 4 — Serial number entry without a barcode scanner

I was considering a barcode scanner for unit serial numbers, but I may not get one. For manual entry, what do people use to stop typos — a format mask, Match Pattern validation, a checksum on the serial itself? I'd like the logged serial to be trustworthy since it's the only link between a test result and a physical unit.


  • Do your serial numbers have a distinctive format? You can only check for known formats…
    When the serial already comes with a "checksum" then you should implement a test for that checksum. (Simple version of such checks.)
  • You can use a filtering event of your string control to filter invalid keys (like letters when only numbers are allowed)…

@FineSoFine wrote:

Problem 5 — General design review

Broader questions from someone still finding their footing:

My code is currently one large block diagram with several sections side by side. At what point should this be split into subVIs, and what's a sensible way to divide it?
For a tab-based operator/engineer split, is an event structure with a single While loop the standard approach, or should the two tabs run as separate parallel loops?
I have hardcoded channel constants in a few places that pin operations to one port regardless of the selector. What's the usual way to make the channel follow a front-panel control on ADLINK cards — a control wired in, or indexing a handle array?
Is there a recommended way to gate access to an engineer tab (password, key switch, page Disabled property)?


The shown block diagram is just bad:

  • way too large
  • using a giant sequence frame, sometimes for no good reason because dataflow already would enforce execution order
  • using lots of locals, while terminals are unused
  • using lots of globals, too
  • (mostly) no error handling

Tab containers are just containers in the front panel: why do you think you need separate loops in the block diagram to handle their content???

 

I would place the whole code into scrap and start over with a simple state machine! There are "init states", "operating states", "UI handling states"… (All you need is a large while loop with one case structure inside.)

 

To gate access you typically ask for passwords. When the correct password is given you can enable controls or show the "engineering" tab…

(We prefer some hardware on our production machines using RFID keys with some data items stored in the key.)

Best regards,
GerdW


using LV2016/2019/2021 on Win10/11+cRIO, TestStand2016/2019
0 Kudos
Message 2 of 3
(500 Views)

Thank You, For Replying my inquiries GerdW

0 Kudos
Message 3 of 3
(496 Views)