Skip to content

Commit 72a03b1

Browse files
committed
More MLC layer.
1 parent 17dd991 commit 72a03b1

File tree

9 files changed

+278
-75
lines changed

9 files changed

+278
-75
lines changed

Common/Cpp/StreamConnections/ReliableStreamConnection.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,10 +393,7 @@ void ReliableStreamConnection::process_RET_VERSION(const PacketHeader* packet){
393393
break;
394394
}
395395

396-
m_logger.log(
397-
"[RSC]: " + str + " (compatible)",
398-
COLOR_BLUE
399-
);
396+
m_logger.log("[RSC]: " + str + " (compatible)", COLOR_BLUE);
400397
m_reliable_sender.remove(packet->seqnum);
401398

402399
}while (false);

Common/PABotBase2/DataLayer/PABotBase2_ComputerHandle.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,17 @@ void ComputerHandle::send_message_u32(uint8_t id, uint32_t data){
2323
response.id = id;
2424
response.data = data;
2525
data_connection.reliable_send(&response, response.message_bytes);
26-
26+
2727
// data_connection.send_oob_info_u32(response.message_bytes);
2828
}
29+
void ComputerHandle::send_message_data(uint8_t id, uint16_t bytes, const void* data){
30+
pabb2_Message_Response_Data response;
31+
response.message_bytes = sizeof(pabb2_Message_Response_Data) + bytes;
32+
response.opcode = PABB2_MESSAGE_OPCODE_RET_DATA;
33+
response.id = id;
34+
data_connection.reliable_send(&response, sizeof(pabb2_Message_Response_Data));
35+
data_connection.reliable_send(data, bytes);
36+
}
2937
void ComputerHandle::process_completed_message(){
3038
const pabb2_MessageHeader* header = (const pabb2_MessageHeader*)m_buffer;
3139

@@ -39,6 +47,12 @@ void ComputerHandle::process_completed_message(){
3947
case PABB2_MESSAGE_OPCODE_DEVICE_IDENTIFIER:
4048
send_message_u32(header->id, PABB2_DEVICE_ID);
4149
return;
50+
case PABB2_MESSAGE_OPCODE_DEVICE_NAME:
51+
send_message_data(header->id, sizeof(PABB2_DEVICE_NAME) - 1, PABB2_DEVICE_NAME);
52+
return;
53+
case PABB2_MESSAGE_OPCODE_CONTROLLER_LIST:
54+
send_message_data(header->id, sizeof(PABB_CONTROLLER_LIST), PABB_CONTROLLER_LIST);
55+
return;
4256
case PABB2_MESSAGE_OPCODE_CQ_CAPACITY:
4357
send_message_u32(header->id, PABB2_CommandQueue_SLOTS);
4458
return;

Common/PABotBase2/DataLayer/PABotBase2_ComputerHandle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class ComputerHandle{
2929

3030
private:
3131
void send_message_u32(uint8_t id, uint32_t data);
32+
void send_message_data(uint8_t id, uint16_t bytes, const void* data);
3233
void process_completed_message();
3334

3435
private:

Common/PABotBase2/DataLayer/PABotBase2_MessageProtocol.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ struct PABB_PACK pabb2_Message_Response_Data{
6161
#define PABB2_MESSAGE_OPCODE_PROTOCOL_VERSION 0x20
6262
#define PABB2_MESSAGE_OPCODE_FIRMWARE_VERSION 0x21
6363
#define PABB2_MESSAGE_OPCODE_DEVICE_IDENTIFIER 0x22
64-
#define PABB2_MESSAGE_OPCODE_CONTROLLER_LIST 0x23
65-
#define PABB2_MESSAGE_OPCODE_CQ_CAPACITY 0x24
64+
#define PABB2_MESSAGE_OPCODE_DEVICE_NAME 0x23
65+
#define PABB2_MESSAGE_OPCODE_CONTROLLER_LIST 0x24
66+
#define PABB2_MESSAGE_OPCODE_CQ_CAPACITY 0x28
6667

6768
#define PABB_MESSAGE_OPCODE_READ_CONTROLLER_MODE 0x30
6869
#define PABB_MESSAGE_OPCODE_CHANGE_CONTROLLER_MODE 0x31

SerialPrograms/Source/Controllers/PABotBase2/PABotBase2_DeviceHandle.cpp

Lines changed: 177 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
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-
184211
uint32_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

Comments
 (0)