controller.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       controller.cc
00003 ///             High level Barry API class
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include "controller.h"
00023 #include "probe.h"
00024 #include "common.h"
00025 #include "protocol.h"
00026 #include "protostructs.h"
00027 #include "data.h"
00028 #include "endian.h"
00029 #include "platform.h"
00030 #include <string.h>
00031 
00032 #define __DEBUG_MODE__
00033 #include "debug.h"
00034 
00035 namespace Barry {
00036 
00037 //
00038 // Controller constructor
00039 //
00040 /// Constructor for the Controller class.  Requires a valid ProbeResult
00041 /// object to find the USB device to talk to.
00042 ///
00043 /// \param[in]  device          One of the ProbeResult objects from the
00044 ///                             Probe class.
00045 /// \param[in]  default_timeout Override Usb::Device's default timeout
00046 ///
00047 Controller::Controller(const ProbeResult &device,
00048                         int default_timeout)
00049         : m_result(device)
00050         , m_dev(device.m_dev, default_timeout)
00051         , m_iface(0)
00052         , m_pin(device.m_pin)
00053         , m_zero(m_dev, device.m_ep.write, device.m_ep.read, device.m_zeroSocketSequence)
00054         , m_queue(0)
00055 {
00056         dout("Controller: Using non-threaded sockets");
00057         SetupUsb(device);
00058 }
00059 
00060 //
00061 // Controller constructor
00062 //
00063 /// Constructor for the Controller class.  Requires a valid ProbeResult
00064 /// object to find the USB device to talk to.
00065 ///
00066 /// \param[in]  device          One of the ProbeResult objects from the
00067 ///                             Probe class.
00068 /// \param[in]  queue           Plugin router object for reading data
00069 ///                             from sockets.
00070 /// \param[in]  default_timeout Override Usb::Device's default timeout
00071 ///
00072 Controller::Controller(const ProbeResult &device,
00073                         SocketRoutingQueue &queue,
00074                         int default_timeout)
00075         : m_result(device)
00076         , m_dev(device.m_dev, default_timeout)
00077         , m_iface(0)
00078         , m_pin(device.m_pin)
00079         , m_zero(queue, device.m_ep.write, device.m_zeroSocketSequence)
00080         , m_queue(&queue)
00081 {
00082         dout("Controller: Using threaded socket router");
00083 
00084         SetupUsb(device);
00085 
00086         // set the queue to use our device
00087         queue.SetUsbDevice(&m_dev, device.m_ep.write, device.m_ep.read);
00088 }
00089 
00090 void Controller::SetupUsb(const ProbeResult &device)
00091 {
00092         unsigned char cfg;
00093         if( !m_dev.GetConfiguration(cfg) )
00094                 throw Usb::Error(m_dev.GetLastError(),
00095                         "Controller: GetConfiguration failed");
00096 
00097         if( cfg != BLACKBERRY_CONFIGURATION || MUST_SET_CONFIGURATION ) {
00098                 if( !m_dev.SetConfiguration(BLACKBERRY_CONFIGURATION) )
00099                         throw Usb::Error(m_dev.GetLastError(),
00100                                 "Controller: SetConfiguration failed");
00101         }
00102 
00103         m_iface = new Usb::Interface(m_dev, device.m_interface);
00104 
00105         if( device.m_needSetAltInterface ) {
00106                 m_dev.SetAltInterface(device.m_interface);
00107         }
00108 
00109         if( device.m_needClearHalt ) {
00110                 m_dev.ClearHalt(device.m_ep.read);
00111                 m_dev.ClearHalt(device.m_ep.write);
00112         }
00113 }
00114 
00115 Controller::~Controller()
00116 {
00117 //      // trap exceptions in the destructor
00118 //      try {
00119 //              // a non-default socket has been opened, close it
00120 //              m_socket.Close();
00121 //      }
00122 //      catch( std::runtime_error &re ) {
00123 //              // do nothing... log it?
00124 //              dout("Exception caught in ~Socket: " << re.what());
00125 //      }
00126 
00127         // detach the router from our device
00128         if( m_queue ) {
00129                 m_queue->ClearUsbDevice();
00130                 m_queue = 0;
00131         }
00132 
00133         // cleanup the interface
00134         delete m_iface;
00135 
00136         // this happens when for some reason the Desktop mode
00137         // is not fully opened, but the device has already recommended
00138         // a socket to open... in this case, reset the device
00139         // in the hopes that on next open, it will be in a
00140         // recognizable state.
00141         //
00142         // FIXME - this should not be necessary, and someday we
00143         // we should figure out how to handle the "already open"
00144         // response we get for the Desktop
00145         //
00146         // FIXME - halfOpen now seems to be handled in the Socket class...
00147         // perhaps move this there if needed
00148         //
00149 /*
00150         if( m_halfOpen ) {
00151                 dout("Controller object destroyed in halfopen state, resetting device");
00152                 m_dev.Reset();
00153         }
00154 */
00155 }
00156 
00157 ///////////////////////////////////////////////////////////////////////////////
00158 // protected members
00159 
00160 //
00161 // Tells device which mode is desired, and returns the suggested
00162 // socket ID to use for that mode.
00163 //
00164 uint16_t Controller::SelectMode(ModeType mode)
00165 {
00166         return SelectMode(mode, NULL);
00167 }
00168 //
00169 // Tells device which mode is desired, and returns the suggested
00170 // socket ID to use for that mode.
00171 //
00172 // If explicitModeName is not NULL then it will be used as the mode name.
00173 // Otherwise the default mode name for the given mode will be used.
00174 // It should be a nul terminated string if it is provided.
00175 //
00176 // The RawChannel mode requires an explicitModeName to be specified.
00177 //
00178 uint16_t Controller::SelectMode(ModeType mode, const char *explicitModeName)
00179 {
00180         // select mode
00181         Protocol::Packet packet;
00182         packet.socket = 0;
00183         packet.size = htobs(SB_MODE_PACKET_COMMAND_SIZE);
00184         packet.command = SB_COMMAND_SELECT_MODE;
00185         packet.u.socket.socket = htobs(SB_MODE_REQUEST_SOCKET);
00186         packet.u.socket.sequence = 0; // updated by Socket::Send()
00187         memset(packet.u.socket.u.mode.name, 0, sizeof(packet.u.socket.u.mode.name));
00188 
00189         char *modeName = (char *) packet.u.socket.u.mode.name;
00190 
00191         if( explicitModeName ) {
00192                 if( strlen(explicitModeName) >= sizeof(packet.u.socket.u.mode.name) ) {
00193                         throw std::logic_error("Controller: explicit mode name too long");
00194                 }
00195                 strcpy(modeName, explicitModeName);
00196         }
00197         else {
00198                 // No modeName given, use the default
00199                 switch( mode )
00200                 {
00201                 case Bypass:
00202                         strcpy(modeName, "RIM Bypass");
00203                         break;
00204 
00205                 case Desktop:
00206                         strcpy(modeName, "RIM Desktop");
00207                         break;
00208 
00209                 case JavaLoader:
00210                         strcpy(modeName, "RIM_JavaLoader");
00211                         break;
00212 
00213                 case JVMDebug:
00214                         strcpy(modeName, "RIM_JVMDebug");
00215                         break;
00216 
00217                 case UsbSerData:
00218                         strcpy(modeName, "RIM_UsbSerData");
00219                         break;
00220 
00221                 case UsbSerCtrl:
00222                         strcpy(modeName, "RIM_UsbSerCtrl");
00223                         break;
00224 
00225                 case RawChannel:
00226                         throw std::logic_error("Controller: No channel name given with RawChannel mode");
00227                         break;
00228 
00229                 default:
00230                         throw std::logic_error("Controller: Invalid mode in SelectMode");
00231                         break;
00232                 }
00233         }
00234 
00235         // send mode command before we open, as a default socket is socket 0
00236         Data command(&packet, btohs(packet.size));
00237         Data response;
00238 
00239         try {
00240                 m_zero.Send(command, response);
00241 
00242                 // get the data socket number
00243                 // indicates the socket number that
00244                 // should be used below in the Open() call
00245                 MAKE_PACKET(modepack, response);
00246                 if( modepack->command == SB_COMMAND_MODE_NOT_SELECTED ) {
00247                         throw Error("Controller: requested mode not supported");
00248                 }
00249                 if( modepack->command != SB_COMMAND_MODE_SELECTED ) {
00250                         eeout(command, response);
00251                         throw Error("Controller: mode not selected");
00252                 }
00253 
00254                 if( mode == Desktop ) {
00255                         // On the BlackBerry Storm, I have to read a packet
00256                         // after opening a socket. (only for Desktop mode)
00257                         // Otherwise, barrybackup and opensync-plugin can crash (timeout)
00258                         // I don't know why ! Maybe a bug on the handheld.
00259                         m_zero.HideSequencePacket(false);
00260                         m_zero.Receive(response);
00261                         m_zero.HideSequencePacket(true);
00262                 }
00263                 // return the socket that the device is expecting us to use
00264                 return btohs(modepack->u.socket.socket);
00265         }
00266         catch( Usb::Error & ) {
00267                 eout("Controller: error setting desktop mode");
00268                 eeout(command, response);
00269                 throw;
00270         }
00271 }
00272 
00273 
00274 ///////////////////////////////////////////////////////////////////////////////
00275 // public API
00276 
00277 
00278 } // namespace Barry
00279 

Generated on Tue Mar 1 17:50:15 2011 for Barry by  doxygen 1.5.6