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:
parent
9bd79c6664
commit
39aa6b75a6
@ -54,6 +54,15 @@ CUBE_OBJ = \
|
||||
example/cube.elf: LDSCRIPT = $(LIB)/alt.lds
|
||||
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 = \
|
||||
example/maple_controller.o \
|
||||
vga.o \
|
||||
|
@ -1,37 +1,116 @@
|
||||
#include <bit>
|
||||
|
||||
#include "vga.hpp"
|
||||
#include "align.hpp"
|
||||
|
||||
#include "maple/maple.hpp"
|
||||
#include "maple/maple_bus_bits.hpp"
|
||||
#include "maple/maple_bus_commands.hpp"
|
||||
#include "maple/maple_bus_ft0.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));
|
||||
uint32_t _command_buf[1024 / 4 + 32] = {0};
|
||||
uint32_t _receive_buf[1024 / 4 + 32] = {0};
|
||||
|
||||
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>)));
|
||||
static uint32_t * command_buf;
|
||||
static uint32_t * receive_buf;
|
||||
|
||||
uint32_t _command_buf[host_command_size * 4 + 32] = {0};
|
||||
uint32_t _receive_buf[command_response_size * 4 + 32] = {0};
|
||||
struct port_state {
|
||||
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()
|
||||
{
|
||||
uint32_t * command_buf = align_32byte(_command_buf);
|
||||
uint32_t * receive_buf = align_32byte(_receive_buf);
|
||||
command_buf = align_32byte(_command_buf);
|
||||
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);
|
||||
while (1) {
|
||||
v_sync_out();
|
||||
v_sync_in();
|
||||
do_device_request();
|
||||
};
|
||||
}
|
||||
|
37
example/maple_device_request.cpp
Normal file
37
example/maple_device_request.cpp
Normal 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);
|
||||
}
|
@ -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,
|
||||
uint32_t destination_port,
|
||||
uint8_t destination_ap)
|
||||
uint8_t destination_ap,
|
||||
uint32_t function_type)
|
||||
{
|
||||
init_host_command(buf, receive_buf,
|
||||
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;
|
||||
// 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,
|
||||
|
@ -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,
|
||||
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,
|
||||
uint32_t destination_port,
|
||||
|
@ -1,38 +1,44 @@
|
||||
#include <cstdint>
|
||||
|
||||
struct device_id {
|
||||
uint32_t ft;
|
||||
uint32_t fd[3];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct device_id)) == 16);
|
||||
namespace device_request {
|
||||
constexpr uint32_t command_code = 0x1;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
};
|
||||
}
|
||||
|
||||
namespace all_status_request {
|
||||
constexpr uint32_t command_code = 0x2;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
};
|
||||
}
|
||||
|
||||
namespace device_reset {
|
||||
constexpr uint32_t command_code = 0x3;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
};
|
||||
}
|
||||
|
||||
namespace device_kill {
|
||||
constexpr uint32_t command_code = 0x4;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
};
|
||||
}
|
||||
|
||||
namespace device_status {
|
||||
constexpr uint32_t command_code = 0x5;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
uint8_t device_id[16];
|
||||
struct device_id device_id;
|
||||
uint8_t destination_code;
|
||||
uint8_t connection_direction;
|
||||
uint8_t product_name[30];
|
||||
@ -40,16 +46,16 @@ namespace device_status {
|
||||
uint16_t low_consumption_standby_current;
|
||||
uint16_t maximum_current_consumption;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 112);
|
||||
}
|
||||
|
||||
namespace device_all_status {
|
||||
constexpr uint32_t command_code = 0x6;
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct data_fields {
|
||||
uint8_t device_id[16];
|
||||
struct device_id device_id;
|
||||
uint8_t destination_code;
|
||||
uint8_t connection_direction;
|
||||
uint8_t product_name[30];
|
||||
@ -58,66 +64,66 @@ namespace device_all_status {
|
||||
uint16_t maximum_current_consumption;
|
||||
T free_device_status;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields<char[0]>)) == 112);
|
||||
}
|
||||
|
||||
namespace device_reply {
|
||||
constexpr uint32_t command_code = 0x7;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
};
|
||||
}
|
||||
|
||||
namespace data_transfer {
|
||||
constexpr uint32_t command_code = 0x8;
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct data_fields {
|
||||
uint32_t function_type;
|
||||
T data;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields<char[0]>)) == 4);
|
||||
}
|
||||
|
||||
namespace get_condition {
|
||||
constexpr uint32_t command_code = 0x9;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
uint32_t function_type;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 4);
|
||||
}
|
||||
|
||||
namespace get_media_info {
|
||||
constexpr uint32_t command_code = 0xa;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
uint32_t function_type;
|
||||
uint32_t pt;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 8);
|
||||
}
|
||||
|
||||
namespace block_read {
|
||||
constexpr uint32_t command_code = 0xb;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
uint32_t function_type;
|
||||
uint8_t pt;
|
||||
uint8_t phase;
|
||||
uint16_t block_no;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 8);
|
||||
}
|
||||
|
||||
namespace block_write {
|
||||
constexpr uint32_t command_code = 0xc;
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct data_fields {
|
||||
uint32_t function_type;
|
||||
@ -126,106 +132,107 @@ namespace block_write {
|
||||
uint16_t block_no;
|
||||
T written_data;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields<char[0]>)) == 8);
|
||||
}
|
||||
|
||||
namespace get_last_error {
|
||||
constexpr uint32_t command_code = 0xd;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
uint32_t function_type;
|
||||
uint8_t pt;
|
||||
uint8_t phase;
|
||||
uint16_t block_no;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 8);
|
||||
}
|
||||
|
||||
namespace set_condition {
|
||||
constexpr uint32_t command_code = 0xe;
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct data_fields {
|
||||
uint32_t function_type;
|
||||
T write_in_data;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields<char[0]>)) == 4);
|
||||
}
|
||||
|
||||
namespace ft4_control {
|
||||
constexpr uint32_t command_code = 0xf;
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct data_fields {
|
||||
uint32_t function_type;
|
||||
T ft4_data;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields<char[0]>)) == 4);
|
||||
}
|
||||
|
||||
namespace ar_control {
|
||||
constexpr uint32_t command_code = 0x10;
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct data_fields {
|
||||
uint32_t function_type;
|
||||
T data;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields<char[0]>)) == 4);
|
||||
}
|
||||
|
||||
namespace function_type_unknown {
|
||||
constexpr uint32_t command_code = 0xfe;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
};
|
||||
}
|
||||
|
||||
namespace command_unknown {
|
||||
constexpr uint32_t command_code = 0xfd;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
};
|
||||
}
|
||||
|
||||
namespace transmit_again {
|
||||
constexpr uint32_t command_code = 0xfc;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
};
|
||||
}
|
||||
|
||||
namespace file_error {
|
||||
constexpr uint32_t command_code = 0xfb;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
uint32_t function_error_code;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 4);
|
||||
}
|
||||
|
||||
namespace lcd_error {
|
||||
constexpr uint32_t command_code = 0xfa;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
uint32_t function_error_code;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 4);
|
||||
}
|
||||
|
||||
namespace ar_error {
|
||||
constexpr uint32_t command_code = 0xf9;
|
||||
|
||||
|
||||
struct data_fields {
|
||||
uint32_t function_error_code;
|
||||
};
|
||||
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 4);
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,8 @@ def command_namespace(namespace: CommandNamespace,
|
||||
if const in {1, 2, 4}:
|
||||
bits = const * 8
|
||||
yield f"uint{bits}_t {field_name};"
|
||||
elif field_name == "device_id":
|
||||
yield f"struct device_id {field_name};"
|
||||
else:
|
||||
yield f"uint8_t {field_name}[{const}];"
|
||||
elif const == 0:
|
||||
@ -155,6 +157,11 @@ def new_aggregator():
|
||||
def headers():
|
||||
yield "#include <cstdint>"
|
||||
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]
|
||||
rows = read_input(input_file)
|
||||
|
Loading…
x
Reference in New Issue
Block a user