serial_transport_llrp.c
Go to the documentation of this file.
00001 
00009 /*
00010  * Copyright (c) 2009 ThingMagic, Inc.
00011  *
00012  * Permission is hereby granted, free of charge, to any person obtaining a copy
00013  * of this software and associated documentation files (the "Software"), to deal
00014  * in the Software without restriction, including without limitation the rights
00015  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00016  * copies of the Software, and to permit persons to whom the Software is
00017  * furnished to do so, subject to the following conditions:
00018  *
00019  * The above copyright notice and this permission notice shall be included in
00020  * all copies or substantial portions of the Software.
00021  * 
00022  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00023  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00024  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00025  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00026  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00027  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00028  * THE SOFTWARE.
00029  */
00030 #include "tm_config.h"
00031 #ifdef TMR_ENABLE_LLRP_TRANSPORT
00032 
00033 #include <errno.h>
00034 #include <netdb.h>
00035 #include <stddef.h>
00036 #include <string.h>
00037 #include <stdio.h>
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040 #include <sys/select.h>
00041 #include <sys/socket.h>
00042 
00043 #include "tm_reader.h"
00044 #include "tmr_utils.h"
00045 
00046 #define LLRP_TYPE_CLOSE_CONNECTION_RESPONSE    4
00047 #define LLRP_TYPE_CLOSE_CONNECTION            14
00048 #define LLRP_TYPE_READER_EVENT_NOTIFICATION   63
00049 #define LLRP_TYPE_CUSTOM_MESSAGE            1023
00050 
00051 #define LLRP_PARAM_READER_EVENT_NOTIFICATION_DATA  246
00052 #define LLRP_PARAM_CONNECTION_ATTEMPT_EVENT        256
00053 #define  LLRP_PARAM_CONNECTION_ATTEMPT_EVENT_SUCCESS 0
00054 #define  LLRP_PARAM_CONNECTION_ATTEMPT_EVENT_ANOTHER 4
00055 #define LLRP_PARAM_CONNECTION_CLOSE_EVENT          257
00056 #define LLRP_PARAM_LLRP_STATUS                     287
00057 #define  LLRP_STATUS_M_SUCCESS                       0
00058 
00059 #define LLRP_TM_ID 0x67ba
00060 #define LLRP_TM_TYPE_DATA_REQUEST     1
00061 #define LLRP_TM_TYPE_DATA_RESPONSE    2
00062 #define LLRP_TM_TYPE_CONTROL_REQUEST  3
00063 #define LLRP_TM_TYPE_CONTROL_RESPONSE 4
00064 #define LLRP_TM_CONTROL_POWER 1
00065 #define LLRP_TM_CONTROL_BAUD  2
00066 
00067 struct llrp_message
00068 {
00069   uint32_t len; /* Length pointed to by value, not the conventional LLRP 
00070                    length of the entire object */
00071   uint32_t id;
00072   uint8_t *value, *rawbuf;
00073   uint8_t ver;
00074   uint16_t type;
00075 };
00076 
00077 struct llrp_param
00078 {
00079   uint16_t type; 
00080   uint16_t len; /* Length pointed to by value, not the conventional LLRP 
00081                     length of the entire object */
00082   uint8_t *value;
00083 };
00084 
00085 
00086 
00087 static TMR_Status
00088 llrp_receive_message(int sockfd, struct llrp_message *message, uint8_t *buf,
00089                      uint16_t buflen, uint32_t timeout)
00090 {
00091   int ret;
00092   ssize_t msgsize, retlen;
00093   struct timeval timeo;
00094 
00095   timeo.tv_sec = timeout / 1000;
00096   timeo.tv_usec = 1000 * (timeout % 1000);
00097 
00098   ret = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
00099   if (-1 == ret)
00100   {
00101     return TMR_ERROR_COMM_ERRNO(errno);
00102   }
00103 
00104   msgsize = 0;
00105   do
00106   {
00107     retlen = recv(sockfd, buf + msgsize, buflen - msgsize, 0);
00108     if (-1 == retlen)
00109     {
00110         if (EAGAIN == errno)
00111         {
00112             return TMR_ERROR_TIMEOUT;
00113         }
00114         else
00115         {
00116             return TMR_ERROR_COMM_ERRNO(errno);
00117         }
00118     }
00119     msgsize += retlen;
00120   }
00121   while ((msgsize < 10 || msgsize < GETU32AT(buf, 2)) && msgsize < buflen);
00122 
00123   message->ver = (GETU8AT(buf, 0) >> 2) & 0x7;
00124   message->type = GETU16AT(buf, 0) & 0x3ff;
00125   message->len =  GETU32AT(buf,2) - 10;
00126   message->id =   GETU32AT(buf,6);
00127   message->rawbuf = buf;
00128   message->value = buf + 10;
00129   
00130   return TMR_SUCCESS;
00131 }
00132 
00133 static TMR_Status
00134 llrp_send_message(int sockfd, struct llrp_message *message)
00135 {
00136   uint8_t *buf;
00137   uint8_t i;
00138   uint16_t msgsize;
00139   ssize_t retlen;
00140 
00141   buf = message->rawbuf;
00142   i = 0;
00143   SETU16(buf, i, (message->ver << 10) | message->type);
00144   SETU32(buf, i, 10 + message->len);
00145   SETU32(buf, i, message->id);
00146 
00147   msgsize = 10 + message->len;
00148 
00149   while (msgsize > 0)
00150   {
00151     retlen = send(sockfd, buf, msgsize, 0);
00152     if (-1 == retlen)
00153     {
00154       return TMR_ERROR_COMM_ERRNO(errno);
00155     }
00156     buf += retlen;
00157     msgsize -= retlen;
00158   }
00159   return TMR_SUCCESS;
00160 }
00161 
00162 /*
00163  * Array containing the length of each TV-type parameter
00164  * or -1 if there is no such parameter. TV-types outside of
00165  * this array are equivalent to -1.
00166  */
00167 static int llrp_tv_param_len[] =
00168 {
00169 /* 0   1   2   3   4   5   6   7   8   9 */
00170   -1,  3,  9,  9,  9,  9,  2,  3,  3,  5,
00171    3,  3,  3, 13,  3,  3,  5,  3,  5
00172 };
00173 
00174 static TMR_Status
00175 llrp_get_param(uint8_t *buf, uint16_t buflen, uint16_t paramtype,
00176                struct llrp_param *param)
00177 {
00178   uint16_t offset, type, headersize, len;
00179 
00180   offset = 0;
00181   while (offset < buflen)
00182   {
00183     type = GETU16AT(buf, offset);
00184     if (type & 0x8000)
00185     {
00186       type = (type >> 8) & 0x7f;
00187       if (type > numberof(llrp_tv_param_len) ||
00188           -1 == llrp_tv_param_len[type])
00189       {
00190         return TMR_ERROR_LLRP;
00191       }
00192       headersize = 1;
00193       len = llrp_tv_param_len[type];
00194     }
00195     else
00196     {
00197       type = type & 0x3ff;
00198       headersize = 4;
00199       len = GETU16AT(buf, offset+2);
00200     }
00201     if (type == paramtype)
00202     {
00203       param->type = type;
00204       param->len = len - headersize;
00205       param->value = buf + offset + headersize;
00206       return TMR_SUCCESS;
00207     }
00208     offset += len;
00209   }
00210 
00211   return TMR_ERROR_NOT_FOUND;
00212 }
00213 
00214 static TMR_Status
00215 llrp_check_success(uint8_t *msgptr, uint16_t msglen)
00216 {
00217   struct llrp_param param;
00218   TMR_Status ret;
00219 
00220   ret = llrp_get_param(msgptr, msglen,
00221                        LLRP_PARAM_LLRP_STATUS, &param);
00222   if (TMR_SUCCESS != ret)
00223     return TMR_ERROR_LLRP;
00224 
00225   if (LLRP_STATUS_M_SUCCESS != GETU16AT(param.value, 0))
00226     return TMR_ERROR_LLRP; 
00228   return TMR_SUCCESS;
00229 }
00230 
00231 /* Wrap llrp_receive_message() in a loop that filters out
00232  * connection-attempt notifications, which the server can send us at
00233  * any time.
00234  */
00235 static TMR_Status
00236 llrp_receive_message_filtered(int sockfd, struct llrp_message *message,
00237                               uint8_t *buf, uint16_t buflen, uint32_t timeout)
00238 {
00239   struct llrp_param param;
00240   TMR_Status ret;
00241   uint16_t status;
00242 
00243   while (1)
00244   {
00245     ret = llrp_receive_message(sockfd, message, buf, buflen, timeout);
00246     if (TMR_SUCCESS != ret)
00247     {
00248       return ret;
00249     }
00250 
00251     if (LLRP_TYPE_READER_EVENT_NOTIFICATION != message->type)
00252       break; /* Got the message we were looking for */
00253 
00254     ret = llrp_get_param(message->value, message->len,
00255                          LLRP_PARAM_READER_EVENT_NOTIFICATION_DATA, &param);
00256     if (TMR_ERROR_NOT_FOUND == ret)
00257     {
00258       /* Not the reader event notification type we're filtering */
00259       break;
00260     }
00261     else if (TMR_SUCCESS != ret)
00262     {
00263       return ret;
00264     }
00265 
00266     ret = llrp_get_param(param.value, param.len,
00267                          LLRP_PARAM_CONNECTION_ATTEMPT_EVENT, &param);
00268     if (TMR_ERROR_NOT_FOUND == ret)
00269     {
00270       /* Not the reader event notification type we're filtering */
00271       break;
00272     }
00273     else if (TMR_SUCCESS != ret)
00274     {
00275       return ret;
00276     }
00277 
00278     status = GETU16AT(param.value, 0);
00279     if (LLRP_PARAM_CONNECTION_ATTEMPT_EVENT_ANOTHER != status)
00280     {
00281       break;
00282     }
00283   }
00284 
00285   return TMR_SUCCESS;
00286 }
00287 
00288 
00289 static TMR_Status
00290 s_open(TMR_SR_SerialTransport *this)
00291 {
00292   TMR_Status ret;
00293   TMR_SR_LlrpEapiTransportContext *context;
00294   struct llrp_message message;
00295   struct llrp_param param;
00296   uint8_t buf[270];
00297   uint16_t status;
00298 
00299   context = this->cookie;
00300 
00301   if (-1 == connect(context->socket, (struct sockaddr *)&context->addr,
00302                     context->addrlen))
00303   {
00304     return TMR_ERROR_COMM_ERRNO(errno);
00305   }
00306   
00307   ret = llrp_receive_message(context->socket, &message, buf, sizeof(buf), 0);
00308   if (TMR_SUCCESS != ret)
00309   {
00310     return ret;
00311   }
00312 
00313   if (LLRP_TYPE_READER_EVENT_NOTIFICATION != message.type)
00314   {
00315     return TMR_ERROR_LLRP;
00316   }
00317 
00318   ret = llrp_get_param(message.value, message.len,
00319                        LLRP_PARAM_READER_EVENT_NOTIFICATION_DATA, &param);
00320   if (TMR_SUCCESS != ret)
00321   {
00322     return ret;
00323   }
00324   ret = llrp_get_param(param.value, param.len,
00325                        LLRP_PARAM_CONNECTION_ATTEMPT_EVENT, &param);
00326   if (TMR_SUCCESS != ret)
00327   {
00328     return ret;
00329   }
00330 
00331   status = GETU16AT(param.value,0);
00332   if (LLRP_PARAM_CONNECTION_ATTEMPT_EVENT_SUCCESS != status)
00333   {
00334     return TMR_ERROR_LLRP;
00335   }
00336 
00337   if (true == context->powerCycleAtOpen)
00338   {
00339     ret = TMR_LlrpEapiPowerCycle(this);
00340     if (TMR_SUCCESS != ret)
00341     {
00342       return ret;
00343     }
00344   }
00345 
00346   return TMR_SUCCESS;
00347 }
00348 
00349 static TMR_Status
00350 s_sendBytes(TMR_SR_SerialTransport *this, uint32_t length, 
00351             uint8_t* bytes, const uint32_t timeoutMs)
00352 {
00353   TMR_SR_LlrpEapiTransportContext *context;
00354   struct llrp_message message;
00355   uint8_t buf[270];
00356   int i;
00357 
00358   context = this->cookie;
00359   i = 0;
00360 
00361   message.ver = 1;
00362   message.type = LLRP_TYPE_CUSTOM_MESSAGE;
00363   message.id = context->sequenceId++;
00364   message.rawbuf = buf;
00365   message.value = buf + 10;
00366 
00367   SETU32(message.value, i, LLRP_TM_ID);
00368   SETU8(message.value, i, LLRP_TM_TYPE_DATA_REQUEST);
00369   memcpy(message.value + i, bytes, length);
00370   message.len = length + i;
00371 
00372   return llrp_send_message(context->socket, &message);
00373 }
00374 
00375 static TMR_Status
00376 s_receiveBytes(TMR_SR_SerialTransport *this, uint32_t length, 
00377                uint32_t* messageLength, uint8_t* bytes, const uint32_t timeoutMs)
00378 {
00379   TMR_SR_LlrpEapiTransportContext *context;
00380   struct llrp_message message;
00381   TMR_Status ret;
00382   uint16_t copylen;
00383   uint8_t buf[270];
00384 
00385   *messageLength = 0;
00386   context = this->cookie;
00387 
00388   if (length > 255)
00389   {
00390     return TMR_ERROR_INVALID;
00391   }
00392   
00393   if (context->buflen > 0)
00394   {
00395     copylen = context->buflen;
00396     if (copylen > length)
00397     {
00398       copylen = length;
00399     }
00400     memcpy(bytes, context->buf + context->bufstart, copylen);
00401     context->buflen -= copylen;
00402     context->bufstart += copylen;
00403     bytes += copylen;
00404     *messageLength += copylen;
00405     length -= copylen;
00406   }
00407 
00408   if (length == 0)
00409   {
00410     return TMR_SUCCESS;
00411   }
00412 
00413   ret = llrp_receive_message_filtered(context->socket, &message, buf,
00414                                       sizeof(buf), timeoutMs);
00415   if (TMR_SUCCESS != ret)
00416   {
00417     return ret;
00418   }
00419 
00420   if (LLRP_TM_ID != GETU32AT(message.value, 0))
00421   {
00422     return TMR_ERROR_LLRP; /* Not for us */
00423   }
00424   if (LLRP_TM_TYPE_DATA_RESPONSE != GETU8AT(message.value, 4))
00425   {
00426     return TMR_ERROR_LLRP; /* Not the data we expected */
00427   }
00428 
00429   copylen = message.len - 5;
00430   if (copylen > length)
00431   {
00432     /* Stash the rest of the data for next time */
00433     memcpy(context->buf, message.value + 5 + length, copylen - length);
00434     context->bufstart = 0;
00435     context->buflen = copylen - length;
00436     copylen = length;
00437   }
00438   memcpy(bytes, message.value + 5, copylen);
00439 
00440   return TMR_SUCCESS;
00441 }
00442 
00443 static TMR_Status
00444 s_setBaudRate(TMR_SR_SerialTransport *this, uint32_t rate)
00445 {
00446   TMR_Status ret;
00447   TMR_SR_LlrpEapiTransportContext *context;
00448   struct llrp_message message;
00449   uint8_t buf[270];
00450   int i;
00451 
00452   context = this->cookie;
00453   i = 0;
00454 
00455   message.ver = 1;
00456   message.type = LLRP_TYPE_CUSTOM_MESSAGE;
00457   message.id = context->sequenceId++;
00458   message.rawbuf = buf;
00459   message.value = buf + 10;
00460 
00461   SETU32(message.value, i, LLRP_TM_ID);
00462   SETU8(message.value, i, LLRP_TM_TYPE_CONTROL_REQUEST);
00463   SETU16(message.value, i, LLRP_TM_CONTROL_BAUD);
00464   SETU32(message.value, i, rate);
00465 
00466   message.len = i;
00467 
00468   ret = llrp_send_message(context->socket, &message);
00469   if (TMR_SUCCESS != ret)
00470   {
00471     return ret;
00472   }
00473 
00474   ret = llrp_receive_message_filtered(context->socket, &message, buf,
00475                                       sizeof(buf), 0);
00476 
00477   if ((LLRP_TYPE_CUSTOM_MESSAGE != message.type) ||
00478       (LLRP_TM_ID != GETU32AT(message.value, 0)))
00479   {
00480     return TMR_ERROR_LLRP; /* Not for us */
00481   }
00482 
00483   if (LLRP_TM_TYPE_CONTROL_RESPONSE != GETU8AT(message.value, 4))
00484   {
00485     return TMR_ERROR_LLRP; /* Not the data we expected */
00486   }
00487 
00488   return llrp_check_success(message.value + 5, message.len - 5);
00489 }
00490 
00491 static TMR_Status
00492 s_shutdown(TMR_SR_SerialTransport *this)
00493 {
00494   TMR_Status ret;
00495   TMR_SR_LlrpEapiTransportContext *context;
00496   struct llrp_message message;
00497   uint8_t buf[270];
00498 
00499   context = this->cookie;
00500 
00501   message.ver = 1;
00502   message.type = LLRP_TYPE_CLOSE_CONNECTION;
00503   message.id = context->sequenceId++;
00504   message.rawbuf = buf;
00505   message.value = buf + 10;
00506   message.len = 0;
00507 
00508   ret = llrp_send_message(context->socket, &message);
00509   if (TMR_SUCCESS != ret)
00510   {
00511     return ret;
00512   }
00513   
00514   ret = llrp_receive_message_filtered(context->socket, &message, buf,
00515                                       sizeof(buf), 0);
00516   if (TMR_SUCCESS != ret)
00517   {
00518     return ret;
00519   }
00520 
00521   if (LLRP_TYPE_CLOSE_CONNECTION_RESPONSE != message.type)
00522   {
00523     return TMR_ERROR_LLRP; /* Not what we expected */
00524   }
00525 
00526   return llrp_check_success(message.value, message.len);
00527 }
00528 
00529 static TMR_Status
00530 s_flush(TMR_SR_SerialTransport *this)
00531 {
00532 
00533   return TMR_SUCCESS;
00534 }
00535 
00536 
00537 TMR_Status
00538 TMR_LlrpEapiPowerCycle(TMR_SR_SerialTransport *this)
00539 {
00540   TMR_Status ret;
00541   TMR_SR_LlrpEapiTransportContext *context;
00542   struct llrp_message message;
00543   uint8_t buf[270];
00544   int i;
00545 
00546   context = this->cookie;
00547   i = 0;
00548 
00549   message.ver = 1;
00550   message.type = LLRP_TYPE_CUSTOM_MESSAGE;
00551   message.id = context->sequenceId++;
00552   message.rawbuf = buf;
00553   message.value = buf + 10;
00554 
00555   SETU32(message.value, i, LLRP_TM_ID);
00556   SETU8(message.value, i, LLRP_TM_TYPE_CONTROL_REQUEST);
00557   SETU16(message.value, i, LLRP_TM_CONTROL_POWER);
00558 
00559   message.len = i;
00560 
00561   ret = llrp_send_message(context->socket, &message);
00562   if (TMR_SUCCESS != ret)
00563   {
00564     return ret;
00565   }
00566   ret = llrp_receive_message(context->socket, &message, buf, sizeof(buf), 0);
00567 
00568   if ((LLRP_TYPE_CUSTOM_MESSAGE != message.type) ||
00569       (LLRP_TM_ID != GETU32AT(message.value, 0)))
00570   {
00571     return TMR_ERROR_LLRP; /* Not for us */
00572   }
00573   if (LLRP_TM_TYPE_CONTROL_RESPONSE != GETU8AT(message.value, 4))
00574   {
00575     return TMR_ERROR_LLRP; /* Not the data we expected */
00576   }
00577 
00578   return llrp_check_success(message.value + 5, message.len - 5);
00579 }
00580 
00581 TMR_Status
00582 TMR_SR_LlrpEapiTransportInit(TMR_SR_SerialTransport *transport,
00583                              TMR_SR_LlrpEapiTransportContext *context,
00584                              const char *host, int port, bool powerCycleAtOpen)
00585 {
00586   int ret, sfd;
00587   struct addrinfo hints;
00588   struct addrinfo *result, *rp;
00589   char portnum[12];
00590 
00591   memset(&hints, 0, sizeof(struct addrinfo));
00592   hints.ai_family = AF_UNSPEC;
00593   hints.ai_socktype = SOCK_STREAM;
00594 #ifdef AI_ADDRCONFIG
00595   hints.ai_flags = AI_ADDRCONFIG;
00596 #else
00597   hints.ai_flags = 0;
00598 #endif
00599 
00600   sprintf(portnum, "%d", port);
00601   ret = getaddrinfo(host, portnum, &hints, &result);
00602   if (ret != 0)
00603   {
00604     return TMR_ERROR_NO_HOST;
00605   }
00606   
00607   for (rp = result; rp != NULL; rp = rp->ai_next)
00608   {
00609     sfd = socket(rp->ai_family, rp->ai_socktype,
00610                  rp->ai_protocol);
00611     if (-1 != sfd)
00612     {
00613       break;
00614     }
00615   }
00616 
00617   if (NULL == rp)
00618   {
00619     ret = TMR_ERROR_COMM_ERRNO(errno);
00620     goto out;
00621   }
00622 
00623   context->socket = sfd;
00624   memcpy(&context->addr, rp->ai_addr, rp->ai_addrlen);
00625   context->addrlen = rp->ai_addrlen;
00626   context->powerCycleAtOpen = powerCycleAtOpen;
00627   context->sequenceId = 1;
00628   context->bufstart = 0;
00629   context->buflen = 0;
00630 
00631   transport->cookie = context;
00632   transport->open = s_open;
00633   transport->sendBytes = s_sendBytes;
00634   transport->receiveBytes = s_receiveBytes;
00635   transport->setBaudRate = s_setBaudRate;
00636   transport->shutdown = s_shutdown;
00637   transport->flush = s_flush;
00638   ret = TMR_SUCCESS;
00639 
00640 out:
00641   freeaddrinfo(result);
00642   return ret;
00643 }
00644 
00645 #endif /* TMR_ENABLE_LLRP_TRANSPORT */


thingmagic_rfid
Author(s): Brian Bingham
autogenerated on Thu May 16 2019 03:01:24