From Saturday, Nov 23rd 7:00 PM CST - Sunday, Nov 24th 7:45 AM CST, ni.com will undergo system upgrades that may result in temporary service interruption.
We appreciate your patience as we improve our online experience.
From Saturday, Nov 23rd 7:00 PM CST - Sunday, Nov 24th 7:45 AM CST, ni.com will undergo system upgrades that may result in temporary service interruption.
We appreciate your patience as we improve our online experience.
06-03-2021 11:25 AM
Thanks ElectroLund. You have helped me to understand the significance of callbacks in the CVI environment and that they can be used even when there is no GUI driving user input events. I came to appreciate the callback function when working with the TCP library as well.
06-04-2021 08:29 AM - edited 06-04-2021 08:37 AM
Hello ElectroLund,
If you don't mind, could you take a quick look at the approach I've implemented based on InstallComCallBack? Just want to make sure I'm on the right track.
First, I call openComConfig.
int status = 0;
int notifyCount = 50; /* Wait for at least 50 bytes in queue. */
int eventChar = 10; /* Wait for LF. */
int eventMask = LWRS_RXFLAG | LWRS_RECEIVE;
while(true)
{
if ((status = OpenComConfig(comPort, deviceName, baudRate, 0, 7, 1, INPT_QUEUE, OTPT_QUEUE)) < 0) //open & config COM port
{
checkRS232Err (status, errBuf);
break;
}
Then I call various functions to further configure (set CTS mode etc...).
Then I install the callback
InstallComCallback (comPort, eventMask, notifyCount, eventChar, charDetectFunc, NULL);
Here is my callback definition, which will read the data into a global buffer.
/********************************************************************************************/
/* Fuction called when LF character or 50 bytes are detected at input Queue */
/********************************************************************************************/
void CVICALLBACK charDetectFunc (int portNo, int eventMask, void *callbackData)
{
int strLen;
g_dataReady = true;
strLen = GetInQLen (portNo);
ComRd (portNo, g_receiveBuffer, strLen);
}
Finally, I have a separate DLL function which I call "read" which simply processes system events, and I will need to implement something there where the global buffer is copied to its local buffer (parameter) so that the calling application can access it.
void readSerialData(int comPort, char buffer[], char errBuf[])
{
while(true)
{
if(g_dataReady)
{
ProcessSystemEvents();
Delay(0.01);
break;
}
}
/* copy global buffer to local buffer */
}
So I believe that this is the correct approach. I have a callback that will fire whenever certain events take place (a LF is detected at input queue or 50 bytes are detected). It will then execute a ComRd() into a global buffer which I can then access from other functions. Finally, I just need to run ProcessSystemEvents() in a loop untl I have read all the data.
Do you think this approach makes sense? Thanks in advance!
06-08-2021 07:34 AM
int status = 0; int notifyCount = 50; /* Wait for at least 50 bytes in queue. */ int eventChar = 10; /* Wait for LF. */ int eventMask = LWRS_RXFLAG | LWRS_RECEIVE; while(true) { if ((status = OpenComConfig(comPort, deviceName, baudRate, 0, 7, 1, INPT_QUEUE, OTPT_QUEUE)) < 0) //open & config COM port { checkRS232Err (status, errBuf); break; }
Your OpenComConfig will continue to fire in that while loop if if passes. I think you meant to check for == 0. I wouldn't keep trying a function until it passes. Personally, I prefer using error handlers to have record of failure where and when it happens.
Finally, I have a separate DLL function which I call "read" which simply processes system events, and I will need to implement something there where the global buffer is copied to its local buffer (parameter) so that the calling application can access it.
void readSerialData(int comPort, char buffer[], char errBuf[]) { while(true) { if(g_dataReady) { ProcessSystemEvents(); Delay(0.01); break; } } /* copy global buffer to local buffer */ }
So I believe that this is the correct approach. I have a callback that will fire whenever certain events take place (a LF is detected at input queue or 50 bytes are detected). It will then execute a ComRd() into a global buffer which I can then access from other functions. Finally, I just need to run ProcessSystemEvents() in a loop untl I have read all the data.
I'm still unclear why you prefer the blocking loops. Your calling application will get stuck in that DLL loop until data is ready. So that application will need to support multi-threading if you want it to do other things while you wait.
Another approach is to consider that the calling app has some idea of when data might be output by the instrument, since it likely controls when that instrument is communicated with.
Also, you won't need the call to ProcessSystemEvents at all, since the CVI runtime engine handles the events fired by InstallComCallback.
If you wanted to be clever, you could forgo the global flag entirely, since you're already filling a global character buffer.
08-22-2024 06:16 AM
I had a situation where I needed to monitor and capture data from a serial bus (RS-232) for an automated test. To tackle this, I used https://www.serial-port-monitor.org/ and it worked really well for my needs.
Here’s how I approached it:
First, I configured the COM port just as you mentioned. I then used Serial port monitor to capture and log all the data transmitted during the boot-up process of the embedded PC. The application allowed me to easily monitor the data stream in real-time and save it directly to a file, which was perfect for my scenario.
This way, I could review the entire boot text and parse it for specific tokens without worrying about missing anything.
Regarding your question about the “termination byte” parameter, Serial port monitor doesn’t require you to define a termination byte upfront, which was helpful for me because, like you, I didn’t know what the text output would look like in its entirety. The tool simply logs all the data as it comes, so you can handle the parsing later, either from the saved file or directly in the buffer.
As for storing the boot text in a file versus a large buffer, I found that writing the text to a file and then parsing it was more manageable, especially when dealing with large or complex outputs. It kept the process simpler and more organized.
08-22-2024 10:43 AM
Yes indeed, a serial port terminal is an excellent development tool, particularly when the protocol isn't well defined.
I have a gaggle of such tool. My favorite for years is one called RealTerm. It's clunky but extremely powerful and free. A more modern equivalent is Terminal, also free.
A commercial tool I use often is Device Monitoring Studio, which is a bit different. It's a try "sniffer" in the sense that it sits at the USB driver level, in between your serial application and the serial device your application is talking to. So it will display both send and receive packets transparently. It's not a terminal, though you can use it that way. I've used it many times that I'm developing from scratch device drivers for instruments that don't have customer DLLs.