maple: add maple_bus_commands.h
This commit is contained in:
parent
ec09e98757
commit
c8ed8cdf9e
210
maple_bus_commands.h
Normal file
210
maple_bus_commands.h
Normal file
@ -0,0 +1,210 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "type.h"
|
||||
|
||||
namespace device_request {
|
||||
constexpr uint32_t command_code = 0x1;
|
||||
}
|
||||
|
||||
namespace all_status_request {
|
||||
constexpr uint32_t command_code = 0x2;
|
||||
}
|
||||
|
||||
namespace device_reset {
|
||||
constexpr uint32_t command_code = 0x3;
|
||||
}
|
||||
|
||||
namespace device_kill {
|
||||
constexpr uint32_t command_code = 0x4;
|
||||
}
|
||||
|
||||
namespace device_status {
|
||||
constexpr uint32_t command_code = 0x5;
|
||||
|
||||
struct data_fields {
|
||||
uint8_t device_id[16];
|
||||
uint8_t destination_code[1];
|
||||
uint8_t connection_direction[1];
|
||||
uint8_t product_name[30];
|
||||
uint8_t license[60];
|
||||
uint8_t low_consumption_standby_current[2];
|
||||
uint8_t maximum_current_consumption[2];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 112);
|
||||
}
|
||||
|
||||
namespace device_all_status {
|
||||
constexpr uint32_t command_code = 0x6;
|
||||
|
||||
template <int N>
|
||||
struct data_fields {
|
||||
uint8_t device_id[16];
|
||||
uint8_t destination_code[1];
|
||||
uint8_t connection_direction[1];
|
||||
uint8_t product_name[30];
|
||||
uint8_t license[60];
|
||||
uint8_t low_consumption_standby_current[2];
|
||||
uint8_t maximum_current_consumption[2];
|
||||
uint8_t free_device_status[N];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields<0>)) == 112);
|
||||
}
|
||||
|
||||
namespace device_reply {
|
||||
constexpr uint32_t command_code = 0x7;
|
||||
}
|
||||
|
||||
namespace data_transfer {
|
||||
constexpr uint32_t command_code = 0x8;
|
||||
|
||||
template <int N>
|
||||
struct data_fields {
|
||||
uint8_t data[N];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields<0>)) == 0);
|
||||
}
|
||||
|
||||
namespace get_condition {
|
||||
constexpr uint32_t command_code = 0x9;
|
||||
|
||||
struct data_fields {
|
||||
uint8_t function_type[4];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 4);
|
||||
}
|
||||
|
||||
namespace get_media_info {
|
||||
constexpr uint32_t command_code = 0xa;
|
||||
|
||||
struct data_fields {
|
||||
uint8_t function_type[4];
|
||||
uint8_t pt[4];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 8);
|
||||
}
|
||||
|
||||
namespace block_read {
|
||||
constexpr uint32_t command_code = 0xb;
|
||||
|
||||
struct data_fields {
|
||||
uint8_t function_type[4];
|
||||
uint8_t pt[1];
|
||||
uint8_t phase[1];
|
||||
uint8_t block_no[2];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 8);
|
||||
}
|
||||
|
||||
namespace block_write {
|
||||
constexpr uint32_t command_code = 0xc;
|
||||
|
||||
template <int N>
|
||||
struct data_fields {
|
||||
uint8_t function_type[4];
|
||||
uint8_t pt[1];
|
||||
uint8_t phase[1];
|
||||
uint8_t block_no[2];
|
||||
uint8_t written_data[N];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields<0>)) == 8);
|
||||
}
|
||||
|
||||
namespace get_last_error {
|
||||
constexpr uint32_t command_code = 0xd;
|
||||
|
||||
struct data_fields {
|
||||
uint8_t function_type[4];
|
||||
uint8_t pt[1];
|
||||
uint8_t phase[1];
|
||||
uint8_t block_no[2];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 8);
|
||||
}
|
||||
|
||||
namespace set_condition {
|
||||
constexpr uint32_t command_code = 0xe;
|
||||
|
||||
template <int N>
|
||||
struct data_fields {
|
||||
uint8_t function_type[4];
|
||||
uint8_t write_in_data[N];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields<0>)) == 4);
|
||||
}
|
||||
|
||||
namespace ft4_control {
|
||||
constexpr uint32_t command_code = 0xf;
|
||||
|
||||
template <int N>
|
||||
struct data_fields {
|
||||
uint8_t function_type[4];
|
||||
uint8_t ft4_data[N];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields<0>)) == 4);
|
||||
}
|
||||
|
||||
namespace ar_control {
|
||||
constexpr uint32_t command_code = 0x10;
|
||||
|
||||
template <int N>
|
||||
struct data_fields {
|
||||
uint8_t function_type[4];
|
||||
uint8_t data[N];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields<0>)) == 4);
|
||||
}
|
||||
|
||||
namespace function_type_unknown {
|
||||
constexpr uint32_t command_code = 0xfe;
|
||||
}
|
||||
|
||||
namespace command_unknown {
|
||||
constexpr uint32_t command_code = 0xfd;
|
||||
}
|
||||
|
||||
namespace transmit_again {
|
||||
constexpr uint32_t command_code = 0xfc;
|
||||
}
|
||||
|
||||
namespace file_error {
|
||||
constexpr uint32_t command_code = 0xfb;
|
||||
|
||||
struct data_fields {
|
||||
uint8_t function_error_code[4];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 4);
|
||||
}
|
||||
|
||||
namespace lcd_error {
|
||||
constexpr uint32_t command_code = 0xfa;
|
||||
|
||||
struct data_fields {
|
||||
uint8_t function_error_code[4];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 4);
|
||||
}
|
||||
|
||||
namespace ar_error {
|
||||
constexpr uint32_t command_code = 0xf9;
|
||||
|
||||
struct data_fields {
|
||||
uint8_t function_error_code[4];
|
||||
};
|
||||
|
||||
static_assert((sizeof (struct data_fields)) == 4);
|
||||
}
|
||||
|
160
regs/gen/maple_commands.py
Normal file
160
regs/gen/maple_commands.py
Normal file
@ -0,0 +1,160 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Union
|
||||
import sys
|
||||
|
||||
from sh7091 import read_input
|
||||
from sh7091 import headers
|
||||
from generate import renderer
|
||||
|
||||
@dataclass
|
||||
class CommandNamespace:
|
||||
name: str
|
||||
issuing_right: set[str]
|
||||
command_code: int
|
||||
data_size: int
|
||||
|
||||
def command_namespace(namespace: CommandNamespace,
|
||||
data_fields: list[tuple[str, tuple[int, str]]]):
|
||||
yield f"namespace {namespace.name} {{"
|
||||
yield f"constexpr uint32_t command_code = {hex(namespace.command_code)};"
|
||||
|
||||
if namespace.data_size == (0, None):
|
||||
assert data_fields == []
|
||||
# do nothing
|
||||
else:
|
||||
length, variable = namespace.data_size
|
||||
|
||||
yield ""
|
||||
|
||||
if variable is not None:
|
||||
assert variable.lower() == "n"
|
||||
yield "template <int N>"
|
||||
|
||||
yield "struct data_fields {"
|
||||
|
||||
for field_name, field_size in data_fields:
|
||||
const, var = field_size
|
||||
if var is None:
|
||||
yield f"uint8_t {field_name}[{const}];"
|
||||
elif const == 0:
|
||||
assert var == "n"
|
||||
yield f"uint8_t {field_name}[{var.upper()}];"
|
||||
else:
|
||||
yield f"uint8_t {field_name}[{const} + {var.upper()}];"
|
||||
|
||||
yield "};"
|
||||
|
||||
yield ""
|
||||
|
||||
if variable is not None:
|
||||
assert variable == "n"
|
||||
yield f"static_assert((sizeof (struct data_fields<0>)) == {length});"
|
||||
else:
|
||||
yield f"static_assert((sizeof (struct data_fields)) == {length});"
|
||||
|
||||
yield "}"
|
||||
yield ""
|
||||
|
||||
def parse_data_size(data_size, base, multiple) -> tuple[int, str]:
|
||||
def parse_term(s):
|
||||
try:
|
||||
return int(s, base) * multiple
|
||||
except ValueError:
|
||||
div = s.split("/")
|
||||
if len(div) == 1:
|
||||
# this must be a variable
|
||||
assert multiple == 1, s
|
||||
a, = div
|
||||
return a
|
||||
elif len(div) == 2:
|
||||
# this must be a variable divided by a number
|
||||
a, b = div
|
||||
b = int(b, 10)
|
||||
assert b == multiple
|
||||
return a
|
||||
else:
|
||||
assert False, div
|
||||
|
||||
_terms = data_size.split("+")
|
||||
terms = tuple(parse_term(term) for term in _terms)
|
||||
if len(terms) == 1:
|
||||
term, = terms
|
||||
if type(term) == str:
|
||||
return (0, term)
|
||||
elif type(term) == int:
|
||||
return (term, None)
|
||||
else:
|
||||
assert False, (_terms, terms)
|
||||
elif len(terms) == 2:
|
||||
assert type(terms[0]) == int
|
||||
assert type(terms[1]) == str
|
||||
return terms
|
||||
else:
|
||||
assert False, (_terms, terms)
|
||||
|
||||
def new_aggregator():
|
||||
last_name = None
|
||||
namespace = None
|
||||
data_fields = []
|
||||
all_names = set()
|
||||
|
||||
def process_row(row):
|
||||
nonlocal last_name
|
||||
nonlocal namespace
|
||||
nonlocal data_fields
|
||||
|
||||
if row["name"] == "":
|
||||
assert all(v == "" for v in row.values()), row
|
||||
return
|
||||
|
||||
if row["name"] != last_name:
|
||||
if namespace is not None:
|
||||
yield namespace, data_fields
|
||||
else:
|
||||
assert data_fields == []
|
||||
assert row["name"] != ""
|
||||
last_name = row["name"]
|
||||
issuing_right = set(row["issuing_right"].split(", "))
|
||||
assert all(s in {"host", "peripheral"} for s in issuing_right), row
|
||||
assert issuing_right != set(), issuing_right
|
||||
data_size = parse_data_size(row["data_size"], 16, 4)
|
||||
|
||||
namespace = CommandNamespace(
|
||||
name = row["name"],
|
||||
issuing_right = issuing_right,
|
||||
command_code = int(row["command_code"], 16),
|
||||
data_size = data_size,
|
||||
)
|
||||
data_fields = []
|
||||
# fall through
|
||||
|
||||
assert last_name is None or row["name"] == last_name, (row["name"], last_name)
|
||||
if row["data_field"] != "":
|
||||
assert row["data_field_size"] != ""
|
||||
data_fields.append((
|
||||
row["data_field"],
|
||||
parse_data_size(row["data_field_size"], 10, 1)
|
||||
))
|
||||
|
||||
def terminate():
|
||||
nonlocal namespace
|
||||
nonlocal data_fields
|
||||
if namespace is not None:
|
||||
yield namespace, data_fields
|
||||
|
||||
def process(rows):
|
||||
for row in rows:
|
||||
yield from process_row(row)
|
||||
yield from terminate()
|
||||
|
||||
return process
|
||||
|
||||
input_file = sys.argv[1]
|
||||
rows = read_input(input_file)
|
||||
process = new_aggregator()
|
||||
|
||||
render, out = renderer()
|
||||
render(headers())
|
||||
for namespace, data_fields in process(rows):
|
||||
render(command_namespace(namespace, data_fields))
|
||||
sys.stdout.write(out.getvalue())
|
71
regs/maple_bus_commands.csv
Normal file
71
regs/maple_bus_commands.csv
Normal file
@ -0,0 +1,71 @@
|
||||
"name","issuing_right","command_code","data_size","data_field","data_field_size"
|
||||
"device_request","host","0x01","0x00",,
|
||||
,,,,,
|
||||
"all_status_request","host","0x02","0x00",,
|
||||
,,,,,
|
||||
"device_reset","host","0x03","0x00",,
|
||||
,,,,,
|
||||
"device_kill","host","0x04","0x00",,
|
||||
,,,,,
|
||||
"device_status","peripheral","0x05","0x1c","device_id",16
|
||||
"device_status",,,,"destination_code",1
|
||||
"device_status",,,,"connection_direction",1
|
||||
"device_status",,,,"product_name",30
|
||||
"device_status",,,,"license",60
|
||||
"device_status",,,,"low_consumption_standby_current",2
|
||||
"device_status",,,,"maximum_current_consumption",2
|
||||
,,,,,
|
||||
"device_all_status","peripheral","0x06","0x1c+n/4","device_id",16
|
||||
"device_all_status",,,,"destination_code",1
|
||||
"device_all_status",,,,"connection_direction",1
|
||||
"device_all_status",,,,"product_name",30
|
||||
"device_all_status",,,,"license",60
|
||||
"device_all_status",,,,"low_consumption_standby_current",2
|
||||
"device_all_status",,,,"maximum_current_consumption",2
|
||||
"device_all_status",,,,"free_device_status","n"
|
||||
,,,,,
|
||||
"device_reply","peripheral","0x07","0x00",,
|
||||
,,,,,
|
||||
"data_transfer","peripheral","0x08","n/4","data","n"
|
||||
,,,,,
|
||||
"get_condition","host","0x09","0x01","function_type",4
|
||||
,,,,,
|
||||
"get_media_info","host","0x0a","0x02","function_type",4
|
||||
"get_media_info",,,,"pt",4
|
||||
,,,,,
|
||||
"block_read","host","0x0b","0x02","function_type",4
|
||||
"block_read",,,,"pt",1
|
||||
"block_read",,,,"phase",1
|
||||
"block_read",,,,"block_no",2
|
||||
,,,,,
|
||||
"block_write","host","0x0c","0x02+n/4","function_type",4
|
||||
"block_write",,,,"pt",1
|
||||
"block_write",,,,"phase",1
|
||||
"block_write",,,,"block_no",2
|
||||
"block_write",,,,"written_data","n"
|
||||
,,,,,
|
||||
"get_last_error","host","0x0d","0x02","function_type",4
|
||||
"get_last_error",,,,"pt",1
|
||||
"get_last_error",,,,"phase",1
|
||||
"get_last_error",,,,"block_no",2
|
||||
,,,,,
|
||||
"set_condition","host","0x0e","0x01+n/4","function_type",4
|
||||
"set_condition",,,,"write_in_data","n"
|
||||
,,,,,
|
||||
"ft4_control","host","0x0f","0x01+n/4","function_type",4
|
||||
"ft4_control",,,,"ft4_data","n"
|
||||
,,,,,
|
||||
"ar_control","host","0x10","0x01+n/4","function_type",4
|
||||
"ar_control",,,,"data","n"
|
||||
,,,,,
|
||||
"function_type_unknown","peripheral","0xfe","0x00",,
|
||||
,,,,,
|
||||
"command_unknown","peripheral","0xfd","0x00",,
|
||||
,,,,,
|
||||
"transmit_again","host, peripheral","0xfc","0x00",,
|
||||
,,,,,
|
||||
"file_error","peripheral","0xfb","0x01","function_error_code",4
|
||||
,,,,,
|
||||
"lcd_error","peripheral","0xfa","0x01","function_error_code",4
|
||||
,,,,,
|
||||
"ar_error","peripheral","0xf9","0x01","function_error_code",4
|
|
BIN
regs/maple_bus_commands.ods
Normal file
BIN
regs/maple_bus_commands.ods
Normal file
Binary file not shown.
BIN
regs/maple_bus_ft0.ods
Normal file
BIN
regs/maple_bus_ft0.ods
Normal file
Binary file not shown.
BIN
regs/maple_bus_ft6.ods
Normal file
BIN
regs/maple_bus_ft6.ods
Normal file
Binary file not shown.
BIN
regs/maple_bus_ft6_key_mapping.ods
Normal file
BIN
regs/maple_bus_ft6_key_mapping.ods
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user