Boot reason via watchdog scratch register, reboot/picoboot CLI commands, enum msgpack support
This commit is contained in:
@@ -113,7 +113,7 @@ func closeTargets(targets []target) {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
slog.Error("usage: picomap <info|load|log|test> [args...]")
|
fmt.Fprintf(os.Stderr, "usage: picomap <command> [args...]\n\ncommands:\n info\n load\n log\n reboot\n picoboot\n test\n")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
cmd := os.Args[1]
|
cmd := os.Args[1]
|
||||||
@@ -127,10 +127,14 @@ func main() {
|
|||||||
err = cmdLoad(args)
|
err = cmdLoad(args)
|
||||||
case "log":
|
case "log":
|
||||||
err = cmdLog(args)
|
err = cmdLog(args)
|
||||||
|
case "reboot":
|
||||||
|
err = cmdReboot(args)
|
||||||
|
case "picoboot":
|
||||||
|
err = cmdPICOBOOT(args)
|
||||||
case "test":
|
case "test":
|
||||||
err = cmdTestGroup(args)
|
err = cmdTestGroup(args)
|
||||||
default:
|
default:
|
||||||
slog.Error("usage: picomap <info|load|log|test> [args...]")
|
fmt.Fprintf(os.Stderr, "usage: picomap <command> [args...]\n\ncommands:\n info\n load\n log\n reboot\n picoboot\n test\n")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -145,7 +149,8 @@ func printInfo(via string, info *client.ResponseInfo) {
|
|||||||
"board_id", hex.EncodeToString(info.BoardID[:]),
|
"board_id", hex.EncodeToString(info.BoardID[:]),
|
||||||
"mac", net.HardwareAddr(info.MAC[:]).String(),
|
"mac", net.HardwareAddr(info.MAC[:]).String(),
|
||||||
"ip", net.IP(info.IP[:]).String(),
|
"ip", net.IP(info.IP[:]).String(),
|
||||||
"firmware", info.FirmwareName)
|
"firmware", info.FirmwareName,
|
||||||
|
"boot", info.Boot.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdInfo(args []string) error {
|
func cmdInfo(args []string) error {
|
||||||
@@ -199,6 +204,48 @@ func cmdLog(args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cmdReboot(args []string) error {
|
||||||
|
fs := flag.NewFlagSet("reboot", flag.ExitOnError)
|
||||||
|
tf := addTargetFlags(fs)
|
||||||
|
fs.Parse(args)
|
||||||
|
|
||||||
|
targets, err := tf.connect(500 * time.Millisecond)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closeTargets(targets)
|
||||||
|
|
||||||
|
for _, t := range targets {
|
||||||
|
if err := t.client.Reboot(); err != nil {
|
||||||
|
slog.Error("reboot error", "via", t.name, "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
slog.Info("rebooted", "via", t.name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdPICOBOOT(args []string) error {
|
||||||
|
fs := flag.NewFlagSet("picoboot", flag.ExitOnError)
|
||||||
|
tf := addTargetFlags(fs)
|
||||||
|
fs.Parse(args)
|
||||||
|
|
||||||
|
targets, err := tf.connect(500 * time.Millisecond)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closeTargets(targets)
|
||||||
|
|
||||||
|
for _, t := range targets {
|
||||||
|
if err := t.client.PICOBOOT(); err != nil {
|
||||||
|
slog.Error("picoboot error", "via", t.name, "err", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
slog.Info("picoboot", "via", t.name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func boardSerial(id [8]byte) string {
|
func boardSerial(id [8]byte) string {
|
||||||
return fmt.Sprintf("%02X%02X%02X%02X%02X%02X%02X%02X",
|
return fmt.Sprintf("%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||||
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7])
|
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7])
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ static constexpr handler_entry handlers[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
handlers_init();
|
||||||
dispatch_init();
|
dispatch_init();
|
||||||
dispatch_run(handlers);
|
dispatch_run(handlers);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
extern std::string_view firmware_name;
|
extern std::string_view firmware_name;
|
||||||
|
|
||||||
|
void handlers_init();
|
||||||
std::optional<ResponsePICOBOOT> handle_picoboot(const responder& resp, const RequestPICOBOOT&);
|
std::optional<ResponsePICOBOOT> handle_picoboot(const responder& resp, const RequestPICOBOOT&);
|
||||||
std::optional<ResponseInfo> handle_info(const responder& resp, const RequestInfo&);
|
std::optional<ResponseInfo> handle_info(const responder& resp, const RequestInfo&);
|
||||||
std::optional<ResponseLog> handle_log(const responder& resp, const RequestLog&);
|
std::optional<ResponseLog> handle_log(const responder& resp, const RequestLog&);
|
||||||
|
|||||||
@@ -373,6 +373,10 @@ public:
|
|||||||
requires std::is_integral_v<T> && (!std::is_same_v<T, bool>)
|
requires std::is_integral_v<T> && (!std::is_same_v<T, bool>)
|
||||||
pack_result pack(T n) { return pack_integer(n); }
|
pack_result pack(T n) { return pack_integer(n); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires std::is_enum_v<T>
|
||||||
|
pack_result pack(T v) { return pack_integer(static_cast<std::underlying_type_t<T>>(v)); }
|
||||||
|
|
||||||
pack_result pack(bool v) { return pack_bool(v); }
|
pack_result pack(bool v) { return pack_bool(v); }
|
||||||
pack_result pack(float v) { return pack_float(v); }
|
pack_result pack(float v) { return pack_float(v); }
|
||||||
pack_result pack(double v) { return pack_double(v); }
|
pack_result pack(double v) { return pack_double(v); }
|
||||||
@@ -727,6 +731,16 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires std::is_enum_v<T>
|
||||||
|
result<parser> unpack(const parser &p, T &out) {
|
||||||
|
std::underlying_type_t<T> v;
|
||||||
|
auto r = unpack(p, v);
|
||||||
|
if (!r) return r;
|
||||||
|
out = static_cast<T>(v);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires std::is_integral_v<T> && (!std::is_same_v<T, bool>)
|
requires std::is_integral_v<T> && (!std::is_same_v<T, bool>)
|
||||||
result<parser> unpack(const parser &p, T &out) {
|
result<parser> unpack(const parser &p, T &out) {
|
||||||
|
|||||||
@@ -44,14 +44,20 @@ struct RequestInfo {
|
|||||||
auto as_tuple() { return std::tie(); }
|
auto as_tuple() { return std::tie(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class boot_reason : uint8_t {
|
||||||
|
cold_boot = 0,
|
||||||
|
request_reboot = 1,
|
||||||
|
};
|
||||||
|
|
||||||
struct ResponseInfo {
|
struct ResponseInfo {
|
||||||
static constexpr int8_t ext_id = 5;
|
static constexpr int8_t ext_id = 5;
|
||||||
std::array<uint8_t, 8> board_id;
|
std::array<uint8_t, 8> board_id;
|
||||||
std::array<uint8_t, 6> mac;
|
std::array<uint8_t, 6> mac;
|
||||||
std::array<uint8_t, 4> ip;
|
std::array<uint8_t, 4> ip;
|
||||||
std::string firmware_name;
|
std::string firmware_name;
|
||||||
auto as_tuple() const { return std::tie(board_id, mac, ip, firmware_name); }
|
boot_reason boot;
|
||||||
auto as_tuple() { return std::tie(board_id, mac, ip, firmware_name); }
|
auto as_tuple() const { return std::tie(board_id, mac, ip, firmware_name, boot); }
|
||||||
|
auto as_tuple() { return std::tie(board_id, mac, ip, firmware_name, boot); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RequestLog {
|
struct RequestLog {
|
||||||
|
|||||||
@@ -9,6 +9,17 @@
|
|||||||
|
|
||||||
static constexpr uint32_t XIP_BASE_ADDR = 0x10000000;
|
static constexpr uint32_t XIP_BASE_ADDR = 0x10000000;
|
||||||
static constexpr uint32_t FLASH_SIZE = 2 * 1024 * 1024;
|
static constexpr uint32_t FLASH_SIZE = 2 * 1024 * 1024;
|
||||||
|
static constexpr uint32_t REBOOT_MAGIC = 0x504D5242;
|
||||||
|
|
||||||
|
static boot_reason detected_boot_reason;
|
||||||
|
|
||||||
|
void handlers_init() {
|
||||||
|
if (watchdog_hw->scratch[0] == REBOOT_MAGIC)
|
||||||
|
detected_boot_reason = boot_reason::request_reboot;
|
||||||
|
else
|
||||||
|
detected_boot_reason = boot_reason::cold_boot;
|
||||||
|
watchdog_hw->scratch[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<ResponsePICOBOOT> handle_picoboot(const responder&, const RequestPICOBOOT&) {
|
std::optional<ResponsePICOBOOT> handle_picoboot(const responder&, const RequestPICOBOOT&) {
|
||||||
dispatch_schedule_ms(100, []{ reset_usb_boot(0, 1); });
|
dispatch_schedule_ms(100, []{ reset_usb_boot(0, 1); });
|
||||||
@@ -24,6 +35,7 @@ std::optional<ResponseInfo> handle_info(const responder&, const RequestInfo&) {
|
|||||||
resp.mac = ns.mac;
|
resp.mac = ns.mac;
|
||||||
resp.ip = ns.ip;
|
resp.ip = ns.ip;
|
||||||
resp.firmware_name = firmware_name;
|
resp.firmware_name = firmware_name;
|
||||||
|
resp.boot = detected_boot_reason;
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +79,10 @@ std::optional<ResponseFlashWrite> handle_flash_write(const responder&, const Req
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ResponseReboot> handle_reboot(const responder&, const RequestReboot&) {
|
std::optional<ResponseReboot> handle_reboot(const responder&, const RequestReboot&) {
|
||||||
dispatch_schedule_ms(100, []{ watchdog_reboot(0, 0, 0); });
|
dispatch_schedule_ms(100, []{
|
||||||
|
watchdog_hw->scratch[0] = REBOOT_MAGIC;
|
||||||
|
watchdog_reboot(0, 0, 0);
|
||||||
|
});
|
||||||
return ResponseReboot{};
|
return ResponseReboot{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ static constexpr handler_entry handlers[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
handlers_init();
|
||||||
dispatch_init();
|
dispatch_init();
|
||||||
|
|
||||||
gpio_init(LED_PIN);
|
gpio_init(LED_PIN);
|
||||||
|
|||||||
@@ -6,11 +6,30 @@ type RequestPICOBOOT struct{}
|
|||||||
type ResponsePICOBOOT struct{}
|
type ResponsePICOBOOT struct{}
|
||||||
|
|
||||||
type RequestInfo struct{}
|
type RequestInfo struct{}
|
||||||
|
type BootReason uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
BootCold BootReason = 0
|
||||||
|
BootReboot BootReason = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b BootReason) String() string {
|
||||||
|
switch b {
|
||||||
|
case BootCold:
|
||||||
|
return "cold"
|
||||||
|
case BootReboot:
|
||||||
|
return "reboot"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ResponseInfo struct {
|
type ResponseInfo struct {
|
||||||
BoardID [8]byte
|
BoardID [8]byte
|
||||||
MAC [6]byte
|
MAC [6]byte
|
||||||
IP [4]byte
|
IP [4]byte
|
||||||
FirmwareName string
|
FirmwareName string
|
||||||
|
Boot BootReason
|
||||||
}
|
}
|
||||||
|
|
||||||
type RequestLog struct{}
|
type RequestLog struct{}
|
||||||
|
|||||||
Reference in New Issue
Block a user