example: new maple "get_condition" demo

This is very barebones, and uses the serial interface to communicate
the status of the "a" controller button being pressed.

I'd like to make this a more interactive/graphical demo.
This commit is contained in:
Zack Buhman 2023-12-15 22:08:23 +08:00
parent 9bd79c6664
commit 39aa6b75a6
7 changed files with 206 additions and 65 deletions

View File

@ -54,6 +54,15 @@ CUBE_OBJ = \
example/cube.elf: LDSCRIPT = $(LIB)/alt.lds example/cube.elf: LDSCRIPT = $(LIB)/alt.lds
example/cube.elf: $(START_OBJ) $(CUBE_OBJ) example/cube.elf: $(START_OBJ) $(CUBE_OBJ)
MAPLE_DEVICE_REQUEST_OBJ = \
example/maple_device_request.o \
vga.o \
serial.o \
maple/maple.o
example/maple_device_request.elf: LDSCRIPT = $(LIB)/alt.lds
example/maple_device_request.elf: $(START_OBJ) $(MAPLE_DEVICE_REQUEST_OBJ)
MAPLE_CONTROLLER_OBJ = \ MAPLE_CONTROLLER_OBJ = \
example/maple_controller.o \ example/maple_controller.o \
vga.o \ vga.o \

View File

@ -1,37 +1,116 @@
#include <bit>
#include "vga.hpp"
#include "align.hpp" #include "align.hpp"
#include "maple/maple.hpp" #include "maple/maple.hpp"
#include "maple/maple_bus_bits.hpp"
#include "maple/maple_bus_commands.hpp" #include "maple/maple_bus_commands.hpp"
#include "maple/maple_bus_ft0.hpp"
#include "serial.hpp" #include "serial.hpp"
constexpr uint32_t command_data_size = (sizeof (device_request::data_fields)); uint32_t _command_buf[1024 / 4 + 32] = {0};
constexpr uint32_t response_data_size = (sizeof (device_status::data_fields)); uint32_t _receive_buf[1024 / 4 + 32] = {0};
constexpr uint32_t host_command_size = (sizeof (struct maple::host_command<device_request::data_fields>)); static uint32_t * command_buf;
constexpr uint32_t command_response_size = align_32byte((sizeof (struct maple::command_response<device_status::data_fields>))); static uint32_t * receive_buf;
uint32_t _command_buf[host_command_size * 4 + 32] = {0}; struct port_state {
uint32_t _receive_buf[command_response_size * 4 + 32] = {0}; bool controller_connected;
};
static port_state state[4] = {0};
void do_get_condition(uint32_t port)
{
uint32_t destination_port;
uint32_t destination_ap;
switch (port) {
case 0:
destination_port = host_instruction::port_select::a;
destination_ap = ap::de::device | ap::port_select::a;
break;
case 1:
destination_port = host_instruction::port_select::b;
destination_ap = ap::de::device | ap::port_select::b;
break;
case 2:
destination_port = host_instruction::port_select::c;
destination_ap = ap::de::device | ap::port_select::c;
break;
case 3:
destination_port = host_instruction::port_select::d;
destination_ap = ap::de::device | ap::port_select::d;
break;
default:
return;
}
maple::init_get_condition(command_buf, receive_buf,
destination_port,
destination_ap,
std::byteswap(function_type::controller));
maple::dma_start(command_buf);
using response_type = struct maple::command_response<data_transfer::data_fields<struct ft0::data_transfer::data_format>>;
auto response = reinterpret_cast<response_type *>(receive_buf);
auto& bus_data = response->bus_data;
auto& data_fields = response->bus_data.data_fields;
if (bus_data.command_code != data_transfer::command_code) {
return;
}
if ((data_fields.function_type & std::byteswap(function_type::controller)) == 0) {
return;
}
state[port].controller_connected = 1;
bool a = data_fields.data.digital_button & ft0::data_transfer::digital_button::a;
if (a == 0) {
serial::string("port ");
serial::integer<uint8_t>(port);
serial::string(" `a` press ");
serial::integer<uint8_t>(a);
}
}
void do_device_request()
{
using response_type = struct maple::command_response<device_status::data_fields>;
constexpr uint32_t response_size = align_32byte(sizeof (response_type));
maple::init_host_command_all_ports(command_buf, receive_buf,
device_request::command_code,
(sizeof (device_request::data_fields)), // command_data_size
(sizeof (device_status::data_fields))); // response_data_size
maple::dma_start(command_buf);
for (uint8_t port = 0; port < 4; port++) {
auto response = reinterpret_cast<response_type *>(&receive_buf[response_size * port / 4]);
auto& bus_data = response->bus_data;
auto& data_fields = response->bus_data.data_fields;
if (bus_data.command_code != device_status::command_code) {
// the controller is disconnected
state[port].controller_connected = 0;
} else {
if ((data_fields.device_id.ft & std::byteswap(function_type::controller)) != 0) {
//serial::string("is controller: ");
//serial::integer<uint8_t>(port);
do_get_condition(port);
}
}
}
}
void main() void main()
{ {
uint32_t * command_buf = align_32byte(_command_buf); command_buf = align_32byte(_command_buf);
uint32_t * receive_buf = align_32byte(_receive_buf); receive_buf = align_32byte(_receive_buf);
maple::init_host_command_all_ports(command_buf, receive_buf, while (1) {
device_request::command_code, command_data_size, response_data_size); v_sync_out();
v_sync_in();
maple::dma_start(command_buf); do_device_request();
};
uint8_t * buf = reinterpret_cast<uint8_t *>(receive_buf);
for (uint8_t port = 0; port < 4; port++) {
serial::string("port ");
serial::integer<uint8_t>(port);
for (uint32_t i = 0; i < command_response_size; i++) {
serial::integer<uint8_t>(buf[port * command_response_size + i]);
}
serial::character('\n');
}
while (1);
} }

View File

@ -0,0 +1,37 @@
#include "align.hpp"
#include "maple/maple.hpp"
#include "maple/maple_bus_commands.hpp"
#include "serial.hpp"
constexpr uint32_t command_data_size = (sizeof (device_request::data_fields));
constexpr uint32_t response_data_size = (sizeof (device_status::data_fields));
constexpr uint32_t host_command_size = (sizeof (struct maple::host_command<device_request::data_fields>));
constexpr uint32_t command_response_size = align_32byte((sizeof (struct maple::command_response<device_status::data_fields>)));
uint32_t _command_buf[host_command_size * 4 + 32] = {0};
uint32_t _receive_buf[command_response_size * 4 + 32] = {0};
void main()
{
uint32_t * command_buf = align_32byte(_command_buf);
uint32_t * receive_buf = align_32byte(_receive_buf);
maple::init_host_command_all_ports(command_buf, receive_buf,
device_request::command_code, command_data_size, response_data_size);
maple::dma_start(command_buf);
uint8_t * buf = reinterpret_cast<uint8_t *>(receive_buf);
for (uint8_t port = 0; port < 4; port++) {
serial::string("port ");
serial::integer<uint8_t>(port);
for (uint32_t i = 0; i < command_response_size; i++) {
serial::integer<uint8_t>(buf[port * command_response_size + i]);
}
serial::character('\n');
}
while (1);
}

View File

@ -76,7 +76,8 @@ void init_device_request(uint32_t * buf, uint32_t * receive_buf,
void init_get_condition(uint32_t * buf, uint32_t * receive_buf, void init_get_condition(uint32_t * buf, uint32_t * receive_buf,
uint32_t destination_port, uint32_t destination_port,
uint8_t destination_ap) uint8_t destination_ap,
uint32_t function_type)
{ {
init_host_command(buf, receive_buf, init_host_command(buf, receive_buf,
destination_port, destination_port,
@ -87,7 +88,7 @@ void init_get_condition(uint32_t * buf, uint32_t * receive_buf,
auto& fields = host_command->bus_data.data_fields; auto& fields = host_command->bus_data.data_fields;
// controller function type // controller function type
fields.function_type = std::byteswap(function_type::controller); fields.function_type = function_type;
} }
void init_block_write(uint32_t * command_buf, uint32_t * receive_buf, void init_block_write(uint32_t * command_buf, uint32_t * receive_buf,

View File

@ -42,7 +42,8 @@ void init_device_request(uint32_t * buf, uint32_t * receive_buf,
void init_get_condition(uint32_t * buf, uint32_t * receive_buf, void init_get_condition(uint32_t * buf, uint32_t * receive_buf,
uint32_t destination_port, uint32_t destination_port,
uint8_t destination_ap); uint8_t destination_ap,
uint32_t function_type);
void init_block_write(uint32_t * buf, uint32_t * receive_buf, void init_block_write(uint32_t * buf, uint32_t * receive_buf,
uint32_t destination_port, uint32_t destination_port,

View File

@ -1,38 +1,44 @@
#include <cstdint> #include <cstdint>
struct device_id {
uint32_t ft;
uint32_t fd[3];
};
static_assert((sizeof (struct device_id)) == 16);
namespace device_request { namespace device_request {
constexpr uint32_t command_code = 0x1; constexpr uint32_t command_code = 0x1;
struct data_fields { struct data_fields {
}; };
} }
namespace all_status_request { namespace all_status_request {
constexpr uint32_t command_code = 0x2; constexpr uint32_t command_code = 0x2;
struct data_fields { struct data_fields {
}; };
} }
namespace device_reset { namespace device_reset {
constexpr uint32_t command_code = 0x3; constexpr uint32_t command_code = 0x3;
struct data_fields { struct data_fields {
}; };
} }
namespace device_kill { namespace device_kill {
constexpr uint32_t command_code = 0x4; constexpr uint32_t command_code = 0x4;
struct data_fields { struct data_fields {
}; };
} }
namespace device_status { namespace device_status {
constexpr uint32_t command_code = 0x5; constexpr uint32_t command_code = 0x5;
struct data_fields { struct data_fields {
uint8_t device_id[16]; struct device_id device_id;
uint8_t destination_code; uint8_t destination_code;
uint8_t connection_direction; uint8_t connection_direction;
uint8_t product_name[30]; uint8_t product_name[30];
@ -40,16 +46,16 @@ namespace device_status {
uint16_t low_consumption_standby_current; uint16_t low_consumption_standby_current;
uint16_t maximum_current_consumption; uint16_t maximum_current_consumption;
}; };
static_assert((sizeof (struct data_fields)) == 112); static_assert((sizeof (struct data_fields)) == 112);
} }
namespace device_all_status { namespace device_all_status {
constexpr uint32_t command_code = 0x6; constexpr uint32_t command_code = 0x6;
template <typename T> template <typename T>
struct data_fields { struct data_fields {
uint8_t device_id[16]; struct device_id device_id;
uint8_t destination_code; uint8_t destination_code;
uint8_t connection_direction; uint8_t connection_direction;
uint8_t product_name[30]; uint8_t product_name[30];
@ -58,66 +64,66 @@ namespace device_all_status {
uint16_t maximum_current_consumption; uint16_t maximum_current_consumption;
T free_device_status; T free_device_status;
}; };
static_assert((sizeof (struct data_fields<char[0]>)) == 112); static_assert((sizeof (struct data_fields<char[0]>)) == 112);
} }
namespace device_reply { namespace device_reply {
constexpr uint32_t command_code = 0x7; constexpr uint32_t command_code = 0x7;
struct data_fields { struct data_fields {
}; };
} }
namespace data_transfer { namespace data_transfer {
constexpr uint32_t command_code = 0x8; constexpr uint32_t command_code = 0x8;
template <typename T> template <typename T>
struct data_fields { struct data_fields {
uint32_t function_type; uint32_t function_type;
T data; T data;
}; };
static_assert((sizeof (struct data_fields<char[0]>)) == 4); static_assert((sizeof (struct data_fields<char[0]>)) == 4);
} }
namespace get_condition { namespace get_condition {
constexpr uint32_t command_code = 0x9; constexpr uint32_t command_code = 0x9;
struct data_fields { struct data_fields {
uint32_t function_type; uint32_t function_type;
}; };
static_assert((sizeof (struct data_fields)) == 4); static_assert((sizeof (struct data_fields)) == 4);
} }
namespace get_media_info { namespace get_media_info {
constexpr uint32_t command_code = 0xa; constexpr uint32_t command_code = 0xa;
struct data_fields { struct data_fields {
uint32_t function_type; uint32_t function_type;
uint32_t pt; uint32_t pt;
}; };
static_assert((sizeof (struct data_fields)) == 8); static_assert((sizeof (struct data_fields)) == 8);
} }
namespace block_read { namespace block_read {
constexpr uint32_t command_code = 0xb; constexpr uint32_t command_code = 0xb;
struct data_fields { struct data_fields {
uint32_t function_type; uint32_t function_type;
uint8_t pt; uint8_t pt;
uint8_t phase; uint8_t phase;
uint16_t block_no; uint16_t block_no;
}; };
static_assert((sizeof (struct data_fields)) == 8); static_assert((sizeof (struct data_fields)) == 8);
} }
namespace block_write { namespace block_write {
constexpr uint32_t command_code = 0xc; constexpr uint32_t command_code = 0xc;
template <typename T> template <typename T>
struct data_fields { struct data_fields {
uint32_t function_type; uint32_t function_type;
@ -126,106 +132,107 @@ namespace block_write {
uint16_t block_no; uint16_t block_no;
T written_data; T written_data;
}; };
static_assert((sizeof (struct data_fields<char[0]>)) == 8); static_assert((sizeof (struct data_fields<char[0]>)) == 8);
} }
namespace get_last_error { namespace get_last_error {
constexpr uint32_t command_code = 0xd; constexpr uint32_t command_code = 0xd;
struct data_fields { struct data_fields {
uint32_t function_type; uint32_t function_type;
uint8_t pt; uint8_t pt;
uint8_t phase; uint8_t phase;
uint16_t block_no; uint16_t block_no;
}; };
static_assert((sizeof (struct data_fields)) == 8); static_assert((sizeof (struct data_fields)) == 8);
} }
namespace set_condition { namespace set_condition {
constexpr uint32_t command_code = 0xe; constexpr uint32_t command_code = 0xe;
template <typename T> template <typename T>
struct data_fields { struct data_fields {
uint32_t function_type; uint32_t function_type;
T write_in_data; T write_in_data;
}; };
static_assert((sizeof (struct data_fields<char[0]>)) == 4); static_assert((sizeof (struct data_fields<char[0]>)) == 4);
} }
namespace ft4_control { namespace ft4_control {
constexpr uint32_t command_code = 0xf; constexpr uint32_t command_code = 0xf;
template <typename T> template <typename T>
struct data_fields { struct data_fields {
uint32_t function_type; uint32_t function_type;
T ft4_data; T ft4_data;
}; };
static_assert((sizeof (struct data_fields<char[0]>)) == 4); static_assert((sizeof (struct data_fields<char[0]>)) == 4);
} }
namespace ar_control { namespace ar_control {
constexpr uint32_t command_code = 0x10; constexpr uint32_t command_code = 0x10;
template <typename T> template <typename T>
struct data_fields { struct data_fields {
uint32_t function_type; uint32_t function_type;
T data; T data;
}; };
static_assert((sizeof (struct data_fields<char[0]>)) == 4); static_assert((sizeof (struct data_fields<char[0]>)) == 4);
} }
namespace function_type_unknown { namespace function_type_unknown {
constexpr uint32_t command_code = 0xfe; constexpr uint32_t command_code = 0xfe;
struct data_fields { struct data_fields {
}; };
} }
namespace command_unknown { namespace command_unknown {
constexpr uint32_t command_code = 0xfd; constexpr uint32_t command_code = 0xfd;
struct data_fields { struct data_fields {
}; };
} }
namespace transmit_again { namespace transmit_again {
constexpr uint32_t command_code = 0xfc; constexpr uint32_t command_code = 0xfc;
struct data_fields { struct data_fields {
}; };
} }
namespace file_error { namespace file_error {
constexpr uint32_t command_code = 0xfb; constexpr uint32_t command_code = 0xfb;
struct data_fields { struct data_fields {
uint32_t function_error_code; uint32_t function_error_code;
}; };
static_assert((sizeof (struct data_fields)) == 4); static_assert((sizeof (struct data_fields)) == 4);
} }
namespace lcd_error { namespace lcd_error {
constexpr uint32_t command_code = 0xfa; constexpr uint32_t command_code = 0xfa;
struct data_fields { struct data_fields {
uint32_t function_error_code; uint32_t function_error_code;
}; };
static_assert((sizeof (struct data_fields)) == 4); static_assert((sizeof (struct data_fields)) == 4);
} }
namespace ar_error { namespace ar_error {
constexpr uint32_t command_code = 0xf9; constexpr uint32_t command_code = 0xf9;
struct data_fields { struct data_fields {
uint32_t function_error_code; uint32_t function_error_code;
}; };
static_assert((sizeof (struct data_fields)) == 4); static_assert((sizeof (struct data_fields)) == 4);
} }

View File

@ -37,6 +37,8 @@ def command_namespace(namespace: CommandNamespace,
if const in {1, 2, 4}: if const in {1, 2, 4}:
bits = const * 8 bits = const * 8
yield f"uint{bits}_t {field_name};" yield f"uint{bits}_t {field_name};"
elif field_name == "device_id":
yield f"struct device_id {field_name};"
else: else:
yield f"uint8_t {field_name}[{const}];" yield f"uint8_t {field_name}[{const}];"
elif const == 0: elif const == 0:
@ -155,6 +157,11 @@ def new_aggregator():
def headers(): def headers():
yield "#include <cstdint>" yield "#include <cstdint>"
yield "" yield ""
yield "struct device_id {"
yield "uint32_t ft;"
yield "uint32_t fd[3];"
yield "};"
yield "static_assert((sizeof (struct device_id)) == 16);"
input_file = sys.argv[1] input_file = sys.argv[1]
rows = read_input(input_file) rows = read_input(input_file)