I am writing C++ code to communicate with a Yokogawa WT3002E power analyzer over Ethernet using the TMCTL library found here: https://tmi.yokogawa.com/us/library/documents-downloads/software/tmctl/ The documentation for the API is included in that .zip file. I am using Visual Studio 2015.
I cannot figure out how to handle errors so that the code can continue pinging the device without interruption when an error occurs. The code works for normal circumstances already. The code needs to be robust enough so that if the Ethernet cable is disconnected, the device power cycles, the .exe is closed unexpectedly, or my computer shuts down unexpectedly, the code will be able to pick back up where it left off. I am running two threads. One of the threads is a pingThread, which queries “*IDN?” to the device to see if the device is still connected. The other thread actually issues the commands for what I want to monitor on the device. I am asking about pingThread because it is more simple and if I can solve the problems with it I should be able to figure out the other one.
Descriptions of user-defined functions/variables:
Specific Problem: When I remove and replace the Ethernet cable connected from the WT3002E to my network switch, depending on the timing of the event, I will often enter an Error state which does not stop once I reconnect the Ethernet cable. When I have both TmcFinish and TmcInitialize, the only thing that is able to allow the program to reset and behave normally is power cycling the device, which is not a satisfactory solution for my application. When I have only TmcFinish, communication with the device still doesn’t reconnect, but restarting my program will allow the program to work again without power cycling the device. (The specific error logs are further down.)
printError definition:
void Comms::printError(int id) {
int errorNumber = 0;
errorNumber = TmcGetLastError(id);
switch (errorNumber) {
case TMCTL_NO_ERROR: //0x00000000
printf("ERROR %x: No Error\n", errorNumber);
break;
case TMCTL_TIMEOUT:
printf("ERROR %x: Timeout\n", errorNumber);
break;
//all the other cases
}
}
excerpts from main:
int main()
{
Comms comm[MAX_DEVICES];
// Begin by initializing the system
for (int i = 0; i < MAX_DEVICES; i++) {
comm[i].isRunning = true;
}
//Assigning IP addresses:
unsigned char ipAddressTable[8][4] = {
{ 10, 0, 0, 253 }, //ipAddress 0 (change these to desired values)
{ 10, 0, 0, 252 }, //ipAddress 1
{ 10, 0, 0, 251 }, //ipAddress 2
{ 10, 0, 0, 250 }, //ipAddress 3
{ 10, 0, 0, 249 }, //ipAddress 4
{ 10, 0, 0, 248 }, //ipAddress 5
{ 10, 0, 0, 247 }, //ipAddress 6
{ 10, 0, 0, 246 }, //ipAddress 7
};
//Open communication with devices
for (int i = 0; i < MAX_DEVICES; i++) {
comm[i].ipAddress[0] = ipAddressTable[i][0];
comm[i].ipAddress[1] = ipAddressTable[i][1];
comm[i].ipAddress[2] = ipAddressTable[i][2];
comm[i].ipAddress[3] = ipAddressTable[i][3];
sprintf_s(comm[i].desc, "%d.%d.%d.%d,anonymous,", comm[i].ipAddress[0], comm[i].ipAddress[1], comm[i].ipAddress[2], comm[i].ipAddress[3]);
printf("Connecting to IP Address %d: %s\n", i, comm[i].desc);
//comm[i].status = viOpen(defaultRM, comm[i].desc, VI_NULL, VI_NULL, &comm[i].vi);
comm[i].status = TmcInitialize(TM_CTL_ETHER, comm[i].desc, &comm[i].id);
if (comm[i].status == 0) {
printf("Connection to %s successful\n", comm[i].desc);
}
else {
//if it failed to connect, keep attempting to connect
while (comm[i].status == 1) {
//printf("ERROR %x\n", TmcGetLastError(comm[i].id));
comm[i].printError(comm[i].id);
printf("Connection to %s failed, reconnecting...\n", comm[i].desc);
Sleep(3000);
comm[i].status = TmcInitialize(TM_CTL_ETHER, comm[i].desc, &comm[i].id);
if (comm[i].status == 0) {
printf("Connection to %s successful\n", comm[i].desc);
}
}
}
//Set Terminal character to LF (\n)
comm[i].status = TmcSetTerm(comm[i].id, 2, 0);
if (comm[i].status != 0) {
comm[i].printError(comm[i].id);
}
//Set Timeout to Infinite
comm[i].status = TmcSetTimeout(comm[i].id, 0);
if (comm[i].status != 0) {
comm[i].printError(comm[i].id);
}
//Set Remote Mode to On
comm[i].status = TmcSetRen(comm[i].id, 1);
if (comm[i].status != 0) {
comm[i].printError(comm[i].id);
}
}
//create threads and mutexes, including pingThread, then close them at the end of the program (not shown)
} //end of main
pingThread (where I need help):
unsigned int __stdcall pingThread(void * data)
{
Comms * pComm = (Comms *)data; //pointer to objects of type Comms
printf("pingThread Created: %d\n", GetCurrentThreadId());
while (pComm->isRunning == true) {
Sleep(5000);
WaitForSingleObject(ghMutex[0], INFINITE);
//ping fxn:
updateTimingStats(pComm->pPingTime);
//Ask Device for Identification:
pComm->status = TmcSend(pComm->id, "*IDN?\n");
pComm->pingWTries++;
if (pComm->status != 0) { //write fail
// something went wrong, so close this handle and clear it from our cache
pComm->pingWFails++;
//Print Error Message
printf("TmcSend: ");
pComm->printError(pComm->id);
pComm->status = TmcFinish(pComm->id);
if (pComm->status != 0) {
printf("pingWrite TmcFinish: ");
pComm->printError(pComm->id);
}
pComm->status = TmcInitialize(TM_CTL_ETHER, pComm->desc, &pComm->id);
if (pComm->status != 0) {
printf("pingWrite TmcInitialize: ");
pComm->printError(pComm->id);
}
}
else { //write success
pComm->pingWResponses++;
//Clear buffer and read the response:
memset(pComm->buf, 0, sizeof(pComm->buf));
pComm->status = TmcReceive(pComm->id, pComm->buf, sizeof(pComm->buf), &pComm->rlen);
pComm->pingRTries++;
if (pComm->status == 0) { //read success
printf("Connected to: %s\n", pComm->buf);
pComm->isConnected = true;
pComm->pingRResponses++;
//calculate time taken for RTT
updateTimingStats(pComm->pPingTime);
printf("pingThread Round Trip Time: %I64d us\n", pComm->pPingTime->usLast);
}
else { //read fail
pComm->isConnected = false;
pComm->pingRFails++;
printf("TmcReceive: ");
pComm->printError(pComm->id);
pComm->status = TmcFinish(pComm->id); //This part works fine
if (pComm->status != 0) {
printf("TmcFinish: ");
pComm->printError(pComm->id);
}
pComm->status = TmcInitialize(TM_CTL_ETHER, pComm->desc, &pComm->id); //Can not re-establish communication after TmcFinish.
if (pComm->status != 0) {
printf("TmcInit: ");
pComm->printError(pComm->id);
}
} //end of else (read fail)
} //end of else (write success)
ReleaseMutex(ghMutex[0]);
} //end of while
I have tried multiple things for the case when TmcSend fails without success. Here are my results:
TmcFinish & TmcInitialize after TmcSend Fail:
Only TmcFinish After TmcSend Fail:
No TmcFinish & TmcInitialize in TmcSend Fail:
User contributions licensed under CC BY-SA 3.0