55 */
66
77#include " Common/Cpp/Exceptions.h"
8+ #include " Common/Cpp/PrettyPrint.h"
89#include " Common/Cpp/StreamConnections/PABotBase2_MessageDumper.h"
10+ #include " CommonFramework/Globals.h"
11+ #include " CommonFramework/Options/Environment/ThemeSelectorOption.h"
912#include " CommonFramework/GlobalSettingsPanel.h"
13+ #include " Controllers/SerialPABotBase/SerialPABotBase.h"
1014#include " PABotBase2_DeviceHandle.h"
1115
1216// REMOVE
@@ -54,79 +58,103 @@ bool DeviceHandle::cancel(std::exception_ptr exception) noexcept{
5458}
5559
5660
57- void DeviceHandle::connect (){
58- m_device_protocol = query_u32 (PABB2_MESSAGE_OPCODE_PROTOCOL_VERSION);
59- m_logger.log (" [MLC]: Remote Protocol: " + std::to_string (m_device_protocol), COLOR_BLUE);
60-
61- m_device_firmware_version = query_u32 (PABB2_MESSAGE_OPCODE_FIRMWARE_VERSION);
62- m_logger.log (" [MLC]: Firmware Version: " + std::to_string (m_device_firmware_version), COLOR_BLUE);
6361
64- m_device_id = query_u32 (PABB2_MESSAGE_OPCODE_DEVICE_IDENTIFIER);
65- m_logger.log (" [MLC]: Device ID: " + std::to_string (m_device_id), COLOR_BLUE);
66-
67- m_command_queue_size = ( uint8_t ) query_u32 (PABB2_MESSAGE_OPCODE_CQ_CAPACITY);
68- m_logger. log ( " [MLC]: Command Queue Size: " + std::to_string (m_command_queue_size), COLOR_BLUE );
62+ void DeviceHandle::throw_incompatible_protocol (){
63+ m_logger.log (
64+ " [MLC]: Remote Protocol: " + std::to_string (m_device_protocol) + " (incompatible) " ,
65+ COLOR_RED
66+ );
6967
68+ throw SerialProtocolException (
69+ m_logger, PA_CURRENT_FUNCTION,
70+ " Incompatible MLC protocol. Device: " + std::to_string (m_device_protocol) + " <br>"
71+ " Please flash your microcontroller (e.g. ESP32, Pico W, Arduino) <br>"
72+ " with the .bin/.uf2/.hex that came with this version of the program.<br>" +
73+ make_text_url (ONLINE_DOC_URL_BASE + " SetupGuide/Reflash.html" , " See documentation for more details." )
74+ );
7075}
71-
72- void DeviceHandle::on_recv ( const void * data, size_t bytes){
73- cout << " DeviceHandle::on_recv() " << endl;
74- m_buffer. insert (m_buffer. end (), ( const char *)data, ( const char *)data + bytes );
75-
76- while ( true ){
77- // Header is incomplete.
78- if (m_buffer. size () < sizeof (pabb2_MessageHeader )){
79- return ;
76+ void DeviceHandle::query_protocol (){
77+ const std::map<pabb_ProgramID, uint8_t >* PROGRAMS;
78+ {
79+ m_device_protocol = query_u32 (PABB2_MESSAGE_OPCODE_PROTOCOL_VERSION );
80+ const std::map< uint32_t , std::map<pabb_ProgramID, uint8_t >>& SUPPORTED_VERSIONS =
81+ SerialPABotBase::SUPPORTED_VERSIONS2 ();
82+ auto iter = SUPPORTED_VERSIONS. find (m_device_protocol / 100 );
83+ if (iter == SUPPORTED_VERSIONS. end ( )){
84+ throw_incompatible_protocol () ;
8085 }
81-
82- // Message is incomplete.
83- uint16_t message_size;
84- std::copy (m_buffer.begin (), m_buffer.begin () + 2 , (char *)&message_size);
85- if (m_buffer.size () < message_size){
86- return ;
86+ PROGRAMS = &iter->second ;
87+ }
88+ {
89+ m_device_id = query_u32 (PABB2_MESSAGE_OPCODE_DEVICE_IDENTIFIER);
90+ m_logger.log (" [MLC]: Device ID: " + tostr_hex (m_device_id), COLOR_BLUE);
91+ auto iter = PROGRAMS->find (m_device_id);
92+ if (iter == PROGRAMS->end ()){
93+ m_logger.Logger ::log (
94+ " Unrecognized Program ID: (0x" + tostr_hex (m_device_id) + " ) for this protocol version. "
95+ " Compatibility is not guaranteed." ,
96+ COLOR_RED
97+ );
98+ iter = PROGRAMS->find (PABB_PID_UNSPECIFIED);
99+ if (iter == PROGRAMS->end ()){
100+ throw_incompatible_protocol ();
101+ }
87102 }
103+ }
104+ m_logger.log (
105+ " [MLC]: Remote Protocol: " + std::to_string (m_device_protocol) + " (compatible)" ,
106+ COLOR_RED
107+ );
108+ }
109+ void DeviceHandle::query_controller_list (){
110+ std::string response = query_data (PABB2_MESSAGE_OPCODE_CONTROLLER_LIST);
111+ if (response.size () % sizeof (pabb_ControllerID) != 0 ){
112+ throw InternalProgramError (
113+ &m_logger,
114+ PA_CURRENT_FUNCTION,
115+ " Controller list query expects a response length divisible by " + std::to_string (sizeof (pabb_ControllerID)) + " ."
116+ );
117+ }
88118
89- auto iter_s = m_buffer.begin ();
90- auto iter_e = iter_s + message_size;
91- std::string message (iter_s, iter_e);
92- m_buffer.erase (iter_s, iter_e);
93-
94- const pabb2_MessageHeader* header = (const pabb2_MessageHeader*)message.c_str ();
95-
96- bool log_everything = GlobalSettings::instance ().LOG_EVERYTHING ;
97-
98- if (log_everything){
99- m_logger.log (" [MLC]: Receive: " + tostr (header), COLOR_PURPLE);
100- }
119+ size_t length = response.size () / sizeof (pabb_ControllerID);
120+ const pabb_ControllerID* list = (const pabb_ControllerID*)response.c_str ();
101121
102- // Now we can process the message.
103- switch (header->opcode ){
104- case PABB2_MESSAGE_OPCODE_INVALID:
105- case PABB2_MESSAGE_OPCODE_REQUEST_DROPPED:
106- if (!log_everything){
107- m_logger.log (" [MLC]: Receive: " + tostr (header), COLOR_PURPLE);
108- }
109- continue ;
110- case PABB2_MESSAGE_OPCODE_RET:
111- case PABB2_MESSAGE_OPCODE_RET_U32:
112- case PABB2_MESSAGE_OPCODE_RET_DATA:
113- {
114- std::lock_guard<Mutex> lg (m_lock);
115- auto iter = m_pending_requests.find (header->id );
116- if (iter == m_pending_requests.end ()){
117- m_logger.log (" [MLC]: Received response for unknown ID: " + std::to_string (header->id ));
118- continue ;
119- }
120- iter->second .response = std::move (message);
121- iter->second .cv .notify_all ();
122- continue ;
122+ std::string str;
123+ bool first = true ;
124+ for (size_t c = 0 ; c < length; c++){
125+ pabb_ControllerID id;
126+ memcpy (&id, list + c, sizeof (pabb_ControllerID));
127+ if (!first){
128+ str += " , " ;
123129 }
130+ first = false ;
131+ str += " 0x" + tostr_hex (id);
132+ if (SerialPABotBase::controller_is_valid (id)){
133+ m_controller_list.emplace_back (SerialPABotBase::id_to_controller_type (id));
124134 }
125-
126- // TODO: Process device-specific messages.
127135 }
136+ m_logger.Logger ::log (" Checking Controller List... (" + str + " )" );
137+ }
138+ void DeviceHandle::query_command_queue (){
139+ m_command_queue_size = (uint8_t )query_u32 (PABB2_MESSAGE_OPCODE_CQ_CAPACITY);
140+ m_logger.log (" [MLC]: Command Queue Size: " + std::to_string (m_command_queue_size), COLOR_BLUE);
141+
142+ // For now we don't need to use that much queue size.
143+ m_command_queue_size = std::min<uint8_t >(m_command_queue_size, 32 );
144+
145+ m_logger.Logger ::log (" Setting queue size to: " + std::to_string (m_command_queue_size));
146+ }
147+ void DeviceHandle::connect (){
148+ query_protocol ();
128149
150+ m_device_firmware_version = query_u32 (PABB2_MESSAGE_OPCODE_FIRMWARE_VERSION);
151+ m_logger.log (" [MLC]: Firmware Version: " + std::to_string (m_device_firmware_version), COLOR_BLUE);
152+
153+ m_device_name = query_data (PABB2_MESSAGE_OPCODE_DEVICE_NAME);
154+ m_logger.log (" [MLC]: Device Name: " + m_device_name, COLOR_BLUE);
129155
156+ query_controller_list ();
157+ query_command_queue ();
130158}
131159
132160
@@ -180,7 +208,6 @@ std::string DeviceHandle::wait_for_response(uint8_t id){
180208 }
181209}
182210
183-
184211uint32_t DeviceHandle::query_u32 (uint8_t opcode){
185212 pabb2_MessageHeader request;
186213 request.message_bytes = sizeof (pabb2_MessageHeader);
@@ -193,13 +220,100 @@ uint32_t DeviceHandle::query_u32(uint8_t opcode){
193220 throw InternalProgramError (
194221 &m_logger,
195222 PA_CURRENT_FUNCTION,
196- " Expected reponse length of: " + std::to_string (sizeof (pabb2_Message_Response_u32))
223+ " Expected response length of: " + std::to_string (sizeof (pabb2_Message_Response_u32))
197224 );
198225 }
199226
200227 const pabb2_Message_Response_u32* msg = (const pabb2_Message_Response_u32*)response.c_str ();
201228 return msg->data ;
202229}
230+ std::string DeviceHandle::query_data (uint8_t opcode){
231+ pabb2_MessageHeader request;
232+ request.message_bytes = sizeof (pabb2_MessageHeader);
233+ request.opcode = opcode;
234+
235+ send_request (request);
236+
237+ std::string response = wait_for_response (request.id );
238+ if (response.size () < sizeof (pabb2_Message_Response_Data)){
239+ throw InternalProgramError (
240+ &m_logger,
241+ PA_CURRENT_FUNCTION,
242+ " Response length of " + std::to_string (response.size ()) + " is too short."
243+ );
244+ }
245+
246+ const pabb2_Message_Response_Data* msg = (const pabb2_Message_Response_Data*)response.c_str ();
247+ return std::string ((const char *)(msg + 1 ), msg->message_bytes - sizeof (pabb2_Message_Response_Data));
248+ }
249+
250+
251+
252+
253+
254+ void DeviceHandle::on_recv (const void * data, size_t bytes){
255+ cout << " DeviceHandle::on_recv()" << endl;
256+ m_buffer.insert (m_buffer.end (), (const char *)data, (const char *)data + bytes);
257+
258+ while (true ){
259+ // Header is incomplete.
260+ if (m_buffer.size () < sizeof (pabb2_MessageHeader)){
261+ return ;
262+ }
263+
264+ // Message is incomplete.
265+ uint16_t message_size;
266+ std::copy (m_buffer.begin (), m_buffer.begin () + 2 , (char *)&message_size);
267+ if (m_buffer.size () < message_size){
268+ return ;
269+ }
270+
271+ auto iter_s = m_buffer.begin ();
272+ auto iter_e = iter_s + message_size;
273+ std::string message (iter_s, iter_e);
274+ m_buffer.erase (iter_s, iter_e);
275+
276+ const pabb2_MessageHeader* header = (const pabb2_MessageHeader*)message.c_str ();
277+
278+ bool log_everything = GlobalSettings::instance ().LOG_EVERYTHING ;
279+
280+ if (log_everything){
281+ m_logger.log (" [MLC]: Receive: " + tostr (header), COLOR_PURPLE);
282+ }
283+
284+ // Now we can process the message.
285+ switch (header->opcode ){
286+ case PABB2_MESSAGE_OPCODE_INVALID:
287+ case PABB2_MESSAGE_OPCODE_REQUEST_DROPPED:
288+ if (!log_everything){
289+ m_logger.log (" [MLC]: Receive: " + tostr (header), COLOR_PURPLE);
290+ }
291+ continue ;
292+ case PABB2_MESSAGE_OPCODE_RET:
293+ case PABB2_MESSAGE_OPCODE_RET_U32:
294+ case PABB2_MESSAGE_OPCODE_RET_DATA:
295+ {
296+ std::lock_guard<Mutex> lg (m_lock);
297+ auto iter = m_pending_requests.find (header->id );
298+ if (iter == m_pending_requests.end ()){
299+ m_logger.log (" [MLC]: Received response for unknown ID: " + std::to_string (header->id ));
300+ continue ;
301+ }
302+ iter->second .response = std::move (message);
303+ iter->second .cv .notify_all ();
304+ continue ;
305+ }
306+ }
307+
308+ // TODO: Process device-specific messages.
309+ }
310+
311+
312+ }
313+
314+
315+
316+
203317
204318
205319
0 commit comments