wge100lib.c
Go to the documentation of this file.
00001 /*********************************************************************
00002 * Software License Agreement (BSD License)
00003 *
00004 *  Copyright (c) 2009, 2010 Willow Garage, Inc.
00005 *  All rights reserved.
00006 *
00007 *  Redistribution and use in source and binary forms, with or without
00008 *  modification, are permitted provided that the following conditions
00009 *  are met:
00010 *
00011 *   * Redistributions of source code must retain the above copyright
00012 *     notice, this list of conditions and the following disclaimer.
00013 *   * Redistributions in binary form must reproduce the above
00014 *     copyright notice, this list of conditions and the following
00015 *     disclaimer in the documentation and/or other materials provided
00016 *     with the distribution.
00017 *   * Neither the name of the Willow Garage nor the names of its
00018 *     contributors may be used to endorse or promote products derived
00019 *     from this software without specific prior written permission.
00020 *
00021 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 *  POSSIBILITY OF SUCH DAMAGE.
00033 *********************************************************************/
00034 
00035 #include "wge100_camera/wge100lib.h"
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <sys/time.h>
00040 #include <errno.h>
00041 #include <unistd.h>
00042 #include <stdbool.h>
00043 #include <net/if.h>
00044 #include <ifaddrs.h>
00045 
00046 #include "wge100_camera/host_netutil.h"
00047 #include "wge100_camera/ipcam_packet.h"
00048 
00050 #define STD_REPLY_TIMEOUT SEC_TO_USEC(0.2) // Should be tens of ms at least or flash writes will fail.
00051 #define STOP_REPLY_TIMEOUT SEC_TO_USEC(0.001)
00052 
00059 int wge100libVersion() {
00060   return WGE100LIB_VERSION;
00061 }
00062 
00063 
00094 int wge100FindByUrl(const char *url, IpCamList *camera, unsigned wait_us, const char **errmsg)
00095 {
00096   static const char *badprefix = "Bad URL prefix, expected name://, serial:// or any://.";
00097   static const char *multiaddress = "Multiple @-prefixed camera addresses found.";
00098   static const char *multiinterface = "Multiple #-prefixed host interfaces found.";
00099   static const char *discoverfailed = "Discover failed. The specified address or interface may be bad.";
00100   static const char *badserial = "serial:// may only be followed by an integer.";
00101   static const char *badany = "Unexpected characters after any://.";
00102   static const char *badip = "@ must be followed by a valid IP address.";
00103   static const char *nomatch = "No cameras matched the URL.";
00104   static const char *multimatch = "More than one camera matched the URL.";
00105   static const char *illegalcase = "Illegal case, this is a bug.";
00106   static const char *nomem = "malloc failed";
00107   const char *name = "name://"; int namelen = strlen(name);
00108   const char *serial = "serial://"; int seriallen = strlen(serial);
00109   const char *any = "any://"; int anylen = strlen(any);
00110   char *idstart;
00111   char *curpos;
00112   char *address = NULL;
00113   char *interface = NULL;
00114   char *copy = malloc(strlen(url) + 1);
00115   int retval = -1;
00116   int camcount = 0;
00117   int mode = 0;
00118   unsigned int serialnum = -1;
00119   IpCamList camList;
00120   IpCamList *curEntry;
00121   
00122   wge100CamListInit(&camList); // Must happen before any potential failures.
00123 
00124   if (errmsg)
00125     *errmsg = illegalcase; // If we return an error
00126 
00127   if (!copy) // malloc is above.
00128   {
00129     *errmsg = nomem;
00130     return -1;
00131   }
00132   strcpy(copy, url);
00133 
00134   // Decypher the prefix.
00135   if (!strncmp(copy, name, namelen))
00136   {
00137     idstart = copy + namelen;
00138     mode = 1;
00139   }
00140   else if (!strncmp(copy, serial, seriallen))
00141   {
00142     idstart = copy + seriallen;
00143     mode = 2;
00144   }
00145   else if (!strncmp(copy, any, anylen))
00146   {
00147     idstart = copy + anylen;
00148     mode = 3;
00149   }
00150   else
00151   {
00152     if (errmsg)
00153       *errmsg = badprefix;
00154     goto bailout;
00155   }
00156 
00157   // Find any # or @ words.
00158   for (curpos = idstart; *curpos; curpos++)
00159   {
00160     if (*curpos == '@')
00161     {
00162       if (address)
00163       {
00164         if (errmsg)
00165           *errmsg = multiaddress;
00166         goto bailout;
00167       }
00168       address = curpos + 1;
00169     }
00170     else if (*curpos == '#')
00171     {
00172       if (interface)
00173       {
00174         if (errmsg)
00175           *errmsg = multiinterface;
00176         goto bailout;
00177       }
00178       interface = curpos + 1;
00179     }
00180     else
00181       continue; // Didn't find anything, don't terminate the string.
00182     *curpos = 0;
00183   }
00184   // Now idstart, address and interface are set.
00185 
00186   if (mode == 3 && *idstart)
00187   {
00188     if (errmsg)
00189       *errmsg = badany;
00190     goto bailout;
00191   }
00192 
00193   if (mode == 2) // serial:// convert the number to integer.
00194   {
00195     char *endpos;
00196     serialnum = strtol(idstart, &endpos, 10);
00197     if (*idstart == 0 || *endpos != 0)
00198     {
00199       if (errmsg)
00200         *errmsg = badserial;
00201       goto bailout;
00202     }
00203   }
00204 
00205   // Build up a list of cameras. Only ones that are on the specified
00206   // interface (if specified), and that can reply from the specified
00207   // address (if specified) will end up in the list.
00208   if (wge100Discover(interface, &camList, address, wait_us) == -1)
00209   {
00210     if (errmsg)
00211       *errmsg = discoverfailed;
00212     goto bailout;
00213   }
00214 
00215   // Now search through the list for a match.
00216   camcount = 0;
00217   list_for_each_entry(curEntry, &(camList.list), list)
00218   {
00219     if ((mode == 1 && strcmp(idstart, curEntry->cam_name) == 0) ||
00220         (mode == 2 && serialnum == curEntry->serial) ||
00221         mode == 3)
00222     {
00223       camcount++;
00224       if (camcount > 1)
00225       {
00226         if (errmsg)
00227           *errmsg = multimatch;
00228         goto bailout;
00229       }
00230       memcpy(camera, curEntry, sizeof(IpCamList));
00231       if (address) // If an address has been specified, we fill it into the camera info.
00232       {
00233         struct in_addr ip;
00234         if (inet_aton(address, &ip))
00235         {
00236           uint8_t *ipbytes = (uint8_t *) &ip.s_addr; // Reconstruct the address, we don't want any funny stuff with the user-provided string.
00237           snprintf(camera->ip_str, sizeof(camera->ip_str), "%i.%i.%i.%i", ipbytes[0], ipbytes[1], ipbytes[2], ipbytes[3]);
00238           camera->ip = ip.s_addr;
00239         }
00240         else
00241         {
00242           if (errmsg)
00243             *errmsg = badip;
00244           goto bailout;
00245         }
00246       }
00247     }
00248   }
00249 
00250   switch (camcount)
00251   {
00252     case 1: // Found exactly one camera, we're good!
00253       retval = 0;
00254       break;
00255 
00256     case 0: // Found no cameras
00257       if (errmsg)
00258         *errmsg = nomatch;
00259       break;
00260 
00261     default:
00262       if (errmsg)
00263         *errmsg = illegalcase;
00264       break;
00265   }
00266 
00267 bailout:
00268   wge100CamListDelAll(&camList);
00269   free(copy);
00270   return retval;
00271 }
00272 
00287 int wge100StatusWait( int s, uint32_t wait_us, uint32_t *type, uint32_t *code ) {
00288   if( wge100WaitForPacket(&s, 1, PKTT_STATUS, sizeof(PacketStatus), &wait_us) != -1 && (wait_us != 0) ) {
00289     PacketStatus sPkt;
00290     if( recvfrom( s, &sPkt, sizeof(PacketStatus), 0, NULL, NULL )  == -1 ) {
00291       perror("wge100StatusWait unable to receive from socket");
00292       *type = PKT_STATUST_ERROR;
00293       *code = PKT_ERROR_SYSERR;
00294       return -1;
00295     }
00296 
00297     *type = ntohl(sPkt.status_type);
00298     *code = ntohl(sPkt.status_code);
00299     return 0;
00300   }
00301 
00302   *type = PKT_STATUST_ERROR;
00303   *code = PKT_ERROR_TIMEOUT;
00304   return 0;
00305 }
00306 
00307 
00308 static void xormem(uint8_t *dst, uint8_t *src, size_t w)
00309 {
00310   while (w--)
00311     *dst++ ^= *src++;
00312 }
00313 
00314 static int wge100DiscoverSend(const char *ifName, const char *ipAddress)
00315 {
00316   // Create and initialize a new Discover packet
00317   PacketDiscover dPkt;
00318   dPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
00319   dPkt.hdr.type = htonl(PKTT_DISCOVER);
00320   strncpy(dPkt.hdr.hrt, "DISCOVER", sizeof(dPkt.hdr.hrt));
00321 
00322   /* Create a new socket bound to a local ephemeral port, and get our local connection
00323    * info so we can request a reply back to the same socket.
00324    */
00325   int s = wge100CmdSocketCreate(ifName, &dPkt.hdr.reply_to);
00326   if(s == -1) {
00327     //perror("Unable to create socket\n");
00328     return -1;
00329   }
00330   
00333 
00334   struct in_addr newIP;
00335   if (ipAddress) // An IP was specified
00336   {
00337     inet_aton(ipAddress, &newIP);
00338     dPkt.ip_addr = newIP.s_addr;
00339   }
00340   else 
00341   {
00342     struct in_addr localip;
00343     struct in_addr netmask;
00344     wge100IpGetLocalAddr(ifName, &localip);
00345     wge100IpGetLocalNetmask(ifName, &netmask);
00346     dPkt.ip_addr = localip.s_addr ^ netmask.s_addr ^ ~0;
00347   }
00348 
00349   if( wge100SendUDPBcast(s, ifName, &dPkt,sizeof(dPkt)) == -1) {
00350     perror("Unable to send broadcast\n");
00351   }
00352 
00353   /*// For the old API
00354   if( wge100SendUDPBcast(s, ifName, &dPkt,sizeof(dPkt)-sizeof(dPkt.ip_addr)) == -1) {
00355     perror("Unable to send broadcast\n");
00356   }*/
00357 
00358   return s;
00359 }
00360 
00372 int wge100Discover(const char *ifName, IpCamList *ipCamList, const char *ipAddress, unsigned wait_us) {
00373   int retval = -1;
00374   int *s = NULL; // Sockets to receive from
00375   int numif = 1;
00376   int nums = 0; // Number of sockets to receive from
00377   int i;
00378   const char **ifNames = NULL;
00379   struct ifaddrs *ifaces = NULL;
00380   struct ifaddrs *curif;
00381   int autoif = 0;
00382 
00383   // Count the number of new cameras found
00384   int newCamCount = 0;
00385 
00386   if (!ifName || !ifName[0]) // The interface has been specified.
00387   {
00388     autoif = 1;
00389     if (getifaddrs(&ifaces))
00390     {
00391       perror("getifaddrs failed");
00392       goto err;
00393     }
00394 
00395     numif = 0;
00396     for (curif = ifaces; curif; curif = curif->ifa_next)
00397       numif++;
00398     //fprintf(stderr, "There are %i interfaces.\n", numif);
00399   }
00400 
00401   ifNames = calloc(numif, sizeof(char *));
00402   if (!ifNames)
00403   {
00404     perror("allocating interfaces memory");
00405     goto err; // Okay because nums == 0 and s and ifNames are allocated or NULL.
00406   }
00407 
00408   if (!autoif)
00409     ifNames[0] = ifName;
00410   else
00411   {
00412      for (numif = 0, curif = ifaces; curif; curif = curif->ifa_next)
00413      {
00414        //fprintf(stderr, "Adding %s to discover list.\n", curif->ifa_name);
00415        if (curif->ifa_addr && curif->ifa_addr->sa_family == AF_INET)
00416          ifNames[numif++] = curif->ifa_name;
00417     }
00418   }
00419 
00420   s = calloc(numif, sizeof(int));
00421   if (!s)
00422   {
00423     perror("allocating socket memory");
00424     goto err; // Okay because nums == 0 and s and ifNames are allocated or NULL.
00425   }
00426 
00427   for (nums = 0; nums < numif; nums++)
00428   {
00429     s[nums] = wge100DiscoverSend(ifNames[nums], ipAddress);
00430     if (s[nums] == -1)
00431     {
00432       //fprintf(stderr, "Removing interface %s.\n", ifNames[nums]);
00433       // Delete this interface as discovery has failed on it.
00434       numif--;
00435       for (i = nums; i < numif; i++)
00436       {
00437         ifNames[i] = ifNames[i+1];
00438       }
00439       nums--;
00440     }
00441   }
00442 
00443   do {
00444     // Wait in the loop for replies. wait_us is updated each time through the loop.
00445     int curs = wge100WaitForPacket(s, nums, PKTT_ANNOUNCE, sizeof(PacketAnnounce) - CAMERA_NAME_LEN - sizeof(IPAddress), &wait_us);
00446     if( curs != -1  && wait_us != 0 ) {
00447       // We've received an Announce packet, so pull it out of the receive queue
00448       PacketAnnounce aPkt;
00449       struct sockaddr_in fromaddr;
00450       fromaddr.sin_family = AF_INET;
00451       socklen_t fromlen = sizeof(fromaddr);
00452       ssize_t packet_len;
00453 
00454       packet_len = recvfrom( s[curs], &aPkt, sizeof(PacketAnnounce), 0, (struct sockaddr *) &fromaddr, &fromlen);
00455       if(packet_len == -1 ) {
00456         perror("wge100Discover unable to receive from socket");
00457         goto err;
00458       }
00459 
00460       if (packet_len != sizeof(PacketAnnounce))
00461       {
00462         //if (packet_len != sizeof(PacketAnnounce) - sizeof(aPkt.camera_name) - sizeof(IPAddress))
00463           continue; // Not a valid packet
00464         /*else // Old announce packet
00465         {
00466           bzero(aPkt.camera_name, sizeof(aPkt.camera_name));
00467           aPkt.camera_ip = fromaddr.sin_addr.s_addr;
00468         } */
00469       }
00470 
00471       // Create a new list entry and initialize it
00472       IpCamList *tmpListItem;
00473       if( (tmpListItem = (IpCamList *)malloc(sizeof(IpCamList))) == NULL ) {
00474         perror("Malloc failed");
00475         goto err;
00476       }
00477       wge100CamListInit( tmpListItem );
00478 
00479       // Initialize the new list item's data fields (byte order corrected)
00480       tmpListItem->hw_version = ntohl(aPkt.hw_version);
00481       tmpListItem->fw_version = ntohl(aPkt.fw_version);
00482       tmpListItem->ip = aPkt.camera_ip;
00483       uint8_t *ipbytes = (uint8_t *) &aPkt.camera_ip;
00484       snprintf(tmpListItem->ip_str, sizeof(tmpListItem->ip_str), "%i.%i.%i.%i", ipbytes[0], ipbytes[1], ipbytes[2], ipbytes[3]);
00485       tmpListItem->serial = ntohl(aPkt.ser_no);
00486       memcpy(&tmpListItem->mac, aPkt.mac, sizeof(aPkt.mac));
00487       memcpy(tmpListItem->cam_name, aPkt.camera_name, sizeof(aPkt.camera_name));
00488       aPkt.camera_name[sizeof(aPkt.camera_name) - 1] = 0;
00489       strncpy(tmpListItem->ifName, ifNames[curs], sizeof(tmpListItem->ifName));
00490       tmpListItem->ifName[sizeof(tmpListItem->ifName) - 1] = 0;
00491       tmpListItem->status = CamStatusDiscovered;
00492       char pcb_rev = 0x0A + (0x0000000F & ntohl(aPkt.hw_version));
00493       int hdl_rev = 0x00000FFF & (ntohl(aPkt.hw_version)>>4);
00494       snprintf(tmpListItem->hwinfo, WGE100_CAMINFO_LEN, "PCB rev %X : HDL rev %3X : FW rev %3X", pcb_rev, hdl_rev, ntohl(aPkt.fw_version));
00495 
00496       // If this camera is already in the list, we don't want to add another copy
00497       if( wge100CamListAdd( ipCamList, tmpListItem ) == CAMLIST_ADD_DUP) {
00498         free(tmpListItem);
00499       } else {
00500         wge100_debug("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", aPkt.mac[0], aPkt.mac[1], aPkt.mac[2], aPkt.mac[3], aPkt.mac[4], aPkt.mac[5]);
00501         wge100_debug("Product #%07u : Unit #%04u\n", ntohl(aPkt.product_id), ntohl(aPkt.ser_no));
00502         wge100_debug("%s\n", tmpListItem->hwinfo);
00503         newCamCount++;
00504       }
00505     }
00506   } while(wait_us > 0);
00507   retval = newCamCount;
00508 
00509 err:
00510   if (ifaces)
00511     freeifaddrs(ifaces);
00512   for (i = 0; i < nums; i++)
00513     close(s[i]);
00514   free(s);
00515   free(ifNames);
00516   return retval;
00517 }
00518 
00519 
00532 int wge100Configure( IpCamList *camInfo, const char *ipAddress, unsigned wait_us) {
00533   // Create and initialize a new Configure packet
00534   PacketConfigure cPkt;
00535 
00536   cPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
00537   cPkt.hdr.type = htonl(PKTT_CONFIGURE);
00538   cPkt.product_id = htonl(CONFIG_PRODUCT_ID);
00539   strncpy(cPkt.hdr.hrt, "CONFIGURE", sizeof(cPkt.hdr.hrt));
00540 
00541   cPkt.ser_no = htonl(camInfo->serial);
00542 
00543   // Create and send the Configure broadcast packet. It is sent broadcast
00544   // because the camera does not yet have an IP address assigned.
00545 
00546   /* Create a new socket bound to a local ephemeral port, and get our local connection
00547    * info so we can request a reply back to the same socket.
00548    */
00549   int s = wge100CmdSocketCreate(camInfo->ifName, &cPkt.hdr.reply_to);
00550   if(s == -1) {
00551     perror("wge100Configure socket creation failed");
00552     return -1;
00553   }
00554   
00555   // Figure out the IP to use, and send the packet.
00556   if (!ipAddress || !*ipAddress)
00557   {
00558     wge100_debug("No ipAddress, using %x\n", camInfo->ip);
00559     cPkt.ip_addr = camInfo->ip;
00560     
00561     if(wge100SendUDP(s, &camInfo->ip, &cPkt, sizeof(cPkt)) == -1) {
00562       wge100_debug("Unable to send packet\n");
00563       close(s);
00564       return -1;
00565     }
00566   }
00567   else
00568   {
00569     struct in_addr newIP;
00570     inet_aton(ipAddress, &newIP);
00571     cPkt.ip_addr = newIP.s_addr;
00572     wge100_debug("Using ipAddress %s -> %x iface %s\n", ipAddress, cPkt.ip_addr, camInfo->ifName);
00573     
00574     wge100_debug("Sending broadcast discover packet.\n");
00575     if(wge100SendUDPBcast(s, camInfo->ifName, &cPkt, sizeof(cPkt)) == -1) {
00576       wge100_debug("Unable to send broadcast\n");
00577       close(s);
00578       return -1;
00579     }
00580   }
00581     
00582   // 'Connect' insures we will only receive datagram replies from the camera's new IP
00583   IPAddress camIP = cPkt.ip_addr;
00584   wge100_debug("Connecting to %x.\n", camIP);
00585   if( wge100SocketConnect(s, &camIP) ) {
00586     wge100_debug("Unable to connect\n");
00587     close(s);
00588     return -1;
00589   }
00590 
00591   // Wait up to wait_us for a valid packet to be received on s
00592   do {
00593     if( wge100WaitForPacket(&s, 1, PKTT_ANNOUNCE, sizeof(PacketAnnounce) - CAMERA_NAME_LEN - sizeof(IPAddress), &wait_us) != -1  && (wait_us != 0) ) {
00594       PacketAnnounce aPkt;
00595 
00596       if( recvfrom( s, &aPkt, sizeof(PacketAnnounce), 0, NULL, NULL )  == -1 ) {
00597         perror("wge100Discover unable to receive from socket");
00598         close(s);
00599         return -1;
00600       }
00601 
00602       // Need to have a valid packet from a camera with the expected serial number
00603       if( ntohl(aPkt.ser_no) == camInfo->serial ) {
00604         camInfo->status = CamStatusConfigured;
00605         memcpy(&camInfo->ip, &cPkt.ip_addr, sizeof(IPAddress));
00606         /*// Add the IP/MAC mapping to the system ARP table
00607         if( wge100ArpAdd(camInfo) ) {
00608           close(s);
00609           return ERR_CONFIG_ARPFAIL;
00610         } */ // ARP handled by the camera except for obsolete firmware versions.
00611         break;
00612       }
00613     }
00614   } while(wait_us > 0);
00615   close(s);
00616 
00617   if(wait_us != 0) {
00618     return 0;
00619   } else {
00620     wge100_debug("Timed out.\n");
00621     return ERR_TIMEOUT;
00622   }
00623 }
00624 
00638 int wge100StartVid( const IpCamList *camInfo, const uint8_t mac[6], const char *ipAddress, uint16_t port ) {
00639   PacketVidStart vPkt;
00640 
00641   // Initialize the packet
00642   vPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
00643   vPkt.hdr.type = htonl(PKTT_VIDSTART);
00644   strncpy(vPkt.hdr.hrt, "Start Video", sizeof(vPkt.hdr.hrt));
00645 
00646 
00647   // Convert the ipAddress string into a binary value in network byte order
00648   inet_aton(ipAddress, (struct in_addr*)&vPkt.receiver.addr);
00649 
00650   // Convert the receiver port into network byte order
00651   vPkt.receiver.port = htons(port);
00652 
00653   // Copy the MAC address into the vPkt
00654   memcpy(&vPkt.receiver.mac, mac, 6);
00655 
00656   /* Create a new socket bound to a local ephemeral port, and get our local connection
00657    * info so we can request a reply back to the same socket.
00658    */
00659   int s = wge100CmdSocketCreate(camInfo->ifName, &vPkt.hdr.reply_to);
00660   if( s == -1 ) {
00661     return -1;
00662   }
00663   
00664   if(wge100SendUDP(s, &camInfo->ip, &vPkt, sizeof(vPkt)) == -1) {
00665     goto err_out;
00666   }
00667 
00668   // 'Connect' insures we will only receive datagram replies from the camera we've specified
00669   if( wge100SocketConnect(s, &camInfo->ip) ) {
00670     goto err_out;
00671   }
00672 
00673   // Wait for a status reply
00674   uint32_t type, code;
00675   if( wge100StatusWait( s, STD_REPLY_TIMEOUT, &type, &code ) == -1) {
00676     goto err_out;
00677   }
00678 
00679   close(s);
00680   if(type == PKT_STATUST_OK) {
00681     return 0;
00682   } else {
00683     wge100_debug("Error: wge100StatusWait returned status %d, code %d\n", type, code);
00684     return 1;
00685   }
00686 
00687 err_out:
00688   close(s);
00689   return -1;
00690 }
00691 
00700 int wge100StopVid( const IpCamList *camInfo ) {
00701   PacketVidStop vPkt;
00702 
00703   // Initialize the packet
00704   vPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
00705   vPkt.hdr.type = htonl(PKTT_VIDSTOP);
00706   strncpy(vPkt.hdr.hrt, "Stop Video", sizeof(vPkt.hdr.hrt));
00707 
00708   /* Create a new socket bound to a local ephemeral port, and get our local connection
00709    * info so we can request a reply back to the same socket.
00710    */
00711   int s = wge100CmdSocketCreate(camInfo->ifName, &vPkt.hdr.reply_to);
00712   if( s == -1 ) {
00713     return -1;
00714   }
00715 
00716   if(  wge100SendUDP(s, &camInfo->ip, &vPkt, sizeof(vPkt)) == -1 ) {
00717     goto err_out;
00718   }
00719 
00720   // 'Connect' insures we will only receive datagram replies from the camera we've specified
00721   if( wge100SocketConnect(s, &camInfo->ip) == -1) {
00722     goto err_out;
00723   }
00724 
00725   uint32_t type, code;
00726   if(wge100StatusWait( s, STOP_REPLY_TIMEOUT, &type, &code ) == -1) {
00727     goto err_out;
00728   }
00729 
00730   close(s);
00731   if(type == PKT_STATUST_OK) {
00732     return 0;
00733   } else {
00734     wge100_debug("Error: wge100StatusWait returned status %d, code %d\n", type, code);
00735     return 1;
00736   }
00737 
00738 err_out:
00739   close(s);
00740   return -1;
00741 }
00742 
00750 int wge100ReconfigureFPGA( IpCamList *camInfo ) {
00751   PacketReconfigureFPGA gPkt;
00752 
00753   // Initialize the packet
00754   gPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
00755   gPkt.hdr.type = htonl(PKTT_RECONFIG_FPGA);
00756   strncpy(gPkt.hdr.hrt, "ReconfigureFPGA", sizeof(gPkt.hdr.hrt));
00757 
00758   /* Create a new socket bound to a local ephemeral port, and get our local connection
00759    * info so we can request a reply back to the same socket.
00760    */
00761   int s = wge100CmdSocketCreate(camInfo->ifName, &gPkt.hdr.reply_to);
00762   if( s == -1 ) {
00763     return -1;
00764   }
00765 
00766   if(  wge100SendUDP(s, &camInfo->ip, &gPkt, sizeof(gPkt)) == -1 ) {
00767     close(s);
00768     return -1;
00769   }
00770 
00771   close(s);
00772 
00773   // Camera is no longer configured after a reset
00774   camInfo->status = CamStatusDiscovered;
00775 
00776   // There is no reply to a reset packet
00777 
00778   return 0;
00779 }
00780 
00788 int wge100Reset( IpCamList *camInfo ) {
00789   PacketReset gPkt;
00790 
00791   // Initialize the packet
00792   gPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
00793   gPkt.hdr.type = htonl(PKTT_RESET);
00794   strncpy(gPkt.hdr.hrt, "Reset", sizeof(gPkt.hdr.hrt));
00795 
00796   /* Create a new socket bound to a local ephemeral port, and get our local connection
00797    * info so we can request a reply back to the same socket.
00798    */
00799   int s = wge100CmdSocketCreate(camInfo->ifName, &gPkt.hdr.reply_to);
00800   if( s == -1 ) {
00801     return -1;
00802   }
00803 
00804   if(  wge100SendUDP(s, &camInfo->ip, &gPkt, sizeof(gPkt)) == -1 ) {
00805     close(s);
00806     return -1;
00807   }
00808 
00809 
00810   close(s);
00811 
00812   // Camera is no longer configured after a reset
00813   camInfo->status = CamStatusDiscovered;
00814 
00815   // There is no reply to a reset packet
00816 
00817   return 0;
00818 }
00819 
00832 int wge100GetTimer( const IpCamList *camInfo, uint64_t *time_us ) {
00833   PacketTimeRequest gPkt;
00834 
00835   // Initialize the packet
00836   gPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
00837   gPkt.hdr.type = htonl(PKTT_TIMEREQ);
00838   strncpy(gPkt.hdr.hrt, "Time Req", sizeof(gPkt.hdr.hrt));
00839 
00840   /* Create a new socket bound to a local ephemeral port, and get our local connection
00841    * info so we can request a reply back to the same socket.
00842    */
00843   int s = wge100CmdSocketCreate(camInfo->ifName, &gPkt.hdr.reply_to);
00844   if( s == -1 ) {
00845     return -1;
00846   }
00847 
00848   if(  wge100SendUDP(s, &camInfo->ip, &gPkt, sizeof(gPkt)) == -1 ) {
00849     close(s);
00850     return -1;
00851   }
00852 
00853   // 'Connect' insures we will only receive datagram replies from the camera we've specified
00854   if( wge100SocketConnect(s, &camInfo->ip) ) {
00855     close(s);
00856     return -1;
00857   }
00858 
00859   uint32_t wait_us = STD_REPLY_TIMEOUT;
00860   do {
00861     if( wge100WaitForPacket(&s, 1, PKTT_TIMEREPLY, sizeof(PacketTimer), &wait_us) != -1 && (wait_us != 0) ) {
00862       PacketTimer tPkt;
00863       if( recvfrom( s, &tPkt, sizeof(PacketTimer), 0, NULL, NULL )  == -1 ) {
00864         perror("GetTime unable to receive from socket");
00865         close(s);
00866         return -1;
00867       }
00868 
00869       *time_us = (uint64_t)ntohl(tPkt.ticks_hi) << 32;
00870       *time_us += ntohl(tPkt.ticks_lo);
00871 
00872       // Need to multiply final result by 1E6 to get us from sec
00873       // Try to do this to limit loss of precision without overflow
00874       // (We will overflow the 64-bit type with this approach
00875       // after the camera has been up for about 11 continuous years)
00876       //FIXME: Review this algorithm for possible improvements.
00877       *time_us *= 1000;
00878       *time_us /= (ntohl(tPkt.ticks_per_sec)/1000);
00879       //debug("Got time of %llu us since last reset\n", *time_us);
00880       close(s);
00881       return 0;
00882     }
00883   } while(wait_us > 0);
00884 
00885   wge100_debug("Timed out waiting for time value\n");
00886   close(s);
00887   return 1;
00888 }
00889 
00906 int wge100ReliableFlashRead( const IpCamList *camInfo, uint32_t address, uint8_t *pageDataOut, int *retries ) {
00907   int retval = -2;
00908 
00909   int counter = 10;
00910 
00911   if (retries == NULL)
00912     retries = &counter;
00913   for (; *retries > 0; (*retries)--)
00914   {
00915     retval = wge100FlashRead( camInfo, address, pageDataOut );
00916 
00917     if (!retval)
00918       return 0;
00919 
00920     wge100_debug("Flash read failed.");
00921   }
00922 
00923   return retval;
00924 }
00925 
00940 int wge100FlashRead( const IpCamList *camInfo, uint32_t address, uint8_t *pageDataOut ) {
00941   PacketFlashRequest rPkt;
00942 
00943   // Initialize the packet
00944   rPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
00945   rPkt.hdr.type = htonl(PKTT_FLASHREAD);
00946   if(address > FLASH_MAX_PAGENO) {
00947     return 1;
00948   }
00949 
00950   // The page portion of the address is 12-bits wide, range (bit9..bit21)
00951   rPkt.address = htonl(address<<9);
00952 
00953   strncpy(rPkt.hdr.hrt, "Flash read", sizeof(rPkt.hdr.hrt));
00954 
00955   /* Create a new socket bound to a local ephemeral port, and get our local connection
00956    * info so we can request a reply back to the same socket.
00957    */
00958   int s = wge100CmdSocketCreate(camInfo->ifName, &rPkt.hdr.reply_to);
00959   if( s == -1 ) {
00960     return -1;
00961   }
00962 
00963   if(  wge100SendUDP(s, &camInfo->ip, &rPkt, sizeof(rPkt)) == -1 ) {
00964     close(s);
00965     return -1;
00966   }
00967 
00968 
00969   // 'Connect' insures we will only receive datagram replies from the camera we've specified
00970   if( wge100SocketConnect(s, &camInfo->ip) ) {
00971     close(s);
00972     return -1;
00973   }
00974 
00975   uint32_t wait_us = STD_REPLY_TIMEOUT;
00976   do {
00977     if( wge100WaitForPacket(&s, 1, PKTT_FLASHDATA, sizeof(PacketFlashPayload), &wait_us) != -1 && (wait_us != 0) ) {
00978       PacketFlashPayload fPkt;
00979       if( recvfrom( s, &fPkt, sizeof(PacketFlashPayload), 0, NULL, NULL )  == -1 ) {
00980         perror("GetTime unable to receive from socket");
00981         close(s);
00982         return -1;
00983       }
00984 
00985       // Copy the received data into the space pointed to by pageDataOut
00986       memcpy(pageDataOut, fPkt.data, FLASH_PAGE_SIZE);
00987       close(s);
00988       return 0;
00989     }
00990   } while(wait_us > 0);
00991 
00992   wge100_debug("Timed out waiting for flash value\n");
00993   close(s);
00994   return 1;
00995 }
00996 
01014 int wge100ReliableFlashWrite( const IpCamList *camInfo, uint32_t address, const uint8_t *pageDataIn, int *retries ) {
01015   uint8_t buffer[FLASH_PAGE_SIZE];
01016   int retval = -2;
01017   int counter = 10;
01018   int first_read = 1;
01019 
01020   if (retries == NULL)
01021     retries = &counter;
01022 
01023   (*retries)++; // Don't count the first read as a retry.
01024   goto read_first; // Don't bother writing if nothing has changed.
01025   
01026   for (; *retries > 0; (*retries)--)
01027   {
01028     //printf("Trying write.\n");
01029     retval = wge100FlashWrite( camInfo, address, pageDataIn );
01030     if (retval)
01031     {
01032       wge100_debug("Failed write, retries left: %i.", *retries);
01033       //printf("Failed compare write.\n");
01034       continue;
01035     }
01036     
01037     first_read = 0;
01038 read_first:
01039     retval = wge100ReliableFlashRead( camInfo, address, buffer, retries );
01040     if (retval)
01041     {
01042       //if (!first_read)
01043       //  wge100_debug("Failed compare read.");
01044       //else
01045         //printf("First read failed.\n");
01046       //printf("Failed compare read.\n");
01047       continue;
01048     }
01049 
01050     if (!memcmp(buffer, pageDataIn, FLASH_PAGE_SIZE))
01051       return 0;
01052     //if (!first_read)
01053     //  wge100_debug("Failed compare.");
01054     //else
01055       //printf("First read mismatch.\n");
01056     //printf("Failed compare.\n");
01057     
01058     if (*retries == 0) // In case retries ran out during the read.
01059       break;
01060   }
01061 
01062   return retval;
01063 }
01064 
01077 int wge100FlashWrite( const IpCamList *camInfo, uint32_t address, const uint8_t *pageDataIn ) {
01078   PacketFlashPayload rPkt;
01079 
01080   // Initialize the packet
01081   rPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
01082   rPkt.hdr.type = htonl(PKTT_FLASHWRITE);
01083   if(address > FLASH_MAX_PAGENO) {
01084     return 1;
01085   }
01086 
01087   // The page portion of the address is 12-bits wide, range (bit9..bit21)
01088   rPkt.address = htonl(address<<9);
01089   strncpy(rPkt.hdr.hrt, "Flash write", sizeof(rPkt.hdr.hrt));
01090 
01091   memcpy(rPkt.data, pageDataIn, FLASH_PAGE_SIZE);
01092 
01093   /* Create a new socket bound to a local ephemeral port, and get our local connection
01094    * info so we can request a reply back to the same socket.
01095    */
01096   int s = wge100CmdSocketCreate(camInfo->ifName, &rPkt.hdr.reply_to);
01097   if( s == -1 ) {
01098     return -1;
01099   }
01100 
01101   if(  wge100SendUDP(s, &camInfo->ip, &rPkt, sizeof(rPkt)) == -1 ) {
01102     close(s);
01103     return -1;
01104   }
01105 
01106   // 'Connect' insures we will only receive datagram replies from the camera we've specified
01107   if( wge100SocketConnect(s, &camInfo->ip) ) {
01108     close(s);
01109     return -1;
01110   }
01111 
01112   // Wait for response - once we get an OK, we're clear to send the next page.
01113   uint32_t type, code;
01114   wge100StatusWait( s, STD_REPLY_TIMEOUT, &type, &code );
01115 
01116   close(s);
01117   if(type == PKT_STATUST_OK) {
01118     return 0;
01119   } else {
01120     wge100_debug("Error: wge100StatusWait returned status %d, code %d\n", type, code);
01121     return 1;
01122   }
01123 }
01124 
01135 int wge100TriggerControl( const IpCamList *camInfo, uint32_t triggerType ) {
01136   PacketTrigControl tPkt;
01137 
01138   // Initialize the packet
01139   tPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
01140   tPkt.hdr.type = htonl(PKTT_TRIGCTRL);
01141   tPkt.trig_state = htonl(triggerType);
01142 
01143   if(triggerType == TRIG_STATE_INTERNAL ) {
01144     strncpy(tPkt.hdr.hrt, "Int. Trigger", sizeof(tPkt.hdr.hrt));
01145   } else {
01146     strncpy(tPkt.hdr.hrt, "Ext. Trigger", sizeof(tPkt.hdr.hrt));
01147   }
01148 
01149   /* Create a new socket bound to a local ephemeral port, and get our local connection
01150    * info so we can request a reply back to the same socket.
01151    */
01152   int s = wge100CmdSocketCreate(camInfo->ifName, &tPkt.hdr.reply_to);
01153   if( s == -1 ) {
01154     return -1;
01155   }
01156 
01157   if(  wge100SendUDP(s, &camInfo->ip, &tPkt, sizeof(tPkt)) == -1 ) {
01158     close(s);
01159     return -1;
01160   }
01161 
01162   // 'Connect' insures we will only receive datagram replies from the camera we've specified
01163   if( wge100SocketConnect(s, &camInfo->ip) ) {
01164     close(s);
01165     return -1;
01166   }
01167 
01168   // Wait for response
01169   uint32_t type, code;
01170   wge100StatusWait( s, STD_REPLY_TIMEOUT, &type, &code );
01171 
01172   close(s);
01173   if(type == PKT_STATUST_OK) {
01174     return 0;
01175   } else {
01176     wge100_debug("Error: wge100StatusWait returned status %d, code %d\n", type, code);
01177     return 1;
01178   }
01179 }
01180 
01194 int wge100ConfigureBoard( const IpCamList *camInfo, uint32_t serial, MACAddress *mac ) {
01195   PacketSysConfig sPkt;
01196 
01197   // Initialize the packet
01198   sPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
01199   sPkt.hdr.type = htonl(PKTT_SYSCONFIG);
01200 
01201   strncpy(sPkt.hdr.hrt, "System Config", sizeof(sPkt.hdr.hrt));
01202   memcpy(&sPkt.mac, mac, 6);
01203   sPkt.serial = htonl(serial);
01204 
01205 
01206   /* Create a new socket bound to a local ephemeral port, and get our local connection
01207    * info so we can request a reply back to the same socket.
01208    */
01209   int s = wge100CmdSocketCreate(camInfo->ifName, &sPkt.hdr.reply_to);
01210   if( s == -1 ) {
01211     return -1;
01212   }
01213 
01214   if(  wge100SendUDP(s, &camInfo->ip, &sPkt, sizeof(sPkt)) == -1 ) {
01215     close(s);
01216     return -1;
01217   }
01218 
01219   // 'Connect' insures we will only receive datagram replies from the camera we've specified
01220   if( wge100SocketConnect(s, &camInfo->ip) ) {
01221     close(s);
01222     return -1;
01223   }
01224   // Wait for response
01225   uint32_t type, code;
01226   wge100StatusWait( s, STD_REPLY_TIMEOUT, &type, &code );
01227 
01228   close(s);
01229   if(type == PKT_STATUST_OK) {
01230     return 0;
01231   } else {
01232     wge100_debug("Error: wge100StatusWait returned status %d, code %d\n", type, code);
01233     return 1;
01234   }
01235 }
01236 
01252 int wge100ReliableSensorWrite( const IpCamList *camInfo, uint8_t reg, uint16_t data, int *retries ) {
01253   uint16_t readbackdata;
01254   int retval = -2;
01255   int counter = 10;
01256 
01257   if (retries == NULL)
01258     retries = &counter;
01259 
01260   for (; *retries > 0; (*retries)--)
01261   {
01262     retval = wge100SensorWrite( camInfo, reg, data );
01263     if (retval)
01264       continue;
01265 
01266     retval = wge100ReliableSensorRead( camInfo, reg, &readbackdata, retries );
01267     if (retval)
01268       continue;
01269 
01270     if (readbackdata == data)
01271       return 0;
01272     
01273     if (*retries == 0) // In case retries ran out during the read.
01274       retval = -2;
01275   }
01276 
01277   return retval;
01278 }
01279   
01291 int wge100SensorWrite( const IpCamList *camInfo, uint8_t reg, uint16_t data ) {
01292   PacketSensorData sPkt;
01293 
01294   // Initialize the packet
01295   sPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
01296   sPkt.hdr.type = htonl(PKTT_SENSORWR);
01297 
01298   strncpy(sPkt.hdr.hrt, "Write I2C", sizeof(sPkt.hdr.hrt));
01299   sPkt.address = reg;
01300   sPkt.data = htons(data);
01301 
01302   /* Create a new socket bound to a local ephemeral port, and get our local connection
01303    * info so we can request a reply back to the same socket.
01304    */
01305   int s = wge100CmdSocketCreate(camInfo->ifName, &sPkt.hdr.reply_to);
01306   if( s == -1 ) {
01307     return -1;
01308   }
01309 
01310   if(  wge100SendUDP(s, &camInfo->ip, &sPkt, sizeof(sPkt)) == -1 ) {
01311     close(s);
01312     return -1;
01313   }
01314 
01315   // 'Connect' insures we will only receive datagram replies from the camera we've specified
01316   if( wge100SocketConnect(s, &camInfo->ip) ) {
01317     close(s);
01318     return -1;
01319   }
01320 
01321   // Wait for response
01322   uint32_t type, code;
01323   wge100StatusWait( s, STD_REPLY_TIMEOUT, &type, &code );
01324 
01325   close(s);
01326   if(type == PKT_STATUST_OK) {
01327     return 0;
01328   } else {
01329     wge100_debug("Error: wge100StatusWait returned status %d, code %d\n", type, code);
01330     return 1;
01331   }
01332 }
01333 
01349 int wge100ReliableSensorRead( const IpCamList *camInfo, uint8_t reg, uint16_t *data, int *retries ) {
01350   int retval = -2;
01351 
01352   int counter = 10;
01353 
01354   if (retries == NULL)
01355     retries = &counter;
01356   for (; *retries > 0; (*retries)--)
01357   {
01358     retval = wge100SensorRead( camInfo, reg, data );
01359 
01360     if (!retval)
01361       return 0;
01362   }
01363 
01364   return retval;
01365 }
01366 
01378 int wge100SensorRead( const IpCamList *camInfo, uint8_t reg, uint16_t *data ) {
01379   PacketSensorRequest rPkt;
01380 
01381   // Initialize the packet
01382   rPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
01383   rPkt.hdr.type = htonl(PKTT_SENSORRD);
01384   rPkt.address = reg;
01385   strncpy(rPkt.hdr.hrt, "Read I2C", sizeof(rPkt.hdr.hrt));
01386 
01387   /* Create a new socket bound to a local ephemeral port, and get our local connection
01388    * info so we can request a reply back to the same socket.
01389    */
01390   int s = wge100CmdSocketCreate(camInfo->ifName, &rPkt.hdr.reply_to);
01391   if( s == -1 ) {
01392     return -1;
01393   }
01394 
01395   if(  wge100SendUDP(s, &camInfo->ip, &rPkt, sizeof(rPkt)) == -1 ) {
01396     close(s);
01397     return -1;
01398   }
01399 
01400   // 'Connect' insures we will only receive datagram replies from the camera we've specified
01401   if( wge100SocketConnect(s, &camInfo->ip) ) {
01402     close(s);
01403     return -1;
01404   }
01405 
01406   uint32_t wait_us = STD_REPLY_TIMEOUT;
01407   do {
01408     if( wge100WaitForPacket(&s, 1, PKTT_SENSORDATA, sizeof(PacketSensorData), &wait_us) != -1 && (wait_us != 0) ) {
01409       PacketSensorData sPkt;
01410       if( recvfrom( s, &sPkt, sizeof(PacketSensorData), 0, NULL, NULL )  == -1 ) {
01411         perror("SensorRead unable to receive from socket");
01412         close(s);
01413         return -1;
01414       }
01415 
01416       *data = ntohs(sPkt.data);
01417       close(s);
01418       return 0;
01419     }
01420   } while(wait_us > 0);
01421 
01422   wge100_debug("Timed out waiting for sensor value\n");
01423   close(s);
01424   return 1;
01425 }
01426 
01438 int wge100SensorSelect( const IpCamList *camInfo, uint8_t index, uint32_t reg ) {
01439   PacketSensorSelect sPkt;
01440 
01441   // Initialize the packet
01442   sPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
01443   sPkt.hdr.type = htonl(PKTT_SENSORSEL);
01444 
01445   strncpy(sPkt.hdr.hrt, "Select I2C", sizeof(sPkt.hdr.hrt));
01446   sPkt.index = index;
01447   sPkt.address = htonl(reg);
01448 
01449   /* Create a new socket bound to a local ephemeral port, and get our local connection
01450    * info so we can request a reply back to the same socket.
01451    */
01452   int s = wge100CmdSocketCreate(camInfo->ifName, &sPkt.hdr.reply_to);
01453   if( s == -1 ) {
01454     return -1;
01455   }
01456 
01457   if(  wge100SendUDP(s, &camInfo->ip, &sPkt, sizeof(sPkt)) == -1 ) {
01458     close(s);
01459     return -1;
01460   }
01461 
01462   // 'Connect' insures we will only receive datagram replies from the camera we've specified
01463   if( wge100SocketConnect(s, &camInfo->ip) ) {
01464     close(s);
01465     return -1;
01466   }
01467 
01468   // Wait for response
01469   uint32_t type, code;
01470   wge100StatusWait( s, STD_REPLY_TIMEOUT, &type, &code );
01471 
01472   close(s);
01473   if(type == PKT_STATUST_OK) {
01474     return 0;
01475   } else {
01476     wge100_debug("Error: wge100StatusWait returned status %d, code %d\n", type, code);
01477     return 1;
01478   }
01479 }
01480 
01491 int wge100ImagerModeSelect( const IpCamList *camInfo, uint32_t mode ) {
01492   PacketImagerMode mPkt;
01493 
01494   // Initialize the packet
01495   mPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
01496   mPkt.hdr.type = htonl(PKTT_IMGRMODE);
01497 
01498   mPkt.mode = htonl(mode);
01499 
01500   strncpy(mPkt.hdr.hrt, "Set Mode", sizeof(mPkt.hdr.hrt));
01501 
01502   /* Create a new socket bound to a local ephemeral port, and get our local connection
01503    * info so we can request a reply back to the same socket.
01504    */
01505   int s = wge100CmdSocketCreate(camInfo->ifName, &mPkt.hdr.reply_to);
01506   if( s == -1 ) {
01507     return -1;
01508   }
01509 
01510   if(  wge100SendUDP(s, &camInfo->ip, &mPkt, sizeof(mPkt)) == -1 ) {
01511     close(s);
01512     return -1;
01513   }
01514 
01515   // 'Connect' insures we will only receive datagram replies from the camera we've specified
01516   if( wge100SocketConnect(s, &camInfo->ip) ) {
01517     close(s);
01518     return -1;
01519   }
01520 
01521   // Wait for response
01522   uint32_t type, code;
01523   wge100StatusWait( s, STD_REPLY_TIMEOUT, &type, &code );
01524 
01525   close(s);
01526   if(type == PKT_STATUST_OK) {
01527     return 0;
01528   } else {
01529     wge100_debug("Error: wge100StatusWait returned status %d, code %d\n", type, code);
01530     return 1;
01531   }
01532 }
01533 
01548 int wge100ImagerSetRes( const IpCamList *camInfo, uint16_t horizontal, uint16_t vertical ) {
01549   PacketImagerSetRes rPkt;
01550 
01551   // Initialize the packet
01552   rPkt.hdr.magic_no = htonl(WG_MAGIC_NO);
01553   rPkt.hdr.type = htonl(PKTT_IMGRSETRES);
01554 
01555   rPkt.horizontal = htons(horizontal);
01556   rPkt.vertical = htons(vertical);
01557 
01558   strncpy(rPkt.hdr.hrt, "Set Res", sizeof(rPkt.hdr.hrt));
01559 
01560   /* Create a new socket bound to a local ephemeral port, and get our local connection
01561    * info so we can request a reply back to the same socket.
01562    */
01563   int s = wge100CmdSocketCreate(camInfo->ifName, &rPkt.hdr.reply_to);
01564   if( s == -1 ) {
01565     return -1;
01566   }
01567 
01568   if(  wge100SendUDP(s, &camInfo->ip, &rPkt, sizeof(rPkt)) == -1 ) {
01569     close(s);
01570     return -1;
01571   }
01572 
01573   // 'Connect' insures we will only receive datagram replies from the camera we've specified
01574   if( wge100SocketConnect(s, &camInfo->ip) ) {
01575     close(s);
01576     return -1;
01577   }
01578 
01579   // Wait for response
01580   uint32_t type, code;
01581   wge100StatusWait( s, STD_REPLY_TIMEOUT, &type, &code );
01582 
01583   close(s);
01584   if(type == PKT_STATUST_OK) {
01585     return 0;
01586   } else {
01587     wge100_debug("Error: wge100StatusWait returned status %d, code %d\n", type, code);
01588     return 1;
01589   }
01590 }
01591 
01592 #define MAX_HORIZ_RESOLUTION 752
01593 #define LINE_NUMBER_MASK 0x3FF
01594 
01595 int wge100VidReceiveSocket( int s, size_t height, size_t width, FrameHandler frameHandler, void *userData ) {
01596   /*
01597    * The default receive buffer size on a 32-bit Linux machine is only 128kB.
01598    * At a burst data rate of ~ 82.6Mbit/s in the 640x480 @30fps, this buffer will fill in ~12.6ms.
01599    * With the default Linux scheduler settings, this leaves virtually no time for any other processes
01600    * to execute before the buffer overflows. Increasing the buffer reduces the chance of lost
01601    * packets.
01602    *
01603    * The 8MB buffer here is far larger than necessary for most applications and may be reduced with
01604    * some experimentation.
01605    *
01606    * Note that the Linux system command 'sysctl -w net.core.rmem_max=8388608' must be used to enable
01607    * receive buffers larger than the kernel default.
01608    */
01609   size_t bufsize = 16*1024*1024;  // 8MB receive buffer.
01610 
01611   int i;
01612 
01613   int return_value = 0;
01614 
01615   if( setsockopt(s, SOL_SOCKET,SO_RCVBUF, &bufsize, sizeof(bufsize)) == -1) {
01616     perror("Can't set rcvbuf option");
01617     close(s);
01618     return -1;
01619   }
01620 
01621   socklen_t bufsizesize = sizeof(bufsize);
01622   if( getsockopt(s, SOL_SOCKET,SO_RCVBUF, &bufsize, &bufsizesize) == 0) {
01623     wge100_debug("Receive buffer size is: %i (%i)\n", bufsize, bufsizesize);
01624   }
01625   else
01626   {
01627     perror("Can't read receive buffer size");
01628   }
01629 
01630   // We receive data one line at a time; lines will be reassembled into this buffer as they arrive
01631   uint8_t *frame_buf;
01632   frame_buf = malloc(sizeof(uint8_t)*width*height);
01633   if(frame_buf == NULL) {
01634     perror("Can't malloc frame buffer");
01635     close(s);
01636     return -1;
01637   }
01638 
01639   // Allocate enough storage for the header as well as 'width' bytes of video data
01640   PacketVideoLine *vPkt=malloc(sizeof(PacketVideoLine));
01641   if(vPkt == NULL) {
01642     perror("Can't malloc line packet buffer");
01643     close(s);
01644     return -1;
01645   }
01646 
01647   // Flag to indicate that 'frameInfo.frame_number' has not yet been set
01648   bool firstPacket = true;
01649 
01650   // Flag to indicate the current frame is complete (either EOF received or first line of next frame received)
01651   bool frameComplete;
01652 
01653   // Flag to indicate that we have set the 'frameInfo.startTime' timeval for this frame.
01654   bool frameStartTimeSet;
01655 
01656   // Holds return code from frameHandler
01657   int handlerReturn;
01658 
01659   // Counts number of lines received in current frame
01660   uint32_t lineCount;
01661 
01662   // Points to an EOF structure for passing to frameHandler;
01663   PacketEOF *eof = NULL;
01664 
01665   // Information structure to pass to the frame handler.
01666   wge100FrameInfo frameInfo;
01667       
01668   // Keep track of where the last packet came from (to send out pings).
01669   struct sockaddr_in fromaddr;
01670 
01671   // Has the current frame had an XOR line
01672   bool has_xor;
01673 
01674   frameInfo.width = width;
01675   frameInfo.height = height;
01676 
01677   uint8_t xorline[width];
01678 
01679   do {
01680     lineCount = 0;
01681     frameComplete = false;
01682     frameStartTimeSet = false;
01683     frameInfo.lastMissingLine = -1;
01684     frameInfo.missingLines = 0;
01685     frameInfo.shortFrame = false;
01686     frameInfo.frame_number = vPkt->header.frame_number+1;
01687     // Ensure the buffer is cleared out. Makes viewing short packets less confusing; missing lines will be black.
01688     memset(frame_buf, 0, width*height);
01689     has_xor = false;
01690 
01691     // We detect a dropped EOF by unexpectedly receiving a line from the next frame before getting the EOF from this frame.
01692     // After the last frame has been processed, start a fresh frame with the expected line.
01693     if( (eof==NULL) && (firstPacket==false) ) {
01694       if(vPkt->header.line_number < height ) {
01695         memcpy(&(frame_buf[vPkt->header.line_number*width]), vPkt->data, width);
01696         lineCount++;
01697       }
01698       frameInfo.frame_number &= ~0xFFFF;
01699       frameInfo.frame_number |= vPkt->header.frame_number;
01700     }
01701 
01702     do {
01703       // Wait forever for video packets to arrive; could use select() with a timeout here if a timeout is needed
01704       struct timeval readtimeout;
01705       fd_set set;
01706       socklen_t fromaddrlen = sizeof(struct sockaddr_in);
01707       fromaddr.sin_family = AF_INET;
01708 
01709       // Wait for either a packet to be received or for timeout
01710       handlerReturn = 0;
01711       do {
01712         readtimeout.tv_sec = 1;
01713         readtimeout.tv_usec = 0;
01714 
01715         FD_ZERO(&set);
01716         FD_SET(s, &set);
01717 
01718         if( select(s+1, &set, NULL, NULL, &readtimeout) == -1 ) {
01719           perror("wge100VidReceive select failed");
01720           close(s);
01721           return -1;
01722         }
01723 
01724         // Call the frame handler with NULL to see if we should bail out. 
01725         if(! FD_ISSET(s, &set) && errno != EINTR) {
01726           wge100_debug("Select timed out. Calling handler.");
01727           handlerReturn = frameHandler(NULL, userData);
01728           if (handlerReturn)
01729             break;
01730         }
01731       } while (! FD_ISSET(s, &set));
01732 
01733       // We timed out, and the handler returned nonzero.
01734       if (handlerReturn) 
01735         break;
01736 
01737       if( recvfrom( s, vPkt, sizeof(HeaderVideoLine)+width, 0, (struct sockaddr *) &fromaddr, &fromaddrlen )  == -1 ) {
01738         perror("wge100VidReceive unable to receive from socket");
01739         break;
01740       }
01741 
01742       // Convert fields to host byte order for easier processing
01743       vPkt->header.frame_number = ntohl(vPkt->header.frame_number);
01744       vPkt->header.line_number = ntohs(vPkt->header.line_number);
01745       vPkt->header.horiz_resolution = ntohs(vPkt->header.horiz_resolution);
01746       vPkt->header.vert_resolution = ntohs(vPkt->header.vert_resolution);
01747 
01748       //debug("frame: #%i line: %i\n", vPkt->header.frame_number, 0x3FF & vPkt->header.line_number);
01749 
01750       // Check to make sure the frame number information is consistent within the packet
01751       uint16_t temp = (vPkt->header.line_number>>10) & 0x003F;
01752       if (((vPkt->header.line_number & IMAGER_MAGICLINE_MASK) == 0) && (temp != (vPkt->header.frame_number & 0x003F))) {
01753         wge100_debug("Mismatched line/frame numbers: %02X / %02X\n", temp, (vPkt->header.frame_number & 0x003F));
01754       }
01755 
01756       // Validate that the frame is the size we expected
01757       if( (vPkt->header.horiz_resolution != width) || (vPkt->header.vert_resolution != height) ) {
01758         wge100_debug("Invalid frame size received: %u x %u, expected %u x %u\n", vPkt->header.horiz_resolution, vPkt->header.vert_resolution, width, height);
01759         close(s);
01760         return 1;
01761       }
01762 
01763       // First time through we need to initialize the number of the first frame we received
01764       if(firstPacket == true) {
01765         firstPacket = false;
01766         frameInfo.frame_number = vPkt->header.frame_number;
01767       }
01768 
01769       // Store the start time for the frame.
01770       if (!frameStartTimeSet)
01771       {
01772         gettimeofday(&frameInfo.startTime, NULL);
01773         frameStartTimeSet = true;
01774       }
01775 
01776       // Check for frames that ended with an error
01777       if( (vPkt->header.line_number == IMAGER_LINENO_ERR) || 
01778           (vPkt->header.line_number == IMAGER_LINENO_OVF) ) {
01779         wge100_debug("Video error: %04X\n", vPkt->header.line_number);
01780 
01781         // In the case of these special 'error' EOF packets, there has been a serious internal camera failure
01782         // so we will abort rather than try to process the last frame.
01783         return_value = vPkt->header.line_number;
01784         break;
01785       } else if (vPkt->header.line_number == IMAGER_LINENO_ABORT) {
01786         wge100_debug("Video aborted\n");
01787         break;  //don't process last frame
01788       } else if((vPkt->header.frame_number - frameInfo.frame_number) & 0xFFFF) { // The camera only sends 16 bits of frame number
01789         // If we have received a line from the next frame, we must have missed the EOF somehow
01790         wge100_debug("Frame #%u missing EOF, got %i lines\n", frameInfo.frame_number, lineCount);
01791         frameComplete = true;
01792         // EOF was missing
01793         eof = NULL;
01794       } else if( vPkt->header.line_number == IMAGER_LINENO_XOR ) {
01795         memcpy(xorline, vPkt->data, width);
01796         has_xor = true;
01797       } else if( vPkt->header.line_number == IMAGER_LINENO_EOF ) {
01798         // This is a 'normal' (non-error) end of frame packet (line number 0x3FF)
01799         frameComplete = true;
01800 
01801         // Handle EOF data fields
01802         eof = (PacketEOF *)vPkt;
01803 
01804         // Correct to network byte order for frameHandler
01805         eof->ticks_hi = ntohl(eof->ticks_hi);
01806         eof->ticks_lo = ntohl(eof->ticks_lo);
01807         eof->ticks_per_sec = ntohl(eof->ticks_per_sec);
01808 
01809         // Correct to network byte order for frameHandler
01810         eof->i2c_valid = ntohl(eof->i2c_valid);
01811         for(i=0; i<I2C_REGS_PER_FRAME; i++) {
01812           eof->i2c[i] = ntohs(eof->i2c[i]);
01813         }
01814 
01815         if(lineCount != height) {
01816           if ((1 == (height - lineCount)) && has_xor) {
01817             wge100_debug("Restoring line %i\n", frameInfo.lastMissingLine);
01818 
01819             // reconstruct the missing line by XORing the frame's XOR line
01820             // with every *other* line in the frame.
01821             uint8_t *repair = &frame_buf[frameInfo.lastMissingLine * width];
01822             memcpy(repair, xorline, width);
01823             unsigned int y;
01824             for (y = 0; y < height; y++) {
01825               if (y != frameInfo.lastMissingLine) {
01826                 xormem(repair, &frame_buf[y * width], width);
01827               }
01828             }
01829           } else {
01830             // Flag packet as being short for the frameHandler
01831             eof->header.line_number = IMAGER_LINENO_SHORT;
01832             frameInfo.shortFrame = true;
01833             frameInfo.missingLines = height - lineCount;
01834           }
01835         }
01836         // Move to the next frame
01837 
01838       } else {
01839         // Remove extraneous frame information from the line number field
01840         vPkt->header.line_number &= LINE_NUMBER_MASK;
01841                                  
01842         if(lineCount > height)
01843         {
01844           wge100_debug("Too many lines received for frame!\n")
01845           break;
01846         }
01847 
01848         if( vPkt->header.line_number >= vPkt->header.vert_resolution ) {
01849           wge100_debug("Invalid line number received: %u (max %u)\n", vPkt->header.line_number, vPkt->header.vert_resolution);
01850           break;
01851         }
01852         if (lineCount + frameInfo.missingLines < vPkt->header.line_number)
01853         {
01854           int missedLines = vPkt->header.line_number - lineCount - frameInfo.missingLines; 
01855           frameInfo.lastMissingLine = vPkt->header.line_number - 1;
01856           wge100_debug("Frame #%i missed %i line(s) starting at %i src port %i\n", vPkt->header.frame_number, 
01857               missedLines, lineCount + frameInfo.missingLines, ntohs(fromaddr.sin_port));
01858           frameInfo.missingLines += missedLines;
01859         }
01860         memcpy(&(frame_buf[vPkt->header.line_number*width]), vPkt->data, width);
01861         lineCount++;
01862       }
01863     } while(frameComplete == false);
01864 
01865     if( frameComplete == true ) {
01866       frameInfo.frameData = frame_buf;
01867       frameInfo.eofInfo = eof;
01868       frameInfo.frame_number = frameInfo.frame_number; 
01869       handlerReturn = frameHandler(&frameInfo, userData);
01870   
01871       // Send a packet to the camera (this ensures that the switches along
01872       // the way won't time out). We could get away with doing this a lot
01873       // less often, but it is a relatively small cost.
01874       uint8_t dummy = 0xff;
01875       if( sendto( s, &dummy, sizeof(dummy), 0, (struct sockaddr *) &fromaddr, sizeof(fromaddr) )  == -1 ) {
01876         handlerReturn = -1; // Should not happen, bail out...
01877       }
01878     } else {
01879       // We wind up here if a serious error has resulted in us 'break'ing out of the loop.
01880       // We won't call frameHandler, we'll just exit directly.
01881       handlerReturn = -1;
01882     }
01883   } while( handlerReturn == 0 );
01884 
01885   close(s);
01886   return return_value;
01887 }
01888 
01889 int wge100VidReceive( const char *ifName, uint16_t port, size_t height, size_t width, FrameHandler frameHandler, void *userData ) {
01890   struct in_addr host_addr;
01891   wge100IpGetLocalAddr( ifName, &host_addr );
01892 
01893   if( frameHandler == NULL ) {
01894     wge100_debug("Invalid frame handler, aborting.\n");
01895     return 1;
01896   }
01897 
01898   wge100_debug("wge100VidReceive ready to receive on %s (%s:%u)\n", ifName, inet_ntoa(host_addr), port);
01899 
01900   int s = wge100SocketCreate( &host_addr, port );
01901   if( s == -1 ) {
01902     return -1;
01903   }
01904 
01905   return wge100VidReceiveSocket( s, height, width, frameHandler, userData);
01906 }
01907 
01908 int wge100VidReceiveAuto( IpCamList *camera, size_t height, size_t width, FrameHandler frameHandler, void *userData ) {
01909   struct sockaddr localMac;
01910   struct in_addr localIp;
01911   struct sockaddr localPort;
01912   socklen_t localPortLen;
01913   int s;
01914   int retval;
01915   int port;
01916 
01917   if ( wge100IpGetLocalAddr(camera->ifName, &localIp) != 0) {
01918     fprintf(stderr, "Unable to get local IP address for interface %s", camera->ifName);
01919     return -1;
01920   }
01921     
01922   if ( wge100EthGetLocalMac(camera->ifName, &localMac) != 0 ) {
01923     fprintf(stderr, "Unable to get local MAC address for interface %s", camera->ifName);
01924     return -1;
01925   }
01926       
01927   if( frameHandler == NULL ) {
01928     wge100_debug("Invalid frame handler, aborting.\n");
01929     return 1;
01930   }
01931 
01932   s = wge100SocketCreate( &localIp, 0 );
01933   if( s == -1 ) {
01934     return -1;
01935   }
01936 
01937   localPortLen = sizeof(localPort);
01938   if (getsockname(s, &localPort, &localPortLen) == -1)
01939   {
01940     fprintf(stderr, "Unable to get local port for socket.");
01941     close(s);
01942     return -1;
01943   }
01944   
01945   port = ntohs(((struct sockaddr_in *)&localPort)->sin_port);
01946 //  fprintf(stderr, "Streaming to port %i.\n", port);
01947 
01948   wge100_debug("wge100VidReceiveAuto ready to receive on %s (%s:%u)\n", camera->ifName, inet_ntoa(localIp), port);
01949 
01950   if ( wge100StartVid( camera, (uint8_t *)&(localMac.sa_data[0]), inet_ntoa(localIp), port) != 0 ) 
01951   {
01952     wge100_debug("Could not start camera streaming.");
01953     close (s);
01954     return -1;
01955   }
01956 
01957   retval = wge100VidReceiveSocket( s, height, width, frameHandler, userData);
01958       
01959   close(s);
01960   wge100StopVid(camera);
01961   return retval;
01962 }
01963 


wge100_camera
Author(s): Blaise Gassend, Patrick Mihelich, Eric MacIntosh, David Palchak
autogenerated on Sat Jun 8 2019 20:51:24