07-02-2014 01:20 AM
hi, i'm writing serial port listener(monitor) to my ARM microcontroler , using VISA to listen to com port and print data in the textbox. but in the same time i want to use another GUI element and another functions.
here some code explanation:
here i'm open thread for task:
int CVICALLBACK SW_ON_OFF (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { char *value; int val; char params[32]; switch (event) { case EVENT_COMMIT: GetCtrlVal (panel, PANEL_BINARYSWITCH, &val); if(val == 1) { CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE, ThreadFunction, NULL, &mainThreadID); CmtWaitForThreadPoolFunctionCompletion (DEFAULT_THREAD_POOL_HANDLE, mainThreadID, OPT_TP_PROCESS_EVENTS_WHILE_WAITING); } else { CmtReleaseThreadPoolFunctionID (DEFAULT_THREAD_POOL_HANDLE, mainThreadID); ResetTextBox (panelHandle, PANEL_TEXTBOX, ""); ResetTextBox (panelHandle, PANEL_TEXTBOX_STATUS,""); executeCOMCommand("CLOSE", 1); } break; } return 0; }
double executeCOMCommand(char *commandString, int deviceNumber) { ViSession defaultRM; ViReal64 measurement = 0; ViUInt32 num_bytes; ViUInt32 RTCount; ViBoolean packetOK; int result, pp = 0; char dirName[4096], pathName[4096]; int i, currentIndex, verbal = 0; //verbal - the returned measurement is in words int *deviceNumberTosend = malloc(sizeof(int)); char adressString[1024], Databuf[1024], meas[1024], debugMSG[1024]; char dataToSend[4], err[4096], *packetdata; int status; char *command = strtok(commandString, " "); if(deviceNumber<0) { MessagePopup("Internal Error", "Window"); return -1; } //Run coresponding thread *deviceNumberTosend = deviceNumber; //init anyway sprintf(adressString, "%s", UUTAddr); viOpenDefaultRM (&defaultRM); result = viOpen(defaultRM,(ViRsrc)adressString, VI_NULL ,VI_NULL, &ssp); if(result!=0) return -1; //init of ssp protocol viSetAttribute (ssp, VI_ATTR_TERMCHAR_EN, VI_TRUE); //disable termination char viSetAttribute (ssp, VI_ATTR_TERMCHAR, 0x0A); viSetAttribute (ssp, VI_ATTR_ASRL_END_IN, VI_ASRL_END_LAST_BIT); viSetAttribute (ssp, VI_ATTR_ASRL_BAUD, 38400); viSetAttribute (ssp, VI_ATTR_ASRL_PARITY, VI_ASRL_PAR_NONE); viSetAttribute (ssp, VI_ATTR_TMO_VALUE, 25000); //TMO 15 seconds viFlush (ssp, VI_ASRL_IN_BUF_DISCARD); Sleep(1); if (!strcmp(command,"CLOSE")) //Reading { viFlush (ssp, VI_WRITE_BUF); viFlush (ssp, VI_READ_BUF); viClose(ssp); return 0; } if (!strcmp(command,"LISTEN")) //Reading { status = viScanf(ssp, "%t", &Databuf); InsertTextBoxLine(panelHandle, PANEL_TEXTBOX, debugTextBoxLine++, Databuf); //*************** Auto Scroll *********************** SetCtrlAttribute(panelHandle, PANEL_TEXTBOX, ATTR_FIRST_VISIBLE_LINE, debugTextBoxLine); //**************************************************** return 0; } viFlush (ssp, VI_WRITE_BUF); viFlush (ssp, VI_READ_BUF); viClose(ssp); return 0; }
and thread function is: this function listen to com port and writes data to textbox
int CVICALLBACK ThreadFunction(void *functionData) { while(!done) { executeCOMCommand("LISTEN", 1); } return 0; }
when i press quit button
int CVICALLBACK Quit (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: done = 1; executeCOMCommand("CLOSE", 1); QuitUserInterface (0); break; } return 0; }
the program hangs and give me general protection error , it's still check the THreadFunction and do executeCOMCommand("LISTEN", 1).
do i wrote it correctly for multithreading or i must to use something else. how i can quit program in write way.
thanks
07-04-2014 02:46 AM - edited 07-04-2014 02:47 AM
There are several points of your code that must be corrected for the application to work regularly. I'm not examining the VISA section here as it depends on external device characteristics which I don't know.
First of all, in SW_ON_OFF you must launch the thread and then exit the function. In your code the program is stuck in CmtWaitForThreadPoolFunctionCompletion, even if it processes events so the application is not hang. Nevertheless, this isn't a good approach: correct way is to launch the thread and then let it run by itself the same as the UI thread.
When you want to terminate the thread, set done = 1, next call CmtWaitForThreadPoolFunctionCompletion and only after it terminates you can dispose of system resourced with CmtReleaseThreadPoolFunctionID. The GPF error you are receiving is likely to happen since you are not guaranteed that the order of calls follows this pattern. This pattern is to be followed both on program end (Quit callback) and when you simply want to terminate interaction with the microcontroller (SW_ON_OFF function with binary switch set to off).
Last but not least, the main thread in such a pattern is the one that handles the user interface: is misleading using 'mainthreadID' as the variable name of a second thread. It seems a detail but it's not: correct names help you remember the theorical pattern that lies behind the code; in a few weeks you may be stuck in other projects and when you'll come back to this app again there is no guarantee that you'll remember the pattern (according to Murphy's law, you surely won't )
07-04-2014 07:09 AM
There also may be a problem with multithreads and using DLL,
If the thread is in the main program (example running a timer or heartbeat indicator) and the VISA communication is handled by a dll, any delay in response (long time to read data from instrument etc) within the dll causes the main program thread to appear to stop.
It may be I am doing something wrong, Hope someone else can comment on this
07-06-2014 01:04 AM
07-06-2014 01:05 AM