INOS code
The following INCO function (MoveXAxis) "just" puts a message into the tasks message queue. Later, when the message will be 'dispatched' by the task, it'll actually perform an axis Move (iMoveXAxis). The function does finally add the current axis position as a result to the message object or returns the INOS_MCMSG_CODE_MYMODULE_MOVEXAXIS_FAILED application error if the move failed. Therefore, the PC code can get this result and thereby be informed about the current axis position.
CMcResult CMyModule::MoveXAxisReturnTargetPosition(double arAxisPosition)
{
CINOSTaskExMsg* msg = new CINOSTaskExMsg(eMsgCmd, CmdMoveXAxisReturnTargetPosition, apSync);
msg->AddParam(arAxisPosition);
return PutMsg(msg);
}
void CMyModule::iMoveXAxisReturnTargetPosition(CINOSTaskExMsg* apMsg)
{
real64 rAxisPosition = apMsg->GetParam<real64>();
...
if( pAxis->Move(rAxisPosition, DF_INOS_SYNCHRONOUS) == 0 ) {
apMsg->AddResult(pAxis->GetActPosition());
MsgDone(apMsg);
} else {
MsgDone(apMsg, CINOSTaskEx::eRplError, INOS_MCMSG_CODE_MYMODULE_MOVEXAXISRETURNTARGETPOSITION_FAILED);
}
}
PC code
Correct usage
- Using CallProcedureExSync() is fine because we know that the function returns exactly one result:
double dTargetPosition = 0.0;
uint32 uError =
CallProcedureExSync(
"TargetName",
"PathToProcedure.MoveAxisReturnTargetPosition(0.1234:d)", &dTargetPosition);
cout << "Move successfully finished. Current axis position: " << dTargetPosition << endl;
} else {
...
}
- Same as above, but using the 'type safe' version of getting the result:
double dTargetPosition = 0.0;
uint32 uError =
CallProcedureExSync(
"TargetName",
"PathToProcedure.MoveAxisReturnTargetPosition(0.1234:d)",
cout << "Move successfully finished. Current axis position: " << dTargetPosition << endl;
} else {
...
}
- Start the move and get the result later:
int32 iTicketOrError =
CallProcedureEx(
"TargetName",
"PathToProcedure.MoveAxisReturnTargetPosition(0.1234:d)");
if( iTicketOrError < 0 ) {
...
double dTargetPosition = 0.0;
cout << "Move successfully finished. Current axis position: " << dTargetPosition << endl;
} else {
...
}
}
- Same as above, but using the 'type safe' version of getting the result:
int32 iTicketOrError =
CallProcedureEx(
"TargetName",
"PathToProcedure.MoveAxisReturnTargetPosition(0.1234:d)");
if( iTicketOrError < 0 ) {
...
double dTargetPosition = 0.0;
cout << "Move successfully finished. Current axis position: " << dTargetPosition << endl;
} else {
...
}
}
- Start move and check whether moving the axis succeeded or failed - wait for the 'async part' to complete using a timeout:
int32 uTimeoutMs = 5000;
int32 iTicketOrError =
CallProcedureEx(
"TargetName",
"PathToProcedure.MoveAxisReturnTargetPosition(0.1234:d)");
if( iTicketOrError < 0 ) {
double dTargetPosition = 0.0;
cout << "Move successfully finished. Current axis position: " << dTargetPosition << endl;
} else {
...
}
}
}
- Start move and check whether moving the axis succeeded or failed - wait for the 'async part' to complete by 'polling':
int32 iTicketOrError =
CallProcedureEx(
"TargetName",
"PathToProcedure.MoveAxisReturnTargetPosition(0.1234:d)");
do {
...
double dTargetPosition;
cout << "Move successfully finished. Current axis position: " << dTargetPosition << endl;
} else {
...
}
}
Strange (but valid) usage
- Start move but don't wait for any result (fire'n'forget):
int32 iTicketOrError =
CallProcedureEx(
"TargetName",
"PathToProcedure.MoveAxisReturnTargetPosition(0.1234:d)");
if( iTicketOrError > 0 ) {
}
This use case is considered "strange" because it would be more obvious to use return type 'void' for "fire'n'forget" functions. This means it would be better to use
void CMyModule::MoveXAxisReturnTargetPosition(double arAxisPosition)
...
When too many calls like this are done, the results that were sent by the target but never picked up by the application accumulate in libinco_32 and will eventually fill up the buffer used to store them. When that happens, to avoid unbounded memory usage, libinco_32 will start to drop the oldest stored results to make space for new ones when they arrive. This is accompanied by a warning printed to stderr.
- Start move and wait until the move finished (either successfully or with error). Doing this without actually checking whether it succeeded or failed:
int32 iTicketOrError =
CallProcedureEx(
"TargetName",
"PathToProcedure.MoveAxisReturnTargetPosition(0.1234:d)");
if( iTicketOrError < 0 ) {
cout << "Move completed (success or with failure)" << endl;
}
} else {
}
This use case is considered to be "strange" because an application should usually not ignore errors. If the application intends to call a "fire'n'forget" function, then it probably be better to have a INOS function that does not return any tickets. But then, of course, the PC part would not be able to wait for the completion of the 'async part' anymore.
Forbidden/invalid usage
- It's not possible to get the same result multiple times. Therefore, in the following use case, the second call to CallProcedureExResult will for sure return an error:
int32 iTicketOrError =
CallProcedureEx(
"TargetName",
"PathToProcedure.MoveAxisReturnTargetPosition(0.1234:d)");
if( iTicketOrError < 0 ) {
double dTargetPosition = 0.0;
uint32 uError;
}