libmanta
A cross-platform API for the Snyderphonics Manta
MantaUSB.cpp
00001 #include "extern/hidapi/hidapi/hidapi.h"
00002 #include <cassert>
00003 #include "MantaUSB.h"
00004 #include "MantaExceptions.h"
00005 #include <cstdlib>
00006 #include <cstring>
00007 #include <wchar.h>
00008 
00009 MantaUSB::MantaUSB(void) :
00010    SerialNumber(0),
00011    DeviceHandle(NULL)
00012 {
00013    mantaList.push_back(this);
00014    MantaIndex = mantaList.size();
00015 
00016    DebugPrint("%s-%d: Manta %d initialized", __FILE__, __LINE__, MantaIndex);
00017 }
00018 
00019 MantaUSB::~MantaUSB(void)
00020 {
00021    Disconnect();
00022    mantaList.remove(this);
00023    if(mantaList.empty())
00024    {
00025       hid_exit();
00026    }
00027 }
00028 
00029 bool MantaUSB::MessageQueued(void)
00030 {
00031    return GetQueuedTxMessage() != NULL;
00032 }
00033 
00034 /************************************************************************/
00053 void MantaUSB::WriteFrame(uint8_t *frame, bool forceQueued)
00054 {
00055    int status;
00056    if(NULL == DeviceHandle)
00057    {
00058       throw(MantaNotConnectedException(this));
00059    }
00060    MantaTxQueueEntry *queuedMessage = GetQueuedTxMessage();
00061    if(queuedMessage && !forceQueued)
00062    {
00063       /* replace the queued packet payload with the new one */
00064       for(int i = 0; i < OutPacketLen; ++i)
00065       {
00066          /* the first byte of the report is the report ID (0x00) */
00067          queuedMessage->OutFrame[i+1] = frame[i];
00068       }
00069       DebugPrint("%s-%d: (WriteFrame) Queued Transfer overwritten on Manta %d",
00070             __FILE__, __LINE__, GetSerialNumber());
00071    }
00072    else
00073    {
00074       /* no transfer in progress, queue up a new one */
00075       MantaTxQueueEntry *newMessage = new MantaTxQueueEntry;
00076       newMessage->OutFrame[0] = 0;
00077       newMessage->TargetManta = this;
00078       /* the first byte of the report is the report ID (0x00) */
00079       memcpy(newMessage->OutFrame + 1, frame, OutPacketLen);
00080       txQueue.push_back(newMessage);
00081       DebugPrint("%s-%d: (WriteFrame) Transfer Queued on Manta %d",
00082             __FILE__, __LINE__, GetSerialNumber());
00083    }
00084 }
00085 
00086 /************************************************************************/
00092 bool MantaUSB::IsConnected(void)
00093 {
00094    return DeviceHandle != NULL;
00095 }
00096 
00097 /************************************************************************/
00108 void MantaUSB::Connect(int connectionSerial)
00109 {
00110 #define SERIAL_STRING_SIZE 32
00111    wchar_t serialString[SERIAL_STRING_SIZE];
00112 
00113    if(IsConnected())
00114    {
00115       return;
00116    }
00117 
00118    DebugPrint("%s-%d: Attempting to Connect to Manta %d...",
00119          __FILE__, __LINE__, connectionSerial);
00120    if(connectionSerial)
00121    {
00122       swprintf(serialString, SERIAL_STRING_SIZE, L"%d", connectionSerial);
00123       DeviceHandle = hid_open(VendorID, ProductID, serialString);
00124    }
00125    else
00126    {
00127       DeviceHandle = hid_open(VendorID, ProductID, NULL);
00128    }
00129    if(NULL == DeviceHandle)
00130       throw(MantaNotFoundException());
00131    hid_get_serial_number_string(DeviceHandle, serialString, SERIAL_STRING_SIZE);
00132    SerialNumber = wcstol(serialString, NULL, 10);
00133    hid_set_nonblocking(DeviceHandle, 1);
00134 }
00135 
00136 /************************************************************************/
00139 void MantaUSB::Disconnect(void)
00140 {
00141    if(! IsConnected())
00142    {
00143       return;
00144    }
00145 
00146    DebugPrint("%s-%d: Manta %d Disconnecting...", __FILE__, __LINE__, GetSerialNumber());
00147    hid_close(DeviceHandle);
00148    DeviceHandle = NULL;
00149 }
00150 
00151 /************************************************************************/
00164 void MantaUSB::HandleEvents(void)
00165 {
00166    list<MantaUSB *>::iterator i = mantaList.begin();
00167    /* read from each manta and trigger any events */
00168    while(mantaList.end() != i)
00169    {
00170       MantaUSB *current = *i;
00171       if(current->IsConnected())
00172       {
00173          int bytesRead;
00174          int8_t inFrame[InPacketLen];
00175 
00176          bytesRead = hid_read(current->DeviceHandle,
00177                reinterpret_cast<uint8_t *>(inFrame), InPacketLen);
00178          if(bytesRead < 0)
00179          {
00180             current->DebugPrint("%s-%d: Read error on Manta %d",
00181                   __FILE__, __LINE__, current->GetSerialNumber());
00182             throw(MantaCommunicationException(current));
00183          }
00184          else if(bytesRead)
00185          {
00186             current->FrameReceived(inFrame);
00187          }
00188       }
00189       ++i;
00190    }
00191 
00192    /* pop one item off the transmit queue and send down to its target */
00193    if(! txQueue.empty())
00194    {
00195       int bytesWritten;
00196       MantaTxQueueEntry *txMessage = txQueue.front();
00197       txQueue.pop_front();
00198       bytesWritten = hid_write(txMessage->TargetManta->DeviceHandle,
00199             txMessage->OutFrame, OutPacketLen + 1);
00200       txMessage->TargetManta->DebugPrint("%s-%d: Frame Written to Manta %d",
00201             __FILE__, __LINE__, txMessage->TargetManta->GetSerialNumber());
00202       for(int i = 0; i < 16; i += 8)
00203       {
00204          uint8_t *frame = txMessage->OutFrame + 1;
00205          txMessage->TargetManta->DebugPrint("\t\t%x %x %x %x %x %x %x %x",
00206                frame[i], frame[i+1], frame[i+2], frame[i+3], frame[i+4],
00207                frame[i+5], frame[i+6], frame[i+7]);
00208       }
00209       delete txMessage;
00210       if(bytesWritten < 0)
00211       {
00212          txMessage->TargetManta->DebugPrint("%s-%d: Write error on Manta %d",
00213                __FILE__, __LINE__, txMessage->TargetManta->GetSerialNumber());
00214          throw(MantaCommunicationException(txMessage->TargetManta));
00215       }
00216    }
00217 }
00218 
00219 /************************************************************************/
00224 int MantaUSB::GetSerialNumber(void)
00225 {
00226    /* TODO: get serial number */
00227    return SerialNumber;
00228 }
00229 
00230 MantaUSB::MantaTxQueueEntry *MantaUSB::GetQueuedTxMessage()
00231 {
00232    list<MantaTxQueueEntry *>::iterator i = txQueue.begin();
00233    /* look for the first queued message matching this manta */
00234    while(txQueue.end() != i)
00235    {
00236       if((*i)->TargetManta == this)
00237       {
00238          return *i;
00239       }
00240       ++i;
00241    }
00242    return NULL;
00243 }
00244 
00245 /* define static class members */
00246 list<MantaUSB *> MantaUSB::mantaList;
00247 list<MantaUSB::MantaTxQueueEntry *> MantaUSB::txQueue;