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