FIRE3: Add reboot support

master
David Rebbe 2026-06-19 21:58:49 +00:00 committed by Kyle Schwarz
parent 54fb89b675
commit 8af6d5f2a8
11 changed files with 77 additions and 0 deletions

View File

@ -825,6 +825,30 @@ icsneoc2_error_t icsneoc2_device_gptp_status_get(const icsneoc2_device_t* device
return icsneoc2_error_success; return icsneoc2_error_success;
} }
icsneoc2_error_t icsneoc2_device_supports_reboot(const icsneoc2_device_t* device, bool* supported) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!supported) {
return icsneoc2_error_invalid_parameters;
}
*supported = device->device->supportsReboot();
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_reboot(const icsneoc2_device_t* device, bool safe) {
auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) {
return res;
}
if(!device->device->reboot(safe)) {
return icsneoc2_error_transmit_message_failed;
}
return icsneoc2_error_success;
}
icsneoc2_error_t icsneoc2_device_digital_io_get(const icsneoc2_device_t* device, icsneoc2_io_type_t type, uint32_t number, bool* value) { icsneoc2_error_t icsneoc2_device_digital_io_get(const icsneoc2_device_t* device, icsneoc2_io_type_t type, uint32_t number, bool* value) {
auto res = icsneoc2_device_is_valid(device); auto res = icsneoc2_device_is_valid(device);
if(res != icsneoc2_error_success) { if(res != icsneoc2_error_success) {

View File

@ -52,9 +52,11 @@ void init_device(pybind11::module_& m) {
.def("set_digital_io", pybind11::overload_cast<IO, size_t, bool>(&Device::setDigitalIO), pybind11::arg("type"), pybind11::arg("number"), pybind11::arg("value"), pybind11::call_guard<pybind11::gil_scoped_release>()) .def("set_digital_io", pybind11::overload_cast<IO, size_t, bool>(&Device::setDigitalIO), pybind11::arg("type"), pybind11::arg("number"), pybind11::arg("value"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("set_polling_message_limit", &Device::setPollingMessageLimit) .def("set_polling_message_limit", &Device::setPollingMessageLimit)
.def("set_rtc", &Device::setRTC, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("set_rtc", &Device::setRTC, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("reboot", &Device::reboot, pybind11::arg("safe") = false, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("start_script", &Device::startScript, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("start_script", &Device::startScript, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("stop_script", &Device::stopScript, pybind11::call_guard<pybind11::gil_scoped_release>()) .def("stop_script", &Device::stopScript, pybind11::call_guard<pybind11::gil_scoped_release>())
.def("supports_tc10", &Device::supportsTC10) .def("supports_tc10", &Device::supportsTC10)
.def("supports_reboot", &Device::supportsReboot)
.def("supports_live_data", &Device::supportsLiveData) .def("supports_live_data", &Device::supportsLiveData)
.def("subscribe_live_data", &Device::subscribeLiveData, pybind11::arg("message"), pybind11::call_guard<pybind11::gil_scoped_release>()) .def("subscribe_live_data", &Device::subscribeLiveData, pybind11::arg("message"), pybind11::call_guard<pybind11::gil_scoped_release>())
.def("unsubscribe_live_data", &Device::unsubscribeLiveData, pybind11::arg("handle"), pybind11::call_guard<pybind11::gil_scoped_release>()) .def("unsubscribe_live_data", &Device::unsubscribeLiveData, pybind11::arg("handle"), pybind11::call_guard<pybind11::gil_scoped_release>())

View File

@ -3735,6 +3735,15 @@ bool Device::requestTC10Sleep(Network::NetID network) {
return typed->response == ExtendedResponse::OK; return typed->response == ExtendedResponse::OK;
} }
bool Device::reboot(bool safe) {
if(!supportsReboot()) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);
return false;
}
// The device reboots in response to this command, so no reply is expected.
return com->sendCommand(ExtendedCommand::Reboot, { uint8_t(safe ? 1 : 0) });
}
std::optional<TC10StatusMessage> Device::getTC10Status(Network::NetID network) { std::optional<TC10StatusMessage> Device::getTC10Status(Network::NetID network) {
if(!supportsTC10()) { if(!supportsTC10()) {
report(APIEvent::Type::NotSupported, APIEvent::Severity::Error); report(APIEvent::Type::NotSupported, APIEvent::Severity::Error);

View File

@ -862,10 +862,17 @@ public:
virtual bool supportsGPTP() const { return false; } virtual bool supportsGPTP() const { return false; }
virtual bool supportsReboot() const { return false; }
bool requestTC10Wake(Network::NetID network); bool requestTC10Wake(Network::NetID network);
bool requestTC10Sleep(Network::NetID network); bool requestTC10Sleep(Network::NetID network);
// Reboot the device. When safe is true the device boots the Linux rescue image and does not
// load coremini ("safe boot"); otherwise it reboots normally. The device reboots in response,
// so no reply is expected. Only supported on devices where supportsReboot() is true.
bool reboot(bool safe = false);
std::optional<TC10StatusMessage> getTC10Status(Network::NetID network); std::optional<TC10StatusMessage> getTC10Status(Network::NetID network);
std::optional<GPTPStatus> getGPTPStatus(std::chrono::milliseconds timeout = std::chrono::milliseconds(100)); std::optional<GPTPStatus> getGPTPStatus(std::chrono::milliseconds timeout = std::chrono::milliseconds(100));

View File

@ -34,6 +34,8 @@ public:
return supportedNetworks; return supportedNetworks;
} }
bool supportsReboot() const override { return true; }
ProductID getProductID() const override { ProductID getProductID() const override {
return ProductID::Connect; return ProductID::Connect;
} }

View File

@ -53,6 +53,8 @@ public:
} }
size_t getEthernetActivationLineCount() const override { return 2; } size_t getEthernetActivationLineCount() const override { return 2; }
bool supportsReboot() const override { return true; }
ProductID getProductID() const override { ProductID getProductID() const override {
return ProductID::neoVIFIRE3; return ProductID::neoVIFIRE3;
} }

View File

@ -55,6 +55,8 @@ public:
return supportedNetworks; return supportedNetworks;
} }
bool supportsReboot() const override { return true; }
ProductID getProductID() const override { ProductID getProductID() const override {
return ProductID::neoVIFIRE3; return ProductID::neoVIFIRE3;
} }

View File

@ -61,6 +61,8 @@ public:
bool supportsTC10() const override { return true; } bool supportsTC10() const override { return true; }
bool supportsReboot() const override { return true; }
ProductID getProductID() const override { ProductID getProductID() const override {
return ProductID::neoVIFIRE3; return ProductID::neoVIFIRE3;
} }

View File

@ -39,6 +39,8 @@ public:
bool supportsGPTP() const override { return true; } bool supportsGPTP() const override { return true; }
bool supportsReboot() const override { return true; }
ProductID getProductID() const override { ProductID getProductID() const override {
return ProductID::neoVIFIRE3; return ProductID::neoVIFIRE3;
} }

View File

@ -602,6 +602,29 @@ icsneoc2_error_t icsneoc2_device_supports_gptp(const icsneoc2_device_t* device,
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise. * @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_invalid_type otherwise.
*/ */
icsneoc2_error_t icsneoc2_device_gptp_status_get(const icsneoc2_device_t* device, uint32_t timeout_ms, icsneoc2_gptp_status_t* status); icsneoc2_error_t icsneoc2_device_gptp_status_get(const icsneoc2_device_t* device, uint32_t timeout_ms, icsneoc2_gptp_status_t* status);
/**
* Check if the device supports rebooting.
*
* @param[in] device The device to check against.
* @param[out] supported Pointer to a bool to copy the value into.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters otherwise.
*/
icsneoc2_error_t icsneoc2_device_supports_reboot(const icsneoc2_device_t* device, bool* supported);
/**
* Reboot the device. When safe is true the device boots the Linux rescue image and does not load
* coremini ("safe boot"); otherwise it reboots normally. The device reboots in response, so no reply
* is expected. Only supported on devices where icsneoc2_device_supports_reboot() reports true.
*
* @param[in] device The device to reboot.
* @param[in] safe true to reboot into safe boot mode, false to reboot normally.
*
* @return icsneoc2_error_t icsneoc2_error_success if successful, icsneoc2_error_invalid_parameters or icsneoc2_error_transmit_message_failed otherwise.
*/
icsneoc2_error_t icsneoc2_device_reboot(const icsneoc2_device_t* device, bool safe);
/** /**
* Get the current state of a digital I/O pin. * Get the current state of a digital I/O pin.
* *

View File

@ -228,6 +228,8 @@ TEST(icsneoc2, test_icsneoc2_error_invalid_parameters_and_invalid_device)
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_tc10_status_get(NULL, icsneoc2_netid_dwcan_01, &sleep_s, &wake_s)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_tc10_status_get(NULL, icsneoc2_netid_dwcan_01, &sleep_s, &wake_s));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_tc10_status_get(NULL, icsneoc2_netid_dwcan_01, NULL, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_tc10_status_get(NULL, icsneoc2_netid_dwcan_01, NULL, NULL));
} }
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_supports_reboot(NULL, &placeholderBool));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_reboot(NULL, false));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_netid_network_type_get(icsneoc2_netid_dwcan_01, NULL)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_netid_network_type_get(icsneoc2_netid_dwcan_01, NULL));
ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_timestamp_resolution_get(NULL, &placeholderInteger32)); ASSERT_EQ(icsneoc2_error_invalid_parameters, icsneoc2_device_timestamp_resolution_get(NULL, &placeholderInteger32));