IoServer.c
Go to the documentation of this file.
00001 // IoServer.c
00002 //
00003 // History:
00004 // 10/12/2017: Refactor IO server into separate task
00005 /*
00006 * Software License Agreement (BSD License) 
00007 *
00008 * Copyright (c) 2013, Yaskawa America, Inc.
00009 * Copyright (c) 2017, Delft University of Technology
00010 * All rights reserved.
00011 *
00012 * Redistribution and use in binary form, with or without modification,
00013 * is permitted provided that the following conditions are met:
00014 *
00015 *       * Redistributions in binary form must reproduce the above copyright
00016 *       notice, this list of conditions and the following disclaimer in the
00017 *       documentation and/or other materials provided with the distribution.
00018 *       * Neither the name of the Yaskawa America, Inc., nor the names 
00019 *       of its contributors may be used to endorse or promote products derived
00020 *       from this software without specific prior written permission.
00021 *
00022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00023 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00026 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00027 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00028 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00029 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00030 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00031 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 * POSSIBILITY OF SUCH DAMAGE.
00033 */ 
00034 
00035 #include "MotoROS.h"
00036 
00037 //-----------------------
00038 // Function Declarations
00039 //-----------------------
00040 // Main Task: 
00041 void Ros_IoServer_StartNewConnection(Controller* controller, int sd);
00042 void Ros_IoServer_StopConnection(Controller* controller, int connectionIndex);
00043 
00044 // WaitForSimpleMsg Task:
00045 void Ros_IoServer_WaitForSimpleMsg(Controller* controller, int connectionIndex);
00046 BOOL Ros_IoServer_SimpleMsgProcess(SimpleMsg* receiveMsg, SimpleMsg* replyMsg);
00047 
00048 //-----------------------
00049 // Function implementation
00050 //-----------------------
00051 
00052 //-----------------------------------------------------------------------
00053 // Start the tasks for a new io server connection:
00054 // - WaitForSimpleMsg: Task that waits to receive new SimpleMessage
00055 //-----------------------------------------------------------------------
00056 void Ros_IoServer_StartNewConnection(Controller* controller, int sd)
00057 {
00058         int connectionIndex;
00059 
00060         printf("Starting new connection to the IO Server\r\n");
00061 
00062         //look for next available connection slot
00063         for (connectionIndex = 0; connectionIndex < MAX_IO_CONNECTIONS; connectionIndex++)
00064         {
00065                 if (controller->sdIoConnections[connectionIndex] == INVALID_SOCKET)
00066                 {
00067                         controller->sdIoConnections[connectionIndex] = sd;
00068                         break;
00069                 }
00070         }
00071         
00072         if (connectionIndex == MAX_IO_CONNECTIONS)
00073         {
00074                 puts("IO server already connected... not accepting last attempt.");
00075                 mpClose(sd);
00076                 return;
00077         }
00078 
00079         if (controller->tidIoConnections[connectionIndex] == INVALID_TASK)
00080         {
00081                 printf("Creating new task: tidIoConnections (connectionIndex = %d)\n", connectionIndex);
00082                         
00083                 //start new task for this specific connection
00084                 controller->tidIoConnections[connectionIndex] = mpCreateTask(MP_PRI_TIME_NORMAL, MP_STACK_SIZE, 
00085                                                                                         (FUNCPTR)Ros_IoServer_WaitForSimpleMsg,
00086                                                                                         (int)controller, connectionIndex, 0, 0, 0, 0, 0, 0, 0, 0);
00087         
00088                 if (controller->tidIoConnections[connectionIndex] != ERROR)
00089                 {
00090                         //set feedback signal indicating success
00091                         Ros_Controller_SetIOState(IO_FEEDBACK_IOSERVERCONNECTED, TRUE);
00092                 }
00093                 else
00094                 {
00095                         puts("Could not create new task in the IO server.  Check robot parameters.");
00096                         mpClose(sd);
00097                         controller->sdIoConnections[connectionIndex] = INVALID_SOCKET;
00098                         controller->tidIoConnections[connectionIndex] = INVALID_TASK;
00099                         Ros_Controller_SetIOState(IO_FEEDBACK_FAILURE, TRUE);
00100                         return;
00101                 }
00102         }
00103 }
00104 
00105 
00106 //-----------------------------------------------------------------------
00107 // Close a connection along with all its associated task
00108 //-----------------------------------------------------------------------
00109 void Ros_IoServer_StopConnection(Controller* controller, int connectionIndex)
00110 {   
00111         int tid;
00112         
00113         printf("Closing IO Server Connection\r\n");
00114         
00115         //close this connection
00116         mpClose(controller->sdIoConnections[connectionIndex]);
00117         //mark connection as invalid
00118         controller->sdIoConnections[connectionIndex] = INVALID_SOCKET;
00119 
00120         // Stop message receiption task
00121         tid = controller->tidIoConnections[connectionIndex];
00122         controller->tidIoConnections[connectionIndex] = INVALID_TASK;
00123         printf("IO Server Connection Closed\r\n");
00124         
00125         mpDeleteTask(tid);
00126 }
00127 
00128 int Ros_IoServer_GetExpectedByteSizeForMessageType(SimpleMsg* receiveMsg)
00129 {
00130         int minSize = sizeof(SmPrefix) + sizeof(SmHeader);
00131         int expectedSize;
00132 
00133         switch (receiveMsg->header.msgType)
00134         {
00135         case ROS_MSG_MOTO_READ_IO_BIT:
00136                 expectedSize = minSize + sizeof(SmBodyMotoReadIOBit);
00137                 break;
00138         case ROS_MSG_MOTO_WRITE_IO_BIT:
00139                 expectedSize = minSize + sizeof(SmBodyMotoWriteIOBit);
00140                 break;
00141         case ROS_MSG_MOTO_READ_IO_GROUP:
00142                 expectedSize = minSize + sizeof(SmBodyMotoReadIOGroup);
00143                 break;
00144         case ROS_MSG_MOTO_WRITE_IO_GROUP:
00145                 expectedSize = minSize + sizeof(SmBodyMotoWriteIOGroup);
00146                 break;
00147         default: //invalid message type
00148                 return -1;
00149         }
00150         return expectedSize;
00151 }
00152 
00153 //-----------------------------------------------------------------------
00154 // Checks the type of message and processes it accordingly
00155 // Return -1=Failure; 0=Success; 1=CloseConnection; 
00156 //-----------------------------------------------------------------------
00157 int Ros_IoServer_SimpleMsgProcess(SimpleMsg* receiveMsg, SimpleMsg* replyMsg)
00158 {
00159         int ret = 0;
00160         int invalidSubcode = 0;
00161 
00162         switch (receiveMsg->header.msgType)
00163         {
00164                 //-----------------------
00165         case ROS_MSG_MOTO_READ_IO_BIT:
00166                 ret = Ros_IoServer_ReadIOBit(receiveMsg, replyMsg);
00167                 break;
00168 
00169                 //-----------------------
00170         case ROS_MSG_MOTO_WRITE_IO_BIT:
00171                 ret = Ros_IoServer_WriteIOBit(receiveMsg, replyMsg);
00172                 break;
00173 
00174                 //-----------------------
00175         case ROS_MSG_MOTO_READ_IO_GROUP:
00176                 ret = Ros_IoServer_ReadIOGroup(receiveMsg, replyMsg);
00177                 break;
00178 
00179                 //-----------------------
00180         case ROS_MSG_MOTO_WRITE_IO_GROUP:
00181                 ret = Ros_IoServer_WriteIOGroup(receiveMsg, replyMsg);
00182                 break;
00183 
00184                 //-----------------------
00185         default:
00186                 printf("Invalid message type: %d\n", receiveMsg->header.msgType);
00187                 invalidSubcode = ROS_RESULT_INVALID_MSGTYPE;
00188                 break;
00189         }
00190 
00191         // Check Invalid Case
00192         if (invalidSubcode != 0)
00193         {
00194                 Ros_SimpleMsg_IoReply(ROS_RESULT_INVALID, invalidSubcode, replyMsg);
00195                 ret = -1;
00196         }
00197 
00198         return ret;
00199 }
00200 
00201 //-----------------------------------------------------------------------
00202 // Task that waits to receive new SimpleMessage and then processes it
00203 //-----------------------------------------------------------------------
00204 void Ros_IoServer_WaitForSimpleMsg(Controller* controller, int connectionIndex)
00205 {
00206         SimpleMsg receiveMsg;
00207         SimpleMsg replyMsg;
00208         int byteSize = 0, byteSizeResponse = 0;
00209         int minSize = sizeof(SmPrefix) + sizeof(SmHeader);
00210         int expectedSize;
00211         int ret = 0;
00212         BOOL bDisconnect = FALSE;
00213         int partialMsgByteCount = 0;
00214         BOOL bSkipNetworkRecv = FALSE;
00215 
00216         while(!bDisconnect) //keep accepting messages until connection closes
00217         {
00218                 Ros_Sleep(0); //allow other tasks to run, if needed
00219                 
00220                 if (!bSkipNetworkRecv)
00221                 {
00222                         if (partialMsgByteCount) //partial (incomplete) message already received
00223                         {
00224                                 //Receive message from the PC
00225                                 memset((&receiveMsg) + partialMsgByteCount, 0x00, sizeof(SimpleMsg) - partialMsgByteCount);
00226                                 byteSize = mpRecv(controller->sdIoConnections[connectionIndex], (char*)((&receiveMsg) + partialMsgByteCount), sizeof(SimpleMsg) - partialMsgByteCount, 0);
00227                                 if (byteSize <= 0)
00228                                         break; //end connection
00229 
00230                                 byteSize += partialMsgByteCount;
00231                                 partialMsgByteCount = 0;
00232                         }
00233                         else //get whole message
00234                         {
00235                                 //Receive message from the PC
00236                                 memset(&receiveMsg, 0x00, sizeof(receiveMsg));
00237                                 byteSize = mpRecv(controller->sdIoConnections[connectionIndex], (char*)(&receiveMsg), sizeof(SimpleMsg), 0);
00238                                 if (byteSize <= 0)
00239                                         break; //end connection
00240                         }
00241                 }
00242                 else
00243                 {
00244                         byteSize = partialMsgByteCount;
00245                         partialMsgByteCount = 0;
00246                         bSkipNetworkRecv = FALSE;
00247                 }
00248 
00249                 // Determine the expected size of the message
00250                 expectedSize = -1;
00251                 if (byteSize >= minSize)
00252                 {
00253                         expectedSize = Ros_IoServer_GetExpectedByteSizeForMessageType(&receiveMsg);
00254 
00255                         if (expectedSize == -1)
00256                         {
00257                                 printf("Unknown Message Received (%d)\r\n", receiveMsg.header.msgType);
00258                                 Ros_SimpleMsg_IoReply(ROS_RESULT_INVALID, ROS_RESULT_INVALID_MSGTYPE, &replyMsg);
00259                         }
00260                         else if (byteSize >= expectedSize) // Check message size
00261                         {
00262                                 // Process the simple message
00263                                 ret = Ros_IoServer_SimpleMsgProcess(&receiveMsg, &replyMsg);
00264                                 if (ret == 1) //error during processing
00265                                 {
00266                                         bDisconnect = TRUE;
00267                                 }
00268                                 else if (byteSize > expectedSize) // Received extra data in single message
00269                                 {
00270                                         // Preserve the remaining bytes and treat them as the start of a new message
00271                                         Db_Print("MessageReceived(%d bytes): expectedSize=%d, processing rest of bytes (%d, %d, %d)\r\n", byteSize, expectedSize, sizeof(receiveMsg), receiveMsg.body.jointTrajData.sequence, ((int*)((char*)&receiveMsg + expectedSize))[5]);
00272                                         partialMsgByteCount = byteSize - expectedSize;
00273                                         memmove(&receiveMsg, (char*)&receiveMsg + expectedSize, partialMsgByteCount);
00274 
00275                                         //Did I receive multiple full messages at once that all need to be processed before listening for new data?
00276                                         if (partialMsgByteCount >= minSize)
00277                                         {
00278                                                 expectedSize = Ros_IoServer_GetExpectedByteSizeForMessageType(&receiveMsg);
00279                                                 bSkipNetworkRecv = (partialMsgByteCount >= expectedSize); //does my modified receiveMsg buffer contain a full message to process?
00280                                         }
00281                                 }
00282                                 else // All good
00283                                         partialMsgByteCount = 0;
00284                         }
00285                         else // Not enough data to process the command
00286                         {
00287                                 Db_Print("MessageReceived(%d bytes): expectedSize=%d\r\n", byteSize, expectedSize);
00288                                 Ros_SimpleMsg_IoReply(ROS_RESULT_INVALID, ROS_RESULT_INVALID_MSGSIZE, &replyMsg);
00289                         }
00290                 }
00291                 else // Didn't even receive a command ID
00292                 {
00293                         Db_Print("Unknown Data Received (%d bytes)\r\n", byteSize);
00294                         Ros_SimpleMsg_IoReply(ROS_RESULT_INVALID, ROS_RESULT_INVALID_MSGSIZE, &replyMsg);
00295                 }
00296 
00297                 //Send reply message
00298                 byteSizeResponse = mpSend(controller->sdIoConnections[connectionIndex], (char*)(&replyMsg), replyMsg.prefix.length + sizeof(SmPrefix), 0);        
00299                 if (byteSizeResponse <= 0)
00300                         break;  // Close the connection
00301         }
00302         
00303         Ros_Sleep(50);  // Just in case other associated task need time to clean-up.  Don't if necessary... but it doesn't hurt
00304         
00305         //close this connection
00306         Ros_IoServer_StopConnection(controller, connectionIndex);
00307 }
00308 
00309 int Ros_IoServer_ReadIOBit(SimpleMsg* receiveMsg, SimpleMsg* replyMsg)
00310 {
00311         int apiRet;
00312         MP_IO_INFO ioReadInfo;
00313         USHORT ioValue;
00314         int resultCode;
00315 
00316         //initialize memory
00317         memset(replyMsg, 0x00, sizeof(SimpleMsg));
00318         
00319         // set prefix: length of message excluding the prefix
00320         replyMsg->prefix.length = sizeof(SmHeader) + sizeof(SmBodyMotoReadIOBitReply);
00321 
00322         // set header information of the reply
00323         replyMsg->header.msgType = ROS_MSG_MOTO_READ_IO_BIT_REPLY;
00324         replyMsg->header.commType = ROS_COMM_SERVICE_REPLY;
00325         
00326         ioReadInfo.ulAddr = receiveMsg->body.readIOBit.ioAddress;
00327         apiRet = mpReadIO(&ioReadInfo, &ioValue, 1);
00328 
00329         if (apiRet == OK)
00330                 resultCode = ROS_REPLY_SUCCESS;
00331         else
00332                 resultCode = ROS_REPLY_FAILURE;
00333 
00334         replyMsg->body.readIOBitReply.value = ioValue;
00335         replyMsg->body.readIOBitReply.resultCode = resultCode;
00336         replyMsg->header.replyType = (SmReplyType)resultCode;
00337         return OK;
00338 }
00339 
00340 int Ros_IoServer_ReadIOGroup(SimpleMsg* receiveMsg, SimpleMsg* replyMsg)
00341 {
00342         int apiRet;
00343         MP_IO_INFO ioReadInfo[8];
00344         USHORT ioValue[8];
00345         int resultCode;
00346         int resultValue = 0;
00347         int i;
00348 
00349         //initialize memory
00350         memset(replyMsg, 0x00, sizeof(SimpleMsg));
00351 
00352         // set prefix: length of message excluding the prefix
00353         replyMsg->prefix.length = sizeof(SmHeader) + sizeof(SmBodyMotoReadIOGroupReply);
00354 
00355         // set header information of the reply
00356         replyMsg->header.msgType = ROS_MSG_MOTO_READ_IO_GROUP_REPLY;
00357         replyMsg->header.commType = ROS_COMM_SERVICE_REPLY;
00358 
00359         for (i = 0; i < 8; i += 1)
00360         {
00361                 ioReadInfo[i].ulAddr = (receiveMsg->body.readIOGroup.ioAddress * 10) + i;
00362         }
00363         apiRet = mpReadIO(ioReadInfo, ioValue, 8);
00364 
00365         resultValue = 0;
00366         for (i = 0; i < 8; i += 1)
00367         {
00368                 resultValue |= (ioValue[i] << i);
00369         }
00370 
00371         if (apiRet == OK)
00372                 resultCode = ROS_REPLY_SUCCESS;
00373         else
00374                 resultCode = ROS_REPLY_FAILURE;
00375 
00376         replyMsg->body.readIOGroupReply.value = resultValue;
00377         replyMsg->body.readIOGroupReply.resultCode = resultCode;
00378         replyMsg->header.replyType = (SmReplyType)resultCode;
00379         return OK;
00380 }
00381 
00382 int Ros_IoServer_WriteIOBit(SimpleMsg* receiveMsg, SimpleMsg* replyMsg)
00383 {       
00384         int apiRet;
00385         MP_IO_DATA ioWriteData;
00386         int resultCode;
00387 
00388         //initialize memory
00389         memset(replyMsg, 0x00, sizeof(SimpleMsg));
00390         
00391         // set prefix: length of message excluding the prefix
00392         replyMsg->prefix.length = sizeof(SmHeader) + sizeof(SmBodyMotoWriteIOBitReply);
00393 
00394         // set header information of the reply
00395         replyMsg->header.msgType = ROS_MSG_MOTO_WRITE_IO_BIT_REPLY;
00396         replyMsg->header.commType = ROS_COMM_SERVICE_REPLY;
00397         
00398         ioWriteData.ulAddr = receiveMsg->body.writeIOBit.ioAddress;
00399         ioWriteData.ulValue = receiveMsg->body.writeIOBit.ioValue;
00400         apiRet = mpWriteIO(&ioWriteData, 1);
00401 
00402         if (apiRet == OK)
00403                 resultCode = ROS_REPLY_SUCCESS;
00404         else
00405                 resultCode = ROS_REPLY_FAILURE;
00406 
00407         replyMsg->body.writeIOBitReply.resultCode = resultCode;
00408         replyMsg->header.replyType = (SmReplyType)resultCode;
00409         return OK;
00410 }
00411 
00412 int Ros_IoServer_WriteIOGroup(SimpleMsg* receiveMsg, SimpleMsg* replyMsg)
00413 {
00414         int apiRet;
00415         MP_IO_DATA ioWriteData[8];
00416         int resultCode;
00417         int i;
00418 
00419         //initialize memory
00420         memset(replyMsg, 0x00, sizeof(SimpleMsg));
00421 
00422         // set prefix: length of message excluding the prefix
00423         replyMsg->prefix.length = sizeof(SmHeader) + sizeof(SmBodyMotoWriteIOGroupReply);
00424 
00425         // set header information of the reply
00426         replyMsg->header.msgType = ROS_MSG_MOTO_WRITE_IO_GROUP_REPLY;
00427         replyMsg->header.commType = ROS_COMM_SERVICE_REPLY;
00428 
00429         for (i = 0; i < 8; i += 1)
00430         {
00431                 ioWriteData[i].ulAddr = (receiveMsg->body.writeIOGroup.ioAddress * 10) + i;
00432                 ioWriteData[i].ulValue = (receiveMsg->body.writeIOGroup.ioValue & (1 << i)) >> i;
00433         }
00434         apiRet = mpWriteIO(ioWriteData, 8);
00435 
00436         if (apiRet == OK)
00437                 resultCode = ROS_REPLY_SUCCESS;
00438         else
00439                 resultCode = ROS_REPLY_FAILURE;
00440 
00441         replyMsg->body.writeIOGroupReply.resultCode = resultCode;
00442         replyMsg->header.replyType = (SmReplyType)resultCode;
00443         return OK;
00444 }


motoman_driver
Author(s): Jeremy Zoss (Southwest Research Institute)
autogenerated on Sat Jun 8 2019 19:06:57