2 /// \file controller.cc
3 /// High level Barry API class
7 Copyright (C) 2005, 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"
25 #include "protostructs.h"
30 #define __DEBUG_MODE__
40 // Controller constructor
42 /// Constructor for the Controller class. Requires a valid ProbeResult
43 /// object to find the USB device to talk to.
45 /// \param[in] device One of the ProbeResult objects from the
48 Controller::Controller(const ProbeResult
&device
)
49 : m_dev(device
.m_dev
),
50 m_iface(m_dev
, BLACKBERRY_INTERFACE
),
52 m_socket(m_dev
, WRITE_ENDPOINT
, READ_ENDPOINT
),
55 if( !m_dev
.SetConfiguration(BLACKBERRY_CONFIGURATION
) )
56 throw BError(m_dev
.GetLastError(),
57 "Controller: SetConfiguration failed");
60 Controller::~Controller()
64 ///////////////////////////////////////////////////////////////////////////////
67 void Controller::SelectMode(ModeType mode
, uint16_t &socket
, uint8_t &flag
)
72 packet
.size
= SB_MODE_PACKET_COMMAND_SIZE
;
73 packet
.command
= SB_COMMAND_SELECT_MODE
;
74 packet
.data
.mode
.socket
= SB_MODE_REQUEST_SOCKET
;
75 packet
.data
.mode
.flag
= 0x05; // FIXME
76 memset(packet
.data
.mode
.modeName
, 0,
77 sizeof(packet
.data
.mode
.modeName
));
79 char *modeName
= (char *) packet
.data
.mode
.modeName
;
83 strcpy(modeName
, "RIM Bypass");
87 strcpy(modeName
, "RIM Desktop");
91 strcpy(modeName
, "RIM_JavaLoader");
95 throw std::logic_error("Controller: Invalid mode in SelectMode");
99 // send mode command before we open, as a default socket is socket 0
100 Data
command(&packet
, packet
.size
);
102 if( !m_socket
.Send(command
, response
) ) {
103 eeout(command
, response
);
104 throw BError(m_socket
.GetLastStatus(),
105 "Controller: error setting desktop mode");
108 // get the data socket number
109 // indicates the socket number that
110 // should be used below in the Open() call
111 CheckSize(response
, SB_MODE_PACKET_RESPONSE_SIZE
);
112 MAKE_PACKET(modepack
, response
);
113 if( modepack
->command
!= SB_COMMAND_MODE_SELECTED
) {
114 eeout(command
, response
);
115 throw BError("Controller: mode not selected");
118 // return the socket and flag that the device is expecting us to use
119 socket
= modepack
->data
.mode
.socket
;
120 flag
= modepack
->data
.mode
.flag
+ 1;
123 unsigned int Controller::GetCommand(CommandType ct
)
125 unsigned int cmd
= 0;
126 char *cmdName
= "Unknown";
131 cmdName
= "Database Access";
132 cmd
= m_commandTable
.GetCommand(cmdName
);
135 throw std::logic_error("Controller: unknown command type");
139 std::ostringstream oss
;
140 oss
<< "Controller: unable to get command code: " << cmdName
;
141 throw BError(oss
.str());
147 void Controller::LoadCommandTable()
149 assert( m_mode
== Desktop
);
151 char rawCommand
[] = { 6, 0, 0x0a, 0, 0x40, 0, 0, 1, 0, 0 };
152 *((uint16_t*) rawCommand
) = m_socket
.GetSocket();
154 Data
command(rawCommand
, sizeof(rawCommand
));
156 if( !m_socket
.Packet(command
, response
) ) {
157 eeout(command
, response
);
158 throw BError(m_socket
.GetLastStatus(),
159 "Controller: error getting command table");
162 MAKE_PACKET(firstpack
, response
);
163 while( firstpack
->command
!= SB_COMMAND_DB_DONE
) {
164 if( !m_socket
.NextRecord(response
) ) {
165 eout("Response packet:\n" << response
);
166 throw BError(m_socket
.GetLastStatus(),
167 "Controller: error getting command table(next)");
170 MAKE_PACKET(rpack
, response
);
171 if( rpack
->command
== SB_COMMAND_DB_DATA
&& rpack
->size
> 10 ) {
172 // second packet is generally large, and contains
174 m_commandTable
.Clear();
175 m_commandTable
.Parse(response
, 6);
179 ddout(m_commandTable
);
182 void Controller::LoadDBDB()
184 assert( m_mode
== Desktop
);
187 packet
.socket
= m_socket
.GetSocket();
189 packet
.command
= SB_COMMAND_DB_DATA
;
190 packet
.data
.db
.tableCmd
= GetCommand(DatabaseAccess
);
191 // packet.data.db.data.db.operation = SB_DBOP_GET_DBDB;
192 packet
.data
.db
.data
.db
.operation
= SB_DBOP_OLD_GET_DBDB
;
194 Data
command(&packet
, packet
.size
);
197 if( !m_socket
.Packet(command
, response
) ) {
198 eeout(command
, response
);
199 throw BError(m_socket
.GetLastStatus(),
200 "Controller: error getting database database");
203 MAKE_PACKET(rpack
, response
);
204 while( rpack
->command
!= SB_COMMAND_DB_DONE
) {
205 if( rpack
->command
== SB_COMMAND_DB_DATA
) {
207 m_dbdb
.Parse(response
);
211 if( !m_socket
.NextRecord(response
) ) {
212 eout("Response packet:\n" << response
);
213 throw BError(m_socket
.GetLastStatus(),
214 "Controller: error getting command table(next)");
216 rpack
= (const Packet
*) response
.GetData();
221 ///////////////////////////////////////////////////////////////////////////////
227 /// Get numeric database ID by name.
229 /// \param[in] name Name of database, which matches one of the
230 /// names listed in GetDBDB()
232 /// \exception Barry::BError
233 /// Thrown if name not found.
235 unsigned int Controller::GetDBID(const std::string
&name
) const
237 unsigned int ID
= m_dbdb
.GetDBNumber(name
);
238 // FIXME - this needs a better error handler... the dbdb needs one too!
240 throw BError("Controller: Address Book not found");
248 /// Select device mode. This is required before using any other mode-based
249 /// operations, such as GetDBDB() and LoadDatabase(). Currently only
250 /// Desktop mode is supported, but the following modes are available.
253 /// - Controller::Bypass
254 /// - Controller::Desktop
255 /// - Controller::JavaLoader
257 /// \exception Barry::BError
258 /// Thrown on protocol error.
260 /// \exception std::logic_error()
261 /// Thrown if unsupported mode is requested.
263 void Controller::OpenMode(ModeType mode
)
268 if( m_mode
!= mode
) {
270 SelectMode(mode
, socket
, flag
);
271 m_socket
.Open(socket
, flag
);
280 // get database database
285 throw std::logic_error("Mode not implemented");
293 /// Retrieve a database from the handheld device, using the given parser
294 /// to parse the resulting data, and optionally store it.
296 /// See the RecordParser<> template to create a parser object. The
297 /// RecordParser<> template allows custom storage based on the type of
298 /// database record retrieved. The database ID and the parser Record
301 /// \param[in] dbId Database Database ID - use GetDBID()
302 /// \param[out] parser Parser object which parses the resulting
303 /// protocol data, and optionally stores it in
304 /// a custom fashion. See the RecordParser<>
307 /// \exception Barry::BError
308 /// Thrown on protocol error.
310 /// \exception std::logic_error
311 /// Thrown if not in Desktop mode.
313 void Controller::LoadDatabase(unsigned int dbId
, Parser
&parser
)
315 if( m_mode
!= Desktop
)
316 throw std::logic_error("Wrong mode in LoadDatabase");
319 packet
.socket
= m_socket
.GetSocket();
321 packet
.command
= SB_COMMAND_DB_DATA
;
322 packet
.data
.db
.tableCmd
= GetCommand(DatabaseAccess
);
323 // packet.data.db.data.db.operation = SB_DBOP_GET_RECORDS;
324 packet
.data
.db
.data
.db
.operation
= SB_DBOP_OLD_GET_RECORDS
;
325 packet
.data
.db
.data
.db
.databaseId
= dbId
;
327 Data
command(&packet
, packet
.size
);
330 if( !m_socket
.Packet(command
, response
) ) {
331 eout("Database ID: " << dbId
);
332 eeout(command
, response
);
333 throw BError(m_socket
.GetLastStatus(),
334 "Controller: error loading database");
337 MAKE_PACKET(rpack
, response
);
338 while( rpack
->command
!= SB_COMMAND_DB_DONE
) {
339 if( rpack
->command
== SB_COMMAND_DB_DATA
) {
344 if( !m_socket
.NextRecord(response
) ) {
345 eout("Response packet:\n" << response
);
346 throw BError(m_socket
.GetLastStatus(),
347 "Controller: error loading database (next)");
349 rpack
= (const Packet
*) response
.GetData();