Updating text, names and comments to be consistent and generally make a bit more...
[barry.git] / src / controller.cc
blobd15dd1aa0e3a14161dfb9aaf4f83354dd076b0a2
1 ///
2 /// \file controller.cc
3 /// High level Barry API class
4 ///
6 /*
7 Copyright (C) 2005-2010, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "controller.h"
23 #include "probe.h"
24 #include "common.h"
25 #include "protocol.h"
26 #include "protostructs.h"
27 #include "data.h"
28 #include "endian.h"
29 #include <string.h>
31 #define __DEBUG_MODE__
32 #include "debug.h"
34 namespace Barry {
37 // Controller constructor
39 /// Constructor for the Controller class. Requires a valid ProbeResult
40 /// object to find the USB device to talk to.
41 ///
42 /// \param[in] device One of the ProbeResult objects from the
43 /// Probe class.
44 /// \param[in] default_timeout Override Usb::Device's default timeout
45 ///
46 Controller::Controller(const ProbeResult &device,
47 int default_timeout)
48 : m_result(device)
49 , m_dev(device.m_dev, default_timeout)
50 , m_iface(0)
51 , m_pin(device.m_pin)
52 , m_zero(m_dev, device.m_ep.write, device.m_ep.read, device.m_zeroSocketSequence)
53 , m_queue(0)
55 dout("Controller: Using non-threaded sockets");
56 SetupUsb(device);
60 // Controller constructor
62 /// Constructor for the Controller class. Requires a valid ProbeResult
63 /// object to find the USB device to talk to.
64 ///
65 /// \param[in] device One of the ProbeResult objects from the
66 /// Probe class.
67 /// \param[in] queue Plugin router object for reading data
68 /// from sockets.
69 /// \param[in] default_timeout Override Usb::Device's default timeout
70 ///
71 Controller::Controller(const ProbeResult &device,
72 SocketRoutingQueue &queue,
73 int default_timeout)
74 : m_result(device)
75 , m_dev(device.m_dev, default_timeout)
76 , m_iface(0)
77 , m_pin(device.m_pin)
78 , m_zero(queue, device.m_ep.write, device.m_zeroSocketSequence)
79 , m_queue(&queue)
81 dout("Controller: Using threaded socket router");
83 SetupUsb(device);
85 // set the queue to use our device
86 queue.SetUsbDevice(&m_dev, device.m_ep.write, device.m_ep.read);
89 void Controller::SetupUsb(const ProbeResult &device)
91 unsigned char cfg;
92 if( !m_dev.GetConfiguration(cfg) )
93 throw Usb::Error(m_dev.GetLastError(),
94 "Controller: GetConfiguration failed");
96 if( cfg != BLACKBERRY_CONFIGURATION ) {
97 if( !m_dev.SetConfiguration(BLACKBERRY_CONFIGURATION) )
98 throw Usb::Error(m_dev.GetLastError(),
99 "Controller: SetConfiguration failed");
102 m_iface = new Usb::Interface(m_dev, device.m_interface);
104 m_dev.ClearHalt(device.m_ep.read);
105 m_dev.ClearHalt(device.m_ep.write);
108 Controller::~Controller()
110 // // trap exceptions in the destructor
111 // try {
112 // // a non-default socket has been opened, close it
113 // m_socket.Close();
114 // }
115 // catch( std::runtime_error &re ) {
116 // // do nothing... log it?
117 // dout("Exception caught in ~Socket: " << re.what());
118 // }
120 // detach the router from our device
121 if( m_queue ) {
122 m_queue->ClearUsbDevice();
123 m_queue = 0;
126 // cleanup the interface
127 delete m_iface;
129 // this happens when for some reason the Desktop mode
130 // is not fully opened, but the device has already recommended
131 // a socket to open... in this case, reset the device
132 // in the hopes that on next open, it will be in a
133 // recognizable state.
135 // FIXME - this should not be necessary, and someday we
136 // we should figure out how to handle the "already open"
137 // response we get for the Desktop
139 // FIXME - halfOpen now seems to be handled in the Socket class...
140 // perhaps move this there if needed
143 if( m_halfOpen ) {
144 dout("Controller object destroyed in halfopen state, resetting device");
145 m_dev.Reset();
150 ///////////////////////////////////////////////////////////////////////////////
151 // protected members
154 // Tells device which mode is desired, and returns the suggested
155 // socket ID to use for that mode.
157 uint16_t Controller::SelectMode(ModeType mode)
159 return SelectMode(mode, NULL);
162 // Tells device which mode is desired, and returns the suggested
163 // socket ID to use for that mode.
165 // If explicitModeName is not NULL then it will be used as the mode name.
166 // Otherwise the default mode name for the given mode will be used.
167 // It should be a nul terminated string if it is provided.
169 // The RawChannel mode requires an explicitModeName to be specified.
171 uint16_t Controller::SelectMode(ModeType mode, const char *explicitModeName)
173 // select mode
174 Protocol::Packet packet;
175 packet.socket = 0;
176 packet.size = htobs(SB_MODE_PACKET_COMMAND_SIZE);
177 packet.command = SB_COMMAND_SELECT_MODE;
178 packet.u.socket.socket = htobs(SB_MODE_REQUEST_SOCKET);
179 packet.u.socket.sequence = 0; // updated by Socket::Send()
180 memset(packet.u.socket.u.mode.name, 0, sizeof(packet.u.socket.u.mode.name));
182 char *modeName = (char *) packet.u.socket.u.mode.name;
184 if(explicitModeName)
186 strcpy(modeName, explicitModeName);
188 else
189 // No modeName given, use the default
190 switch( mode )
192 case Bypass:
193 strcpy(modeName, "RIM Bypass");
194 break;
196 case Desktop:
197 strcpy(modeName, "RIM Desktop");
198 break;
200 case JavaLoader:
201 strcpy(modeName, "RIM_JavaLoader");
202 break;
204 case JVMDebug:
205 strcpy(modeName, "RIM_JVMDebug");
206 break;
208 case UsbSerData:
209 strcpy(modeName, "RIM_UsbSerData");
210 break;
212 case UsbSerCtrl:
213 strcpy(modeName, "RIM_UsbSerCtrl");
214 break;
216 case RawChannel:
217 throw std::logic_error("Controller: No channel name given with RawChannel mode");
218 break;
220 default:
221 throw std::logic_error("Controller: Invalid mode in SelectMode");
222 break;
225 // send mode command before we open, as a default socket is socket 0
226 Data command(&packet, btohs(packet.size));
227 Data response;
229 try {
230 m_zero.Send(command, response);
232 // get the data socket number
233 // indicates the socket number that
234 // should be used below in the Open() call
235 MAKE_PACKET(modepack, response);
236 if (modepack->command == SB_COMMAND_MODE_NOT_SELECTED) {
237 throw Error("Controller: requested mode not supported");
239 if (modepack->command != SB_COMMAND_MODE_SELECTED) {
240 eeout(command, response);
241 throw Error("Controller: mode not selected");
244 if (mode == Desktop) {
245 // On the BlackBerry Storm, I have to read a packet
246 // after opening a socket. (only for Desktop mode)
247 // Otherwise, barrybackup and opensync-plugin can crash (timeout)
248 // I don't know why ! Maybe a bug on the handheld.
249 m_zero.HideSequencePacket(false);
250 m_zero.Receive(response);
251 m_zero.HideSequencePacket(true);
253 // return the socket that the device is expecting us to use
254 return btohs(modepack->u.socket.socket);
256 catch( Usb::Error & ) {
257 eout("Controller: error setting desktop mode");
258 eeout(command, response);
259 throw;
264 ///////////////////////////////////////////////////////////////////////////////
265 // public API
268 } // namespace Barry