mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-09-06 16:13:48 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 422488562f | |||
| 7f1f926c47 | |||
| 9cb1b6b11d |
Binary file not shown.
@@ -310,6 +310,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
|||||||
{"DeveloperSidebarMetric7", {PERSISTENT, INT, "7", "0", 3}},
|
{"DeveloperSidebarMetric7", {PERSISTENT, INT, "7", "0", 3}},
|
||||||
{"DeveloperUI", {PERSISTENT, BOOL, "0", "0", 3}},
|
{"DeveloperUI", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||||
{"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
{"GalaxyDeveloperMode", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_SIMPLE}},
|
||||||
|
{"GalaxyMobileDefault", {PERSISTENT | DONT_LOG, BOOL, "0", "0", 0, SETTINGS_ADVANCED}},
|
||||||
{"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}},
|
{"DeveloperWidgets", {PERSISTENT, BOOL, "1", "0", 3}},
|
||||||
{"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
{"DeviceManagement", {PERSISTENT, BOOL, "1", "0", 1, SETTINGS_SIMPLE}},
|
||||||
{"DeviceShutdown", {PERSISTENT, INT, "6", "6", 1, SETTINGS_SIMPLE}},
|
{"DeviceShutdown", {PERSISTENT, INT, "6", "6", 1, SETTINGS_SIMPLE}},
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +1,2 @@
|
|||||||
extern const uint8_t gitversion[19];
|
extern const uint8_t gitversion[19];
|
||||||
const uint8_t gitversion[19] = "DEV-cec1a0fb-DEBUG";
|
const uint8_t gitversion[19] = "DEV-9cb1b6b1-DEBUG";
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
DEV-cec1a0fb-DEBUG
|
DEV-9cb1b6b1-DEBUG
|
||||||
Binary file not shown.
@@ -45,326 +45,326 @@ const static double MAHA_THRESH_31 = 3.8414588206941227;
|
|||||||
* *
|
* *
|
||||||
* This file is part of 'ekf' *
|
* This file is part of 'ekf' *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void err_fun(double *nom_x, double *delta_x, double *out_5825026556611430403) {
|
void err_fun(double *nom_x, double *delta_x, double *out_694062864366320957) {
|
||||||
out_5825026556611430403[0] = delta_x[0] + nom_x[0];
|
out_694062864366320957[0] = delta_x[0] + nom_x[0];
|
||||||
out_5825026556611430403[1] = delta_x[1] + nom_x[1];
|
out_694062864366320957[1] = delta_x[1] + nom_x[1];
|
||||||
out_5825026556611430403[2] = delta_x[2] + nom_x[2];
|
out_694062864366320957[2] = delta_x[2] + nom_x[2];
|
||||||
out_5825026556611430403[3] = delta_x[3] + nom_x[3];
|
out_694062864366320957[3] = delta_x[3] + nom_x[3];
|
||||||
out_5825026556611430403[4] = delta_x[4] + nom_x[4];
|
out_694062864366320957[4] = delta_x[4] + nom_x[4];
|
||||||
out_5825026556611430403[5] = delta_x[5] + nom_x[5];
|
out_694062864366320957[5] = delta_x[5] + nom_x[5];
|
||||||
out_5825026556611430403[6] = delta_x[6] + nom_x[6];
|
out_694062864366320957[6] = delta_x[6] + nom_x[6];
|
||||||
out_5825026556611430403[7] = delta_x[7] + nom_x[7];
|
out_694062864366320957[7] = delta_x[7] + nom_x[7];
|
||||||
out_5825026556611430403[8] = delta_x[8] + nom_x[8];
|
out_694062864366320957[8] = delta_x[8] + nom_x[8];
|
||||||
}
|
}
|
||||||
void inv_err_fun(double *nom_x, double *true_x, double *out_8876036798993240698) {
|
void inv_err_fun(double *nom_x, double *true_x, double *out_7656216431051591408) {
|
||||||
out_8876036798993240698[0] = -nom_x[0] + true_x[0];
|
out_7656216431051591408[0] = -nom_x[0] + true_x[0];
|
||||||
out_8876036798993240698[1] = -nom_x[1] + true_x[1];
|
out_7656216431051591408[1] = -nom_x[1] + true_x[1];
|
||||||
out_8876036798993240698[2] = -nom_x[2] + true_x[2];
|
out_7656216431051591408[2] = -nom_x[2] + true_x[2];
|
||||||
out_8876036798993240698[3] = -nom_x[3] + true_x[3];
|
out_7656216431051591408[3] = -nom_x[3] + true_x[3];
|
||||||
out_8876036798993240698[4] = -nom_x[4] + true_x[4];
|
out_7656216431051591408[4] = -nom_x[4] + true_x[4];
|
||||||
out_8876036798993240698[5] = -nom_x[5] + true_x[5];
|
out_7656216431051591408[5] = -nom_x[5] + true_x[5];
|
||||||
out_8876036798993240698[6] = -nom_x[6] + true_x[6];
|
out_7656216431051591408[6] = -nom_x[6] + true_x[6];
|
||||||
out_8876036798993240698[7] = -nom_x[7] + true_x[7];
|
out_7656216431051591408[7] = -nom_x[7] + true_x[7];
|
||||||
out_8876036798993240698[8] = -nom_x[8] + true_x[8];
|
out_7656216431051591408[8] = -nom_x[8] + true_x[8];
|
||||||
}
|
}
|
||||||
void H_mod_fun(double *state, double *out_6203949078932441352) {
|
void H_mod_fun(double *state, double *out_2454126163912067491) {
|
||||||
out_6203949078932441352[0] = 1.0;
|
out_2454126163912067491[0] = 1.0;
|
||||||
out_6203949078932441352[1] = 0.0;
|
out_2454126163912067491[1] = 0.0;
|
||||||
out_6203949078932441352[2] = 0.0;
|
out_2454126163912067491[2] = 0.0;
|
||||||
out_6203949078932441352[3] = 0.0;
|
out_2454126163912067491[3] = 0.0;
|
||||||
out_6203949078932441352[4] = 0.0;
|
out_2454126163912067491[4] = 0.0;
|
||||||
out_6203949078932441352[5] = 0.0;
|
out_2454126163912067491[5] = 0.0;
|
||||||
out_6203949078932441352[6] = 0.0;
|
out_2454126163912067491[6] = 0.0;
|
||||||
out_6203949078932441352[7] = 0.0;
|
out_2454126163912067491[7] = 0.0;
|
||||||
out_6203949078932441352[8] = 0.0;
|
out_2454126163912067491[8] = 0.0;
|
||||||
out_6203949078932441352[9] = 0.0;
|
out_2454126163912067491[9] = 0.0;
|
||||||
out_6203949078932441352[10] = 1.0;
|
out_2454126163912067491[10] = 1.0;
|
||||||
out_6203949078932441352[11] = 0.0;
|
out_2454126163912067491[11] = 0.0;
|
||||||
out_6203949078932441352[12] = 0.0;
|
out_2454126163912067491[12] = 0.0;
|
||||||
out_6203949078932441352[13] = 0.0;
|
out_2454126163912067491[13] = 0.0;
|
||||||
out_6203949078932441352[14] = 0.0;
|
out_2454126163912067491[14] = 0.0;
|
||||||
out_6203949078932441352[15] = 0.0;
|
out_2454126163912067491[15] = 0.0;
|
||||||
out_6203949078932441352[16] = 0.0;
|
out_2454126163912067491[16] = 0.0;
|
||||||
out_6203949078932441352[17] = 0.0;
|
out_2454126163912067491[17] = 0.0;
|
||||||
out_6203949078932441352[18] = 0.0;
|
out_2454126163912067491[18] = 0.0;
|
||||||
out_6203949078932441352[19] = 0.0;
|
out_2454126163912067491[19] = 0.0;
|
||||||
out_6203949078932441352[20] = 1.0;
|
out_2454126163912067491[20] = 1.0;
|
||||||
out_6203949078932441352[21] = 0.0;
|
out_2454126163912067491[21] = 0.0;
|
||||||
out_6203949078932441352[22] = 0.0;
|
out_2454126163912067491[22] = 0.0;
|
||||||
out_6203949078932441352[23] = 0.0;
|
out_2454126163912067491[23] = 0.0;
|
||||||
out_6203949078932441352[24] = 0.0;
|
out_2454126163912067491[24] = 0.0;
|
||||||
out_6203949078932441352[25] = 0.0;
|
out_2454126163912067491[25] = 0.0;
|
||||||
out_6203949078932441352[26] = 0.0;
|
out_2454126163912067491[26] = 0.0;
|
||||||
out_6203949078932441352[27] = 0.0;
|
out_2454126163912067491[27] = 0.0;
|
||||||
out_6203949078932441352[28] = 0.0;
|
out_2454126163912067491[28] = 0.0;
|
||||||
out_6203949078932441352[29] = 0.0;
|
out_2454126163912067491[29] = 0.0;
|
||||||
out_6203949078932441352[30] = 1.0;
|
out_2454126163912067491[30] = 1.0;
|
||||||
out_6203949078932441352[31] = 0.0;
|
out_2454126163912067491[31] = 0.0;
|
||||||
out_6203949078932441352[32] = 0.0;
|
out_2454126163912067491[32] = 0.0;
|
||||||
out_6203949078932441352[33] = 0.0;
|
out_2454126163912067491[33] = 0.0;
|
||||||
out_6203949078932441352[34] = 0.0;
|
out_2454126163912067491[34] = 0.0;
|
||||||
out_6203949078932441352[35] = 0.0;
|
out_2454126163912067491[35] = 0.0;
|
||||||
out_6203949078932441352[36] = 0.0;
|
out_2454126163912067491[36] = 0.0;
|
||||||
out_6203949078932441352[37] = 0.0;
|
out_2454126163912067491[37] = 0.0;
|
||||||
out_6203949078932441352[38] = 0.0;
|
out_2454126163912067491[38] = 0.0;
|
||||||
out_6203949078932441352[39] = 0.0;
|
out_2454126163912067491[39] = 0.0;
|
||||||
out_6203949078932441352[40] = 1.0;
|
out_2454126163912067491[40] = 1.0;
|
||||||
out_6203949078932441352[41] = 0.0;
|
out_2454126163912067491[41] = 0.0;
|
||||||
out_6203949078932441352[42] = 0.0;
|
out_2454126163912067491[42] = 0.0;
|
||||||
out_6203949078932441352[43] = 0.0;
|
out_2454126163912067491[43] = 0.0;
|
||||||
out_6203949078932441352[44] = 0.0;
|
out_2454126163912067491[44] = 0.0;
|
||||||
out_6203949078932441352[45] = 0.0;
|
out_2454126163912067491[45] = 0.0;
|
||||||
out_6203949078932441352[46] = 0.0;
|
out_2454126163912067491[46] = 0.0;
|
||||||
out_6203949078932441352[47] = 0.0;
|
out_2454126163912067491[47] = 0.0;
|
||||||
out_6203949078932441352[48] = 0.0;
|
out_2454126163912067491[48] = 0.0;
|
||||||
out_6203949078932441352[49] = 0.0;
|
out_2454126163912067491[49] = 0.0;
|
||||||
out_6203949078932441352[50] = 1.0;
|
out_2454126163912067491[50] = 1.0;
|
||||||
out_6203949078932441352[51] = 0.0;
|
out_2454126163912067491[51] = 0.0;
|
||||||
out_6203949078932441352[52] = 0.0;
|
out_2454126163912067491[52] = 0.0;
|
||||||
out_6203949078932441352[53] = 0.0;
|
out_2454126163912067491[53] = 0.0;
|
||||||
out_6203949078932441352[54] = 0.0;
|
out_2454126163912067491[54] = 0.0;
|
||||||
out_6203949078932441352[55] = 0.0;
|
out_2454126163912067491[55] = 0.0;
|
||||||
out_6203949078932441352[56] = 0.0;
|
out_2454126163912067491[56] = 0.0;
|
||||||
out_6203949078932441352[57] = 0.0;
|
out_2454126163912067491[57] = 0.0;
|
||||||
out_6203949078932441352[58] = 0.0;
|
out_2454126163912067491[58] = 0.0;
|
||||||
out_6203949078932441352[59] = 0.0;
|
out_2454126163912067491[59] = 0.0;
|
||||||
out_6203949078932441352[60] = 1.0;
|
out_2454126163912067491[60] = 1.0;
|
||||||
out_6203949078932441352[61] = 0.0;
|
out_2454126163912067491[61] = 0.0;
|
||||||
out_6203949078932441352[62] = 0.0;
|
out_2454126163912067491[62] = 0.0;
|
||||||
out_6203949078932441352[63] = 0.0;
|
out_2454126163912067491[63] = 0.0;
|
||||||
out_6203949078932441352[64] = 0.0;
|
out_2454126163912067491[64] = 0.0;
|
||||||
out_6203949078932441352[65] = 0.0;
|
out_2454126163912067491[65] = 0.0;
|
||||||
out_6203949078932441352[66] = 0.0;
|
out_2454126163912067491[66] = 0.0;
|
||||||
out_6203949078932441352[67] = 0.0;
|
out_2454126163912067491[67] = 0.0;
|
||||||
out_6203949078932441352[68] = 0.0;
|
out_2454126163912067491[68] = 0.0;
|
||||||
out_6203949078932441352[69] = 0.0;
|
out_2454126163912067491[69] = 0.0;
|
||||||
out_6203949078932441352[70] = 1.0;
|
out_2454126163912067491[70] = 1.0;
|
||||||
out_6203949078932441352[71] = 0.0;
|
out_2454126163912067491[71] = 0.0;
|
||||||
out_6203949078932441352[72] = 0.0;
|
out_2454126163912067491[72] = 0.0;
|
||||||
out_6203949078932441352[73] = 0.0;
|
out_2454126163912067491[73] = 0.0;
|
||||||
out_6203949078932441352[74] = 0.0;
|
out_2454126163912067491[74] = 0.0;
|
||||||
out_6203949078932441352[75] = 0.0;
|
out_2454126163912067491[75] = 0.0;
|
||||||
out_6203949078932441352[76] = 0.0;
|
out_2454126163912067491[76] = 0.0;
|
||||||
out_6203949078932441352[77] = 0.0;
|
out_2454126163912067491[77] = 0.0;
|
||||||
out_6203949078932441352[78] = 0.0;
|
out_2454126163912067491[78] = 0.0;
|
||||||
out_6203949078932441352[79] = 0.0;
|
out_2454126163912067491[79] = 0.0;
|
||||||
out_6203949078932441352[80] = 1.0;
|
out_2454126163912067491[80] = 1.0;
|
||||||
}
|
}
|
||||||
void f_fun(double *state, double dt, double *out_343822199527135251) {
|
void f_fun(double *state, double dt, double *out_1843607112126961388) {
|
||||||
out_343822199527135251[0] = state[0];
|
out_1843607112126961388[0] = state[0];
|
||||||
out_343822199527135251[1] = state[1];
|
out_1843607112126961388[1] = state[1];
|
||||||
out_343822199527135251[2] = state[2];
|
out_1843607112126961388[2] = state[2];
|
||||||
out_343822199527135251[3] = state[3];
|
out_1843607112126961388[3] = state[3];
|
||||||
out_343822199527135251[4] = state[4];
|
out_1843607112126961388[4] = state[4];
|
||||||
out_343822199527135251[5] = dt*((-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]))*state[6] - 9.8100000000000005*state[8] + stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*state[1]) + (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*state[4])) + state[5];
|
out_1843607112126961388[5] = dt*((-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]))*state[6] - 9.8100000000000005*state[8] + stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*state[1]) + (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*state[4])) + state[5];
|
||||||
out_343822199527135251[6] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*state[4])) + state[6];
|
out_1843607112126961388[6] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*state[4])) + state[6];
|
||||||
out_343822199527135251[7] = state[7];
|
out_1843607112126961388[7] = state[7];
|
||||||
out_343822199527135251[8] = state[8];
|
out_1843607112126961388[8] = state[8];
|
||||||
}
|
}
|
||||||
void F_fun(double *state, double dt, double *out_7416815269748566643) {
|
void F_fun(double *state, double dt, double *out_2182262497468252920) {
|
||||||
out_7416815269748566643[0] = 1;
|
out_2182262497468252920[0] = 1;
|
||||||
out_7416815269748566643[1] = 0;
|
out_2182262497468252920[1] = 0;
|
||||||
out_7416815269748566643[2] = 0;
|
out_2182262497468252920[2] = 0;
|
||||||
out_7416815269748566643[3] = 0;
|
out_2182262497468252920[3] = 0;
|
||||||
out_7416815269748566643[4] = 0;
|
out_2182262497468252920[4] = 0;
|
||||||
out_7416815269748566643[5] = 0;
|
out_2182262497468252920[5] = 0;
|
||||||
out_7416815269748566643[6] = 0;
|
out_2182262497468252920[6] = 0;
|
||||||
out_7416815269748566643[7] = 0;
|
out_2182262497468252920[7] = 0;
|
||||||
out_7416815269748566643[8] = 0;
|
out_2182262497468252920[8] = 0;
|
||||||
out_7416815269748566643[9] = 0;
|
out_2182262497468252920[9] = 0;
|
||||||
out_7416815269748566643[10] = 1;
|
out_2182262497468252920[10] = 1;
|
||||||
out_7416815269748566643[11] = 0;
|
out_2182262497468252920[11] = 0;
|
||||||
out_7416815269748566643[12] = 0;
|
out_2182262497468252920[12] = 0;
|
||||||
out_7416815269748566643[13] = 0;
|
out_2182262497468252920[13] = 0;
|
||||||
out_7416815269748566643[14] = 0;
|
out_2182262497468252920[14] = 0;
|
||||||
out_7416815269748566643[15] = 0;
|
out_2182262497468252920[15] = 0;
|
||||||
out_7416815269748566643[16] = 0;
|
out_2182262497468252920[16] = 0;
|
||||||
out_7416815269748566643[17] = 0;
|
out_2182262497468252920[17] = 0;
|
||||||
out_7416815269748566643[18] = 0;
|
out_2182262497468252920[18] = 0;
|
||||||
out_7416815269748566643[19] = 0;
|
out_2182262497468252920[19] = 0;
|
||||||
out_7416815269748566643[20] = 1;
|
out_2182262497468252920[20] = 1;
|
||||||
out_7416815269748566643[21] = 0;
|
out_2182262497468252920[21] = 0;
|
||||||
out_7416815269748566643[22] = 0;
|
out_2182262497468252920[22] = 0;
|
||||||
out_7416815269748566643[23] = 0;
|
out_2182262497468252920[23] = 0;
|
||||||
out_7416815269748566643[24] = 0;
|
out_2182262497468252920[24] = 0;
|
||||||
out_7416815269748566643[25] = 0;
|
out_2182262497468252920[25] = 0;
|
||||||
out_7416815269748566643[26] = 0;
|
out_2182262497468252920[26] = 0;
|
||||||
out_7416815269748566643[27] = 0;
|
out_2182262497468252920[27] = 0;
|
||||||
out_7416815269748566643[28] = 0;
|
out_2182262497468252920[28] = 0;
|
||||||
out_7416815269748566643[29] = 0;
|
out_2182262497468252920[29] = 0;
|
||||||
out_7416815269748566643[30] = 1;
|
out_2182262497468252920[30] = 1;
|
||||||
out_7416815269748566643[31] = 0;
|
out_2182262497468252920[31] = 0;
|
||||||
out_7416815269748566643[32] = 0;
|
out_2182262497468252920[32] = 0;
|
||||||
out_7416815269748566643[33] = 0;
|
out_2182262497468252920[33] = 0;
|
||||||
out_7416815269748566643[34] = 0;
|
out_2182262497468252920[34] = 0;
|
||||||
out_7416815269748566643[35] = 0;
|
out_2182262497468252920[35] = 0;
|
||||||
out_7416815269748566643[36] = 0;
|
out_2182262497468252920[36] = 0;
|
||||||
out_7416815269748566643[37] = 0;
|
out_2182262497468252920[37] = 0;
|
||||||
out_7416815269748566643[38] = 0;
|
out_2182262497468252920[38] = 0;
|
||||||
out_7416815269748566643[39] = 0;
|
out_2182262497468252920[39] = 0;
|
||||||
out_7416815269748566643[40] = 1;
|
out_2182262497468252920[40] = 1;
|
||||||
out_7416815269748566643[41] = 0;
|
out_2182262497468252920[41] = 0;
|
||||||
out_7416815269748566643[42] = 0;
|
out_2182262497468252920[42] = 0;
|
||||||
out_7416815269748566643[43] = 0;
|
out_2182262497468252920[43] = 0;
|
||||||
out_7416815269748566643[44] = 0;
|
out_2182262497468252920[44] = 0;
|
||||||
out_7416815269748566643[45] = dt*(stiffness_front*(-state[2] - state[3] + state[7])/(mass*state[1]) + (-stiffness_front - stiffness_rear)*state[5]/(mass*state[4]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[6]/(mass*state[4]));
|
out_2182262497468252920[45] = dt*(stiffness_front*(-state[2] - state[3] + state[7])/(mass*state[1]) + (-stiffness_front - stiffness_rear)*state[5]/(mass*state[4]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[6]/(mass*state[4]));
|
||||||
out_7416815269748566643[46] = -dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*pow(state[1], 2));
|
out_2182262497468252920[46] = -dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(mass*pow(state[1], 2));
|
||||||
out_7416815269748566643[47] = -dt*stiffness_front*state[0]/(mass*state[1]);
|
out_2182262497468252920[47] = -dt*stiffness_front*state[0]/(mass*state[1]);
|
||||||
out_7416815269748566643[48] = -dt*stiffness_front*state[0]/(mass*state[1]);
|
out_2182262497468252920[48] = -dt*stiffness_front*state[0]/(mass*state[1]);
|
||||||
out_7416815269748566643[49] = dt*((-1 - (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*pow(state[4], 2)))*state[6] - (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*pow(state[4], 2)));
|
out_2182262497468252920[49] = dt*((-1 - (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*pow(state[4], 2)))*state[6] - (-stiffness_front*state[0] - stiffness_rear*state[0])*state[5]/(mass*pow(state[4], 2)));
|
||||||
out_7416815269748566643[50] = dt*(-stiffness_front*state[0] - stiffness_rear*state[0])/(mass*state[4]) + 1;
|
out_2182262497468252920[50] = dt*(-stiffness_front*state[0] - stiffness_rear*state[0])/(mass*state[4]) + 1;
|
||||||
out_7416815269748566643[51] = dt*(-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]));
|
out_2182262497468252920[51] = dt*(-state[4] + (-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(mass*state[4]));
|
||||||
out_7416815269748566643[52] = dt*stiffness_front*state[0]/(mass*state[1]);
|
out_2182262497468252920[52] = dt*stiffness_front*state[0]/(mass*state[1]);
|
||||||
out_7416815269748566643[53] = -9.8100000000000005*dt;
|
out_2182262497468252920[53] = -9.8100000000000005*dt;
|
||||||
out_7416815269748566643[54] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front - pow(center_to_rear, 2)*stiffness_rear)*state[6]/(rotational_inertia*state[4]));
|
out_2182262497468252920[54] = dt*(center_to_front*stiffness_front*(-state[2] - state[3] + state[7])/(rotational_inertia*state[1]) + (-center_to_front*stiffness_front + center_to_rear*stiffness_rear)*state[5]/(rotational_inertia*state[4]) + (-pow(center_to_front, 2)*stiffness_front - pow(center_to_rear, 2)*stiffness_rear)*state[6]/(rotational_inertia*state[4]));
|
||||||
out_7416815269748566643[55] = -center_to_front*dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*pow(state[1], 2));
|
out_2182262497468252920[55] = -center_to_front*dt*stiffness_front*(-state[2] - state[3] + state[7])*state[0]/(rotational_inertia*pow(state[1], 2));
|
||||||
out_7416815269748566643[56] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
|
out_2182262497468252920[56] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
|
||||||
out_7416815269748566643[57] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
|
out_2182262497468252920[57] = -center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
|
||||||
out_7416815269748566643[58] = dt*(-(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*pow(state[4], 2)) - (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*pow(state[4], 2)));
|
out_2182262497468252920[58] = dt*(-(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])*state[5]/(rotational_inertia*pow(state[4], 2)) - (-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])*state[6]/(rotational_inertia*pow(state[4], 2)));
|
||||||
out_7416815269748566643[59] = dt*(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(rotational_inertia*state[4]);
|
out_2182262497468252920[59] = dt*(-center_to_front*stiffness_front*state[0] + center_to_rear*stiffness_rear*state[0])/(rotational_inertia*state[4]);
|
||||||
out_7416815269748566643[60] = dt*(-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])/(rotational_inertia*state[4]) + 1;
|
out_2182262497468252920[60] = dt*(-pow(center_to_front, 2)*stiffness_front*state[0] - pow(center_to_rear, 2)*stiffness_rear*state[0])/(rotational_inertia*state[4]) + 1;
|
||||||
out_7416815269748566643[61] = center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
|
out_2182262497468252920[61] = center_to_front*dt*stiffness_front*state[0]/(rotational_inertia*state[1]);
|
||||||
out_7416815269748566643[62] = 0;
|
out_2182262497468252920[62] = 0;
|
||||||
out_7416815269748566643[63] = 0;
|
out_2182262497468252920[63] = 0;
|
||||||
out_7416815269748566643[64] = 0;
|
out_2182262497468252920[64] = 0;
|
||||||
out_7416815269748566643[65] = 0;
|
out_2182262497468252920[65] = 0;
|
||||||
out_7416815269748566643[66] = 0;
|
out_2182262497468252920[66] = 0;
|
||||||
out_7416815269748566643[67] = 0;
|
out_2182262497468252920[67] = 0;
|
||||||
out_7416815269748566643[68] = 0;
|
out_2182262497468252920[68] = 0;
|
||||||
out_7416815269748566643[69] = 0;
|
out_2182262497468252920[69] = 0;
|
||||||
out_7416815269748566643[70] = 1;
|
out_2182262497468252920[70] = 1;
|
||||||
out_7416815269748566643[71] = 0;
|
out_2182262497468252920[71] = 0;
|
||||||
out_7416815269748566643[72] = 0;
|
out_2182262497468252920[72] = 0;
|
||||||
out_7416815269748566643[73] = 0;
|
out_2182262497468252920[73] = 0;
|
||||||
out_7416815269748566643[74] = 0;
|
out_2182262497468252920[74] = 0;
|
||||||
out_7416815269748566643[75] = 0;
|
out_2182262497468252920[75] = 0;
|
||||||
out_7416815269748566643[76] = 0;
|
out_2182262497468252920[76] = 0;
|
||||||
out_7416815269748566643[77] = 0;
|
out_2182262497468252920[77] = 0;
|
||||||
out_7416815269748566643[78] = 0;
|
out_2182262497468252920[78] = 0;
|
||||||
out_7416815269748566643[79] = 0;
|
out_2182262497468252920[79] = 0;
|
||||||
out_7416815269748566643[80] = 1;
|
out_2182262497468252920[80] = 1;
|
||||||
}
|
}
|
||||||
void h_25(double *state, double *unused, double *out_8641933420137717402) {
|
void h_25(double *state, double *unused, double *out_4798003278786560335) {
|
||||||
out_8641933420137717402[0] = state[6];
|
out_4798003278786560335[0] = state[6];
|
||||||
}
|
}
|
||||||
void H_25(double *state, double *unused, double *out_7339103169592445424) {
|
void H_25(double *state, double *unused, double *out_7357817989096732331) {
|
||||||
out_7339103169592445424[0] = 0;
|
out_7357817989096732331[0] = 0;
|
||||||
out_7339103169592445424[1] = 0;
|
out_7357817989096732331[1] = 0;
|
||||||
out_7339103169592445424[2] = 0;
|
out_7357817989096732331[2] = 0;
|
||||||
out_7339103169592445424[3] = 0;
|
out_7357817989096732331[3] = 0;
|
||||||
out_7339103169592445424[4] = 0;
|
out_7357817989096732331[4] = 0;
|
||||||
out_7339103169592445424[5] = 0;
|
out_7357817989096732331[5] = 0;
|
||||||
out_7339103169592445424[6] = 1;
|
out_7357817989096732331[6] = 1;
|
||||||
out_7339103169592445424[7] = 0;
|
out_7357817989096732331[7] = 0;
|
||||||
out_7339103169592445424[8] = 0;
|
out_7357817989096732331[8] = 0;
|
||||||
}
|
}
|
||||||
void h_24(double *state, double *unused, double *out_5501280400540853584) {
|
void h_24(double *state, double *unused, double *out_6970490004472512085) {
|
||||||
out_5501280400540853584[0] = state[4];
|
out_6970490004472512085[0] = state[4];
|
||||||
out_5501280400540853584[1] = state[5];
|
out_6970490004472512085[1] = state[5];
|
||||||
}
|
}
|
||||||
void H_24(double *state, double *unused, double *out_9067966288769759493) {
|
void H_24(double *state, double *unused, double *out_1156785309245570905) {
|
||||||
out_9067966288769759493[0] = 0;
|
out_1156785309245570905[0] = 0;
|
||||||
out_9067966288769759493[1] = 0;
|
out_1156785309245570905[1] = 0;
|
||||||
out_9067966288769759493[2] = 0;
|
out_1156785309245570905[2] = 0;
|
||||||
out_9067966288769759493[3] = 0;
|
out_1156785309245570905[3] = 0;
|
||||||
out_9067966288769759493[4] = 1;
|
out_1156785309245570905[4] = 1;
|
||||||
out_9067966288769759493[5] = 0;
|
out_1156785309245570905[5] = 0;
|
||||||
out_9067966288769759493[6] = 0;
|
out_1156785309245570905[6] = 0;
|
||||||
out_9067966288769759493[7] = 0;
|
out_1156785309245570905[7] = 0;
|
||||||
out_9067966288769759493[8] = 0;
|
out_1156785309245570905[8] = 0;
|
||||||
out_9067966288769759493[9] = 0;
|
out_1156785309245570905[9] = 0;
|
||||||
out_9067966288769759493[10] = 0;
|
out_1156785309245570905[10] = 0;
|
||||||
out_9067966288769759493[11] = 0;
|
out_1156785309245570905[11] = 0;
|
||||||
out_9067966288769759493[12] = 0;
|
out_1156785309245570905[12] = 0;
|
||||||
out_9067966288769759493[13] = 0;
|
out_1156785309245570905[13] = 0;
|
||||||
out_9067966288769759493[14] = 1;
|
out_1156785309245570905[14] = 1;
|
||||||
out_9067966288769759493[15] = 0;
|
out_1156785309245570905[15] = 0;
|
||||||
out_9067966288769759493[16] = 0;
|
out_1156785309245570905[16] = 0;
|
||||||
out_9067966288769759493[17] = 0;
|
out_1156785309245570905[17] = 0;
|
||||||
}
|
}
|
||||||
void h_30(double *state, double *unused, double *out_5706507355292462350) {
|
void h_30(double *state, double *unused, double *out_3972351172998717479) {
|
||||||
out_5706507355292462350[0] = state[4];
|
out_3972351172998717479[0] = state[4];
|
||||||
}
|
}
|
||||||
void H_30(double *state, double *unused, double *out_422412828100828669) {
|
void H_30(double *state, double *unused, double *out_7228479041953492261) {
|
||||||
out_422412828100828669[0] = 0;
|
out_7228479041953492261[0] = 0;
|
||||||
out_422412828100828669[1] = 0;
|
out_7228479041953492261[1] = 0;
|
||||||
out_422412828100828669[2] = 0;
|
out_7228479041953492261[2] = 0;
|
||||||
out_422412828100828669[3] = 0;
|
out_7228479041953492261[3] = 0;
|
||||||
out_422412828100828669[4] = 1;
|
out_7228479041953492261[4] = 1;
|
||||||
out_422412828100828669[5] = 0;
|
out_7228479041953492261[5] = 0;
|
||||||
out_422412828100828669[6] = 0;
|
out_7228479041953492261[6] = 0;
|
||||||
out_422412828100828669[7] = 0;
|
out_7228479041953492261[7] = 0;
|
||||||
out_422412828100828669[8] = 0;
|
out_7228479041953492261[8] = 0;
|
||||||
}
|
}
|
||||||
void h_26(double *state, double *unused, double *out_8743293406736795035) {
|
void h_26(double *state, double *unused, double *out_1029322094662128166) {
|
||||||
out_8743293406736795035[0] = state[7];
|
out_1029322094662128166[0] = state[7];
|
||||||
}
|
}
|
||||||
void H_26(double *state, double *unused, double *out_7366137585243049968) {
|
void H_26(double *state, double *unused, double *out_3616314670222676107) {
|
||||||
out_7366137585243049968[0] = 0;
|
out_3616314670222676107[0] = 0;
|
||||||
out_7366137585243049968[1] = 0;
|
out_3616314670222676107[1] = 0;
|
||||||
out_7366137585243049968[2] = 0;
|
out_3616314670222676107[2] = 0;
|
||||||
out_7366137585243049968[3] = 0;
|
out_3616314670222676107[3] = 0;
|
||||||
out_7366137585243049968[4] = 0;
|
out_3616314670222676107[4] = 0;
|
||||||
out_7366137585243049968[5] = 0;
|
out_3616314670222676107[5] = 0;
|
||||||
out_7366137585243049968[6] = 0;
|
out_3616314670222676107[6] = 0;
|
||||||
out_7366137585243049968[7] = 1;
|
out_3616314670222676107[7] = 1;
|
||||||
out_7366137585243049968[8] = 0;
|
out_3616314670222676107[8] = 0;
|
||||||
}
|
}
|
||||||
void h_27(double *state, double *unused, double *out_6768024602127501529) {
|
void h_27(double *state, double *unused, double *out_9195955360068189347) {
|
||||||
out_6768024602127501529[0] = state[3];
|
out_9195955360068189347[0] = state[3];
|
||||||
}
|
}
|
||||||
void H_27(double *state, double *unused, double *out_2597176139901253580) {
|
void H_27(double *state, double *unused, double *out_5053715730153067350) {
|
||||||
out_2597176139901253580[0] = 0;
|
out_5053715730153067350[0] = 0;
|
||||||
out_2597176139901253580[1] = 0;
|
out_5053715730153067350[1] = 0;
|
||||||
out_2597176139901253580[2] = 0;
|
out_5053715730153067350[2] = 0;
|
||||||
out_2597176139901253580[3] = 1;
|
out_5053715730153067350[3] = 1;
|
||||||
out_2597176139901253580[4] = 0;
|
out_5053715730153067350[4] = 0;
|
||||||
out_2597176139901253580[5] = 0;
|
out_5053715730153067350[5] = 0;
|
||||||
out_2597176139901253580[6] = 0;
|
out_5053715730153067350[6] = 0;
|
||||||
out_2597176139901253580[7] = 0;
|
out_5053715730153067350[7] = 0;
|
||||||
out_2597176139901253580[8] = 0;
|
out_5053715730153067350[8] = 0;
|
||||||
}
|
}
|
||||||
void h_29(double *state, double *unused, double *out_5090891545105754924) {
|
void h_29(double *state, double *unused, double *out_9038768691717060202) {
|
||||||
out_5090891545105754924[0] = state[1];
|
out_9038768691717060202[0] = state[1];
|
||||||
}
|
}
|
||||||
void H_29(double *state, double *unused, double *out_4310538866770804613) {
|
void H_29(double *state, double *unused, double *out_3340353003283516317) {
|
||||||
out_4310538866770804613[0] = 0;
|
out_3340353003283516317[0] = 0;
|
||||||
out_4310538866770804613[1] = 1;
|
out_3340353003283516317[1] = 1;
|
||||||
out_4310538866770804613[2] = 0;
|
out_3340353003283516317[2] = 0;
|
||||||
out_4310538866770804613[3] = 0;
|
out_3340353003283516317[3] = 0;
|
||||||
out_4310538866770804613[4] = 0;
|
out_3340353003283516317[4] = 0;
|
||||||
out_4310538866770804613[5] = 0;
|
out_3340353003283516317[5] = 0;
|
||||||
out_4310538866770804613[6] = 0;
|
out_3340353003283516317[6] = 0;
|
||||||
out_4310538866770804613[7] = 0;
|
out_3340353003283516317[7] = 0;
|
||||||
out_4310538866770804613[8] = 0;
|
out_3340353003283516317[8] = 0;
|
||||||
}
|
}
|
||||||
void h_28(double *state, double *unused, double *out_5824514749225839094) {
|
void h_28(double *state, double *unused, double *out_4249115445980516624) {
|
||||||
out_5824514749225839094[0] = state[0];
|
out_4249115445980516624[0] = state[0];
|
||||||
}
|
}
|
||||||
void H_28(double *state, double *unused, double *out_9053806189869216429) {
|
void H_28(double *state, double *unused, double *out_5303983274848842568) {
|
||||||
out_9053806189869216429[0] = 1;
|
out_5303983274848842568[0] = 1;
|
||||||
out_9053806189869216429[1] = 0;
|
out_5303983274848842568[1] = 0;
|
||||||
out_9053806189869216429[2] = 0;
|
out_5303983274848842568[2] = 0;
|
||||||
out_9053806189869216429[3] = 0;
|
out_5303983274848842568[3] = 0;
|
||||||
out_9053806189869216429[4] = 0;
|
out_5303983274848842568[4] = 0;
|
||||||
out_9053806189869216429[5] = 0;
|
out_5303983274848842568[5] = 0;
|
||||||
out_9053806189869216429[6] = 0;
|
out_5303983274848842568[6] = 0;
|
||||||
out_9053806189869216429[7] = 0;
|
out_5303983274848842568[7] = 0;
|
||||||
out_9053806189869216429[8] = 0;
|
out_5303983274848842568[8] = 0;
|
||||||
}
|
}
|
||||||
void h_31(double *state, double *unused, double *out_8917127482422223291) {
|
void h_31(double *state, double *unused, double *out_5644913485036226869) {
|
||||||
out_8917127482422223291[0] = state[8];
|
out_5644913485036226869[0] = state[8];
|
||||||
}
|
}
|
||||||
void H_31(double *state, double *unused, double *out_7308457207715484996) {
|
void H_31(double *state, double *unused, double *out_7388463950973692759) {
|
||||||
out_7308457207715484996[0] = 0;
|
out_7388463950973692759[0] = 0;
|
||||||
out_7308457207715484996[1] = 0;
|
out_7388463950973692759[1] = 0;
|
||||||
out_7308457207715484996[2] = 0;
|
out_7388463950973692759[2] = 0;
|
||||||
out_7308457207715484996[3] = 0;
|
out_7388463950973692759[3] = 0;
|
||||||
out_7308457207715484996[4] = 0;
|
out_7388463950973692759[4] = 0;
|
||||||
out_7308457207715484996[5] = 0;
|
out_7388463950973692759[5] = 0;
|
||||||
out_7308457207715484996[6] = 0;
|
out_7388463950973692759[6] = 0;
|
||||||
out_7308457207715484996[7] = 0;
|
out_7388463950973692759[7] = 0;
|
||||||
out_7308457207715484996[8] = 1;
|
out_7388463950973692759[8] = 1;
|
||||||
}
|
}
|
||||||
#include <eigen3/Eigen/Dense>
|
#include <eigen3/Eigen/Dense>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -518,68 +518,68 @@ void car_update_28(double *in_x, double *in_P, double *in_z, double *in_R, doubl
|
|||||||
void car_update_31(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea) {
|
void car_update_31(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea) {
|
||||||
update<1, 3, 0>(in_x, in_P, h_31, H_31, NULL, in_z, in_R, in_ea, MAHA_THRESH_31);
|
update<1, 3, 0>(in_x, in_P, h_31, H_31, NULL, in_z, in_R, in_ea, MAHA_THRESH_31);
|
||||||
}
|
}
|
||||||
void car_err_fun(double *nom_x, double *delta_x, double *out_5825026556611430403) {
|
void car_err_fun(double *nom_x, double *delta_x, double *out_694062864366320957) {
|
||||||
err_fun(nom_x, delta_x, out_5825026556611430403);
|
err_fun(nom_x, delta_x, out_694062864366320957);
|
||||||
}
|
}
|
||||||
void car_inv_err_fun(double *nom_x, double *true_x, double *out_8876036798993240698) {
|
void car_inv_err_fun(double *nom_x, double *true_x, double *out_7656216431051591408) {
|
||||||
inv_err_fun(nom_x, true_x, out_8876036798993240698);
|
inv_err_fun(nom_x, true_x, out_7656216431051591408);
|
||||||
}
|
}
|
||||||
void car_H_mod_fun(double *state, double *out_6203949078932441352) {
|
void car_H_mod_fun(double *state, double *out_2454126163912067491) {
|
||||||
H_mod_fun(state, out_6203949078932441352);
|
H_mod_fun(state, out_2454126163912067491);
|
||||||
}
|
}
|
||||||
void car_f_fun(double *state, double dt, double *out_343822199527135251) {
|
void car_f_fun(double *state, double dt, double *out_1843607112126961388) {
|
||||||
f_fun(state, dt, out_343822199527135251);
|
f_fun(state, dt, out_1843607112126961388);
|
||||||
}
|
}
|
||||||
void car_F_fun(double *state, double dt, double *out_7416815269748566643) {
|
void car_F_fun(double *state, double dt, double *out_2182262497468252920) {
|
||||||
F_fun(state, dt, out_7416815269748566643);
|
F_fun(state, dt, out_2182262497468252920);
|
||||||
}
|
}
|
||||||
void car_h_25(double *state, double *unused, double *out_8641933420137717402) {
|
void car_h_25(double *state, double *unused, double *out_4798003278786560335) {
|
||||||
h_25(state, unused, out_8641933420137717402);
|
h_25(state, unused, out_4798003278786560335);
|
||||||
}
|
}
|
||||||
void car_H_25(double *state, double *unused, double *out_7339103169592445424) {
|
void car_H_25(double *state, double *unused, double *out_7357817989096732331) {
|
||||||
H_25(state, unused, out_7339103169592445424);
|
H_25(state, unused, out_7357817989096732331);
|
||||||
}
|
}
|
||||||
void car_h_24(double *state, double *unused, double *out_5501280400540853584) {
|
void car_h_24(double *state, double *unused, double *out_6970490004472512085) {
|
||||||
h_24(state, unused, out_5501280400540853584);
|
h_24(state, unused, out_6970490004472512085);
|
||||||
}
|
}
|
||||||
void car_H_24(double *state, double *unused, double *out_9067966288769759493) {
|
void car_H_24(double *state, double *unused, double *out_1156785309245570905) {
|
||||||
H_24(state, unused, out_9067966288769759493);
|
H_24(state, unused, out_1156785309245570905);
|
||||||
}
|
}
|
||||||
void car_h_30(double *state, double *unused, double *out_5706507355292462350) {
|
void car_h_30(double *state, double *unused, double *out_3972351172998717479) {
|
||||||
h_30(state, unused, out_5706507355292462350);
|
h_30(state, unused, out_3972351172998717479);
|
||||||
}
|
}
|
||||||
void car_H_30(double *state, double *unused, double *out_422412828100828669) {
|
void car_H_30(double *state, double *unused, double *out_7228479041953492261) {
|
||||||
H_30(state, unused, out_422412828100828669);
|
H_30(state, unused, out_7228479041953492261);
|
||||||
}
|
}
|
||||||
void car_h_26(double *state, double *unused, double *out_8743293406736795035) {
|
void car_h_26(double *state, double *unused, double *out_1029322094662128166) {
|
||||||
h_26(state, unused, out_8743293406736795035);
|
h_26(state, unused, out_1029322094662128166);
|
||||||
}
|
}
|
||||||
void car_H_26(double *state, double *unused, double *out_7366137585243049968) {
|
void car_H_26(double *state, double *unused, double *out_3616314670222676107) {
|
||||||
H_26(state, unused, out_7366137585243049968);
|
H_26(state, unused, out_3616314670222676107);
|
||||||
}
|
}
|
||||||
void car_h_27(double *state, double *unused, double *out_6768024602127501529) {
|
void car_h_27(double *state, double *unused, double *out_9195955360068189347) {
|
||||||
h_27(state, unused, out_6768024602127501529);
|
h_27(state, unused, out_9195955360068189347);
|
||||||
}
|
}
|
||||||
void car_H_27(double *state, double *unused, double *out_2597176139901253580) {
|
void car_H_27(double *state, double *unused, double *out_5053715730153067350) {
|
||||||
H_27(state, unused, out_2597176139901253580);
|
H_27(state, unused, out_5053715730153067350);
|
||||||
}
|
}
|
||||||
void car_h_29(double *state, double *unused, double *out_5090891545105754924) {
|
void car_h_29(double *state, double *unused, double *out_9038768691717060202) {
|
||||||
h_29(state, unused, out_5090891545105754924);
|
h_29(state, unused, out_9038768691717060202);
|
||||||
}
|
}
|
||||||
void car_H_29(double *state, double *unused, double *out_4310538866770804613) {
|
void car_H_29(double *state, double *unused, double *out_3340353003283516317) {
|
||||||
H_29(state, unused, out_4310538866770804613);
|
H_29(state, unused, out_3340353003283516317);
|
||||||
}
|
}
|
||||||
void car_h_28(double *state, double *unused, double *out_5824514749225839094) {
|
void car_h_28(double *state, double *unused, double *out_4249115445980516624) {
|
||||||
h_28(state, unused, out_5824514749225839094);
|
h_28(state, unused, out_4249115445980516624);
|
||||||
}
|
}
|
||||||
void car_H_28(double *state, double *unused, double *out_9053806189869216429) {
|
void car_H_28(double *state, double *unused, double *out_5303983274848842568) {
|
||||||
H_28(state, unused, out_9053806189869216429);
|
H_28(state, unused, out_5303983274848842568);
|
||||||
}
|
}
|
||||||
void car_h_31(double *state, double *unused, double *out_8917127482422223291) {
|
void car_h_31(double *state, double *unused, double *out_5644913485036226869) {
|
||||||
h_31(state, unused, out_8917127482422223291);
|
h_31(state, unused, out_5644913485036226869);
|
||||||
}
|
}
|
||||||
void car_H_31(double *state, double *unused, double *out_7308457207715484996) {
|
void car_H_31(double *state, double *unused, double *out_7388463950973692759) {
|
||||||
H_31(state, unused, out_7308457207715484996);
|
H_31(state, unused, out_7388463950973692759);
|
||||||
}
|
}
|
||||||
void car_predict(double *in_x, double *in_P, double *in_Q, double dt) {
|
void car_predict(double *in_x, double *in_P, double *in_Q, double dt) {
|
||||||
predict(in_x, in_P, in_Q, dt);
|
predict(in_x, in_P, in_Q, dt);
|
||||||
|
|||||||
@@ -9,27 +9,27 @@ void car_update_27(double *in_x, double *in_P, double *in_z, double *in_R, doubl
|
|||||||
void car_update_29(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
void car_update_29(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
||||||
void car_update_28(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
void car_update_28(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
||||||
void car_update_31(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
void car_update_31(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
||||||
void car_err_fun(double *nom_x, double *delta_x, double *out_5825026556611430403);
|
void car_err_fun(double *nom_x, double *delta_x, double *out_694062864366320957);
|
||||||
void car_inv_err_fun(double *nom_x, double *true_x, double *out_8876036798993240698);
|
void car_inv_err_fun(double *nom_x, double *true_x, double *out_7656216431051591408);
|
||||||
void car_H_mod_fun(double *state, double *out_6203949078932441352);
|
void car_H_mod_fun(double *state, double *out_2454126163912067491);
|
||||||
void car_f_fun(double *state, double dt, double *out_343822199527135251);
|
void car_f_fun(double *state, double dt, double *out_1843607112126961388);
|
||||||
void car_F_fun(double *state, double dt, double *out_7416815269748566643);
|
void car_F_fun(double *state, double dt, double *out_2182262497468252920);
|
||||||
void car_h_25(double *state, double *unused, double *out_8641933420137717402);
|
void car_h_25(double *state, double *unused, double *out_4798003278786560335);
|
||||||
void car_H_25(double *state, double *unused, double *out_7339103169592445424);
|
void car_H_25(double *state, double *unused, double *out_7357817989096732331);
|
||||||
void car_h_24(double *state, double *unused, double *out_5501280400540853584);
|
void car_h_24(double *state, double *unused, double *out_6970490004472512085);
|
||||||
void car_H_24(double *state, double *unused, double *out_9067966288769759493);
|
void car_H_24(double *state, double *unused, double *out_1156785309245570905);
|
||||||
void car_h_30(double *state, double *unused, double *out_5706507355292462350);
|
void car_h_30(double *state, double *unused, double *out_3972351172998717479);
|
||||||
void car_H_30(double *state, double *unused, double *out_422412828100828669);
|
void car_H_30(double *state, double *unused, double *out_7228479041953492261);
|
||||||
void car_h_26(double *state, double *unused, double *out_8743293406736795035);
|
void car_h_26(double *state, double *unused, double *out_1029322094662128166);
|
||||||
void car_H_26(double *state, double *unused, double *out_7366137585243049968);
|
void car_H_26(double *state, double *unused, double *out_3616314670222676107);
|
||||||
void car_h_27(double *state, double *unused, double *out_6768024602127501529);
|
void car_h_27(double *state, double *unused, double *out_9195955360068189347);
|
||||||
void car_H_27(double *state, double *unused, double *out_2597176139901253580);
|
void car_H_27(double *state, double *unused, double *out_5053715730153067350);
|
||||||
void car_h_29(double *state, double *unused, double *out_5090891545105754924);
|
void car_h_29(double *state, double *unused, double *out_9038768691717060202);
|
||||||
void car_H_29(double *state, double *unused, double *out_4310538866770804613);
|
void car_H_29(double *state, double *unused, double *out_3340353003283516317);
|
||||||
void car_h_28(double *state, double *unused, double *out_5824514749225839094);
|
void car_h_28(double *state, double *unused, double *out_4249115445980516624);
|
||||||
void car_H_28(double *state, double *unused, double *out_9053806189869216429);
|
void car_H_28(double *state, double *unused, double *out_5303983274848842568);
|
||||||
void car_h_31(double *state, double *unused, double *out_8917127482422223291);
|
void car_h_31(double *state, double *unused, double *out_5644913485036226869);
|
||||||
void car_H_31(double *state, double *unused, double *out_7308457207715484996);
|
void car_H_31(double *state, double *unused, double *out_7388463950973692759);
|
||||||
void car_predict(double *in_x, double *in_P, double *in_Q, double dt);
|
void car_predict(double *in_x, double *in_P, double *in_Q, double dt);
|
||||||
void car_set_mass(double x);
|
void car_set_mass(double x);
|
||||||
void car_set_rotational_inertia(double x);
|
void car_set_rotational_inertia(double x);
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -5,18 +5,18 @@ void pose_update_4(double *in_x, double *in_P, double *in_z, double *in_R, doubl
|
|||||||
void pose_update_10(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
void pose_update_10(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
||||||
void pose_update_13(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
void pose_update_13(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
||||||
void pose_update_14(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
void pose_update_14(double *in_x, double *in_P, double *in_z, double *in_R, double *in_ea);
|
||||||
void pose_err_fun(double *nom_x, double *delta_x, double *out_4860250714300227404);
|
void pose_err_fun(double *nom_x, double *delta_x, double *out_6507930050433723456);
|
||||||
void pose_inv_err_fun(double *nom_x, double *true_x, double *out_6437944255548658708);
|
void pose_inv_err_fun(double *nom_x, double *true_x, double *out_4828699442560272840);
|
||||||
void pose_H_mod_fun(double *state, double *out_22797630451996970);
|
void pose_H_mod_fun(double *state, double *out_6044345162965507958);
|
||||||
void pose_f_fun(double *state, double dt, double *out_2362837524605346595);
|
void pose_f_fun(double *state, double dt, double *out_2707422486897363634);
|
||||||
void pose_F_fun(double *state, double dt, double *out_4166989473592392013);
|
void pose_F_fun(double *state, double dt, double *out_2783420399776033045);
|
||||||
void pose_h_4(double *state, double *unused, double *out_800785631088066019);
|
void pose_h_4(double *state, double *unused, double *out_6625322830489649201);
|
||||||
void pose_H_4(double *state, double *unused, double *out_2555861026626074297);
|
void pose_H_4(double *state, double *unused, double *out_891826777926427223);
|
||||||
void pose_h_10(double *state, double *unused, double *out_7585285090603906809);
|
void pose_h_10(double *state, double *unused, double *out_495585793918053605);
|
||||||
void pose_H_10(double *state, double *unused, double *out_6341548427213940478);
|
void pose_H_10(double *state, double *unused, double *out_8682725662931185277);
|
||||||
void pose_h_13(double *state, double *unused, double *out_7888682643875678910);
|
void pose_h_13(double *state, double *unused, double *out_6437595282912769194);
|
||||||
void pose_H_13(double *state, double *unused, double *out_5768134851958407098);
|
void pose_H_13(double *state, double *unused, double *out_2320447047405905578);
|
||||||
void pose_h_14(double *state, double *unused, double *out_3441729687180753414);
|
void pose_h_14(double *state, double *unused, double *out_1731855561045144303);
|
||||||
void pose_H_14(double *state, double *unused, double *out_4925284788653666127);
|
void pose_H_14(double *state, double *unused, double *out_1326943304571310822);
|
||||||
void pose_predict(double *in_x, double *in_P, double *in_Q, double dt);
|
void pose_predict(double *in_x, double *in_P, double *in_Q, double dt);
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -4914,6 +4914,15 @@
|
|||||||
"is_parent_toggle": true,
|
"is_parent_toggle": true,
|
||||||
"settings_tier": "simple"
|
"settings_tier": "simple"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "GalaxyMobileDefault",
|
||||||
|
"label": "Try the Big Dipper Web UI",
|
||||||
|
"description": "Open the Big Dipper at the top-level Galaxy link instead of the classic Galaxy. The classic UI remains available at /classic and Big Dipper at /mobile regardless of this toggle.",
|
||||||
|
"picker_description": "Serve the Big Dipper as the default landing page.",
|
||||||
|
"data_type": "bool",
|
||||||
|
"ui_type": "toggle",
|
||||||
|
"settings_tier": "advanced"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "AlphaLongitudinalEnabled",
|
"key": "AlphaLongitudinalEnabled",
|
||||||
"label": "openpilot Longitudinal Control (Alpha)",
|
"label": "openpilot Longitudinal Control (Alpha)",
|
||||||
|
|||||||
@@ -444,15 +444,26 @@ class SpeedLimitController:
|
|||||||
return
|
return
|
||||||
|
|
||||||
current_road_name = sm["mapdOut"].roadName if desired_source == "Map Data" else ""
|
current_road_name = sm["mapdOut"].roadName if desired_source == "Map Data" else ""
|
||||||
|
current_speed = self.target if (self.source != "None" and self.target > 0) else self.last_valid_limit
|
||||||
|
|
||||||
if abs(desired_target - self.previous_target) >= 1 or (current_road_name != self.previous_road_name and current_road_name != ""):
|
# Do not trigger alerts when shifting to fallback or when re-obtaining the same speed limit
|
||||||
|
is_fallback = desired_source == "None" or desired_target == 0
|
||||||
|
same_speed = desired_target > 0 and current_speed > 0 and abs(desired_target - current_speed) < 1
|
||||||
|
|
||||||
|
if not is_fallback and not same_speed and (abs(desired_target - self.previous_target) >= 1 or current_speed == 0):
|
||||||
self.handle_limit_change(desired_source, desired_target, current_road_name, v_ego, sm)
|
self.handle_limit_change(desired_source, desired_target, current_road_name, v_ego, sm)
|
||||||
elif desired_source != self.source and (abs(desired_target - self.target) < 1 or self.target == 0):
|
|
||||||
self.source = desired_source
|
|
||||||
self.target = desired_target
|
|
||||||
else:
|
else:
|
||||||
self.speed_limit_changed_timer = 0
|
self.speed_limit_changed_timer = 0
|
||||||
self.unconfirmed_speed_limit = 0
|
self.unconfirmed_speed_limit = 0
|
||||||
|
if desired_source != self.source or desired_target != self.target:
|
||||||
|
self.source = desired_source
|
||||||
|
self.target = desired_target
|
||||||
|
if desired_source != "None" and desired_target > 0:
|
||||||
|
self.previous_source = desired_source
|
||||||
|
self.previous_target = desired_target
|
||||||
|
if current_road_name != self.previous_road_name and current_road_name != "":
|
||||||
|
self.previous_road_name = current_road_name
|
||||||
|
self.denied_target = 0
|
||||||
|
|
||||||
if self.source != "None" and self.target > 0:
|
if self.source != "None" and self.target > 0:
|
||||||
self.last_valid_limit = self.target
|
self.last_valid_limit = self.target
|
||||||
|
|||||||
@@ -342,6 +342,10 @@ ul { list-style: none; margin: 0; padding: 0; }
|
|||||||
.gx-appbar__back:active { transform: scale(0.92); }
|
.gx-appbar__back:active { transform: scale(0.92); }
|
||||||
|
|
||||||
.gx-appbar__title {
|
.gx-appbar__title {
|
||||||
|
background: linear-gradient(135deg, #8b6cc5 0%, #5ec8c8 55%, #d4789c 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
font-size: var(--fs-lg);
|
font-size: var(--fs-lg);
|
||||||
font-weight: var(--fw-bold);
|
font-weight: var(--fw-bold);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||||
<meta name="apple-mobile-web-app-title" content="Galaxy">
|
<meta name="apple-mobile-web-app-title" content="Big Dipper">
|
||||||
<meta name="format-detection" content="telephone=no">
|
<meta name="format-detection" content="telephone=no">
|
||||||
<meta name="theme-color" content="#8b6cc5" />
|
<meta name="theme-color" content="#8b6cc5" />
|
||||||
<link rel="manifest" href="/assets/mobile/manifest.json" crossorigin="use-credentials">
|
<link rel="manifest" href="/assets/mobile/manifest.json" crossorigin="use-credentials">
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<title>Galaxy</title>
|
<title>Big Dipper</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -105,11 +105,38 @@ export const api = {
|
|||||||
deleteAllRoutes(includePreserved) { return request(`/api/routes/delete_all?include_preserved=${includePreserved}`, { method: "DELETE" }) },
|
deleteAllRoutes(includePreserved) { return request(`/api/routes/delete_all?include_preserved=${includePreserved}`, { method: "DELETE" }) },
|
||||||
getRouteLogs(name) { return request(`/api/routes/${encodeURIComponent(name)}/logs`) },
|
getRouteLogs(name) { return request(`/api/routes/${encodeURIComponent(name)}/logs`) },
|
||||||
|
|
||||||
getScreenRecordings() { return request("/api/screen_recordings/list") },
|
async screenRecordingsStream({ onProgress, onRecordings, signal } = {}) {
|
||||||
|
const res = await fetch("/api/screen_recordings/list", { signal })
|
||||||
|
if (!res.ok || !res.body) throw new Error(`Screen recordings request failed (${res.status})`)
|
||||||
|
const reader = res.body.getReader()
|
||||||
|
const decoder = new TextDecoder()
|
||||||
|
let buffer = ""
|
||||||
|
while (true) {
|
||||||
|
const { value, done } = await reader.read()
|
||||||
|
if (done) break
|
||||||
|
buffer += decoder.decode(value, { stream: true })
|
||||||
|
const events = buffer.split(/\r?\n\r?\n/)
|
||||||
|
buffer = events.pop() || ""
|
||||||
|
for (const event of events) {
|
||||||
|
const lines = event.split(/\r?\n/).filter((l) => l.startsWith("data:"))
|
||||||
|
if (!lines.length) continue
|
||||||
|
try {
|
||||||
|
const payload = JSON.parse(lines.map((l) => l.slice(5).trimStart()).join("\n"))
|
||||||
|
if (Number.isFinite(payload.progress)) onProgress?.(payload.progress)
|
||||||
|
onRecordings?.(Array.isArray(payload.recordings) ? payload.recordings : [])
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
screenRecordingVideoUrl(filename) { return `/api/screen_recordings/download/${encodeURIComponent(filename)}` },
|
||||||
deleteScreenRecording(filename) { return request(`/api/screen_recordings/delete/${encodeURIComponent(filename)}`, { method: "DELETE" }) },
|
deleteScreenRecording(filename) { return request(`/api/screen_recordings/delete/${encodeURIComponent(filename)}`, { method: "DELETE" }) },
|
||||||
deleteAllScreenRecordings() { return request("/api/screen_recordings/delete_all", { method: "DELETE" }) },
|
deleteAllScreenRecordings() { return request("/api/screen_recordings/delete_all", { method: "DELETE" }) },
|
||||||
renameScreenRecording(oldName, newName) { return request("/api/screen_recordings/rename", { method: "POST", data: { old: oldName, new: newName } }) },
|
renameScreenRecording(oldName, newName) { return request("/api/screen_recordings/rename", { method: "POST", data: { old: oldName, new: newName } }) },
|
||||||
|
|
||||||
|
getModelLab() { return request("/api/model-laboratory", { cache: "no-store" }) },
|
||||||
|
saveModelLab(config) { return request("/api/model-laboratory", { method: "PUT", data: config }) },
|
||||||
|
prepareModelLabArtifact(model) { return request("/api/model-laboratory/download", { method: "POST", data: { model } }) },
|
||||||
|
|
||||||
getErrorLogs() { return request("/api/error_logs", { headers: { Accept: "application/json" } }) },
|
getErrorLogs() { return request("/api/error_logs", { headers: { Accept: "application/json" } }) },
|
||||||
getErrorLog(filename) { return fetch(`/api/error_logs/${encodeURIComponent(filename)}`).then((r) => r.text()) },
|
getErrorLog(filename) { return fetch(`/api/error_logs/${encodeURIComponent(filename)}`).then((r) => r.text()) },
|
||||||
deleteErrorLog(filename) { return delOk(`/api/error_logs/${encodeURIComponent(filename)}`) },
|
deleteErrorLog(filename) { return delOk(`/api/error_logs/${encodeURIComponent(filename)}`) },
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { ModelManager } from "./views/ModelManager.js"
|
|||||||
import { Plots } from "./views/Plots.js"
|
import { Plots } from "./views/Plots.js"
|
||||||
import { TestingGround } from "./views/TestingGround.js"
|
import { TestingGround } from "./views/TestingGround.js"
|
||||||
import { ThemeMaker } from "./views/ThemeMaker.js"
|
import { ThemeMaker } from "./views/ThemeMaker.js"
|
||||||
|
import { ModelLaboratory } from "./views/ModelLaboratory.js"
|
||||||
import { Cameras } from "./views/Cameras.js"
|
import { Cameras } from "./views/Cameras.js"
|
||||||
import { store, initRouter, navigate } from "./store.js"
|
import { store, initRouter, navigate } from "./store.js"
|
||||||
import { showSnackbar } from "./api.js"
|
import { showSnackbar } from "./api.js"
|
||||||
@@ -52,6 +53,7 @@ const VIEWS = {
|
|||||||
"/plots": Plots,
|
"/plots": Plots,
|
||||||
"/testing_ground": TestingGround,
|
"/testing_ground": TestingGround,
|
||||||
"/theme_maker": ThemeMaker,
|
"/theme_maker": ThemeMaker,
|
||||||
|
"/model_laboratory": ModelLaboratory,
|
||||||
"/cameras": Cameras,
|
"/cameras": Cameras,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export const AppShell = {
|
|||||||
<button type="button" class="gx-icon-btn gx-menu-btn" aria-label="Menu" @click="store.drawerOpen = true">
|
<button type="button" class="gx-icon-btn gx-menu-btn" aria-label="Menu" @click="store.drawerOpen = true">
|
||||||
<i class="bi bi-list"></i>
|
<i class="bi bi-list"></i>
|
||||||
</button>
|
</button>
|
||||||
<span class="gx-appbar__title">Galaxy</span>
|
<span class="gx-appbar__title">Big Dipper</span>
|
||||||
<div class="gx-searchwrap">
|
<div class="gx-searchwrap">
|
||||||
<input ref="searchInput" class="gx-search gx-appbar__search" type="search" placeholder="Search toggles..."
|
<input ref="searchInput" class="gx-search gx-appbar__search" type="search" placeholder="Search toggles..."
|
||||||
v-model="search" aria-label="Search toggles" />
|
v-model="search" aria-label="Search toggles" />
|
||||||
@@ -128,8 +128,8 @@ export const AppShell = {
|
|||||||
</transition>
|
</transition>
|
||||||
<aside class="gx-drawer" :class="{ open: store.drawerOpen }">
|
<aside class="gx-drawer" :class="{ open: store.drawerOpen }">
|
||||||
<div class="gx-drawer__header">
|
<div class="gx-drawer__header">
|
||||||
<img class="gx-logo" src="/assets/images/main_logo.png" alt="Galaxy logo" />
|
<img class="gx-logo" src="/assets/images/main_logo.png" alt="Big Dipper logo" />
|
||||||
<span class="gx-drawer-title">Galaxy</span>
|
<span class="gx-drawer-title">Big Dipper</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="gx-nav-section">
|
<div class="gx-nav-section">
|
||||||
<div class="gx-nav-section__title">Main</div>
|
<div class="gx-nav-section__title">Main</div>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { pwaState, requestInstall } from "../install.js"
|
||||||
|
|
||||||
export const FIRESTAR_HOST = "galaxy.firestar.link"
|
export const FIRESTAR_HOST = "galaxy.firestar.link"
|
||||||
|
|
||||||
export function isFirestarOrigin() {
|
export function isFirestarOrigin() {
|
||||||
@@ -9,10 +11,6 @@ function isIos() {
|
|||||||
return /iPad|iPhone|iPod/.test(ua) && !/CriOS|FxiOS|OPiOS|EdgiOS/.test(ua)
|
return /iPad|iPhone|iPod/.test(ua) && !/CriOS|FxiOS|OPiOS|EdgiOS/.test(ua)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isStandalone() {
|
|
||||||
return window.matchMedia("(display-mode: standalone)").matches || !!window.navigator.standalone
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PwaInstallSection = {
|
export const PwaInstallSection = {
|
||||||
name: "PwaInstallSection",
|
name: "PwaInstallSection",
|
||||||
props: {
|
props: {
|
||||||
@@ -21,10 +19,8 @@ export const PwaInstallSection = {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
installed: isStandalone(),
|
|
||||||
isIos: isIos(),
|
isIos: isIos(),
|
||||||
onFirestar: isFirestarOrigin(),
|
onFirestar: isFirestarOrigin(),
|
||||||
deferredPrompt: null,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -35,33 +31,19 @@ export const PwaInstallSection = {
|
|||||||
if (this.onFirestar) return window.location.origin
|
if (this.onFirestar) return window.location.origin
|
||||||
return ""
|
return ""
|
||||||
},
|
},
|
||||||
canInstall() { return !!this.deferredPrompt && !this.installed },
|
installed() { return pwaState.installed },
|
||||||
showManual() { return this.isIos && !this.installed && !this.deferredPrompt },
|
canInstall() { return !!pwaState.deferredPrompt && !pwaState.installed },
|
||||||
|
showManual() { return this.isIos && !pwaState.installed && !pwaState.deferredPrompt },
|
||||||
onLocal() { return !this.onFirestar && !this.installUrl },
|
onLocal() { return !this.onFirestar && !this.installUrl },
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
capturePrompt(e) {
|
|
||||||
e.preventDefault()
|
|
||||||
this.deferredPrompt = e
|
|
||||||
},
|
|
||||||
async install() {
|
async install() {
|
||||||
const prompt = this.deferredPrompt
|
await requestInstall()
|
||||||
if (!prompt) return
|
|
||||||
prompt.prompt()
|
|
||||||
try { await prompt.userChoice } catch (e) { /* user cancelled */ }
|
|
||||||
this.deferredPrompt = null
|
|
||||||
this.installed = true
|
|
||||||
},
|
},
|
||||||
installHost() {
|
installHost() {
|
||||||
try { return new URL(this.installUrl).host } catch (e) { return this.installUrl }
|
try { return new URL(this.installUrl).host } catch (e) { return this.installUrl }
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
window.addEventListener("beforeinstallprompt", this.capturePrompt)
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
window.removeEventListener("beforeinstallprompt", this.capturePrompt)
|
|
||||||
},
|
|
||||||
template: `
|
template: `
|
||||||
<section v-if="!installed" class="gx-card gx-install">
|
<section v-if="!installed" class="gx-card gx-install">
|
||||||
<div class="gx-section__header">
|
<div class="gx-section__header">
|
||||||
@@ -128,4 +110,4 @@ export const PwaInstallSection = {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { reactive } from "vue"
|
||||||
|
|
||||||
|
function inStandaloneMode() {
|
||||||
|
return window.matchMedia("(display-mode: standalone)").matches || !!window.navigator.standalone
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pwaState = reactive({
|
||||||
|
deferredPrompt: null,
|
||||||
|
installed: inStandaloneMode(),
|
||||||
|
})
|
||||||
|
|
||||||
|
function capture(event) {
|
||||||
|
event.preventDefault()
|
||||||
|
pwaState.deferredPrompt = event
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("beforeinstallprompt", capture)
|
||||||
|
window.addEventListener("appinstalled", () => {
|
||||||
|
pwaState.deferredPrompt = null
|
||||||
|
pwaState.installed = true
|
||||||
|
})
|
||||||
|
|
||||||
|
export async function requestInstall() {
|
||||||
|
const prompt = pwaState.deferredPrompt
|
||||||
|
if (!prompt) return false
|
||||||
|
prompt.prompt()
|
||||||
|
try { await prompt.userChoice } catch (e) { /* user dismissed */ }
|
||||||
|
pwaState.deferredPrompt = null
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -91,7 +91,7 @@ export function goBack() {
|
|||||||
window.location.hash = prev
|
window.location.hash = prev
|
||||||
}
|
}
|
||||||
|
|
||||||
const NATIVE_ROOTS = new Set(["/", "/settings", "/tools", "/recordings", "/logs", "/tuning", "/navigation", "/vehicle", "/system", "/embed", "/manage_doors", "/galaxy", "/manage_tsk", "/sentry", "/manage_models", "/plots", "/testing_ground", "/theme_maker", "/cameras"])
|
const NATIVE_ROOTS = new Set(["/", "/settings", "/tools", "/recordings", "/logs", "/tuning", "/navigation", "/vehicle", "/system", "/embed", "/manage_doors", "/galaxy", "/manage_tsk", "/sentry", "/manage_models", "/plots", "/testing_ground", "/theme_maker", "/model_laboratory", "/cameras"])
|
||||||
|
|
||||||
export function toolHref(link) {
|
export function toolHref(link) {
|
||||||
const path = link.split("?")[0]
|
const path = link.split("?")[0]
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ export const Logs = {
|
|||||||
</div>
|
</div>
|
||||||
<pre ref="tmuxtail" class="gx-terminal" @scroll.passive="onTmuxScroll">{{ stream.state.log || '(waiting for log output…)' }}</pre>
|
<pre ref="tmuxtail" class="gx-terminal" @scroll.passive="onTmuxScroll">{{ stream.state.log || '(waiting for log output…)' }}</pre>
|
||||||
<div style="display:flex; gap:8px; padding: var(--sp-3); flex-wrap:wrap;">
|
<div style="display:flex; gap:8px; padding: var(--sp-3); flex-wrap:wrap;">
|
||||||
<button type="button" class="gx-btn gx-btn--tonal" @click="stream.togglePause()">{{ stream.state.paused ? '▶️ Resume' : '⏸️ Pause' }}</button>
|
<button type="button" class="gx-btn gx-btn--tonal" @click="stream.togglePause()"><i class="bi" :class="stream.state.paused ? 'bi-play-fill' : 'bi-pause-fill'"></i> {{ stream.state.paused ? 'Resume' : 'Pause' }}</button>
|
||||||
<button type="button" class="gx-btn gx-btn--tonal" @click="captureTmux">Capture Log</button>
|
<button type="button" class="gx-btn gx-btn--tonal" @click="captureTmux">Capture Log</button>
|
||||||
<button type="button" class="gx-btn gx-btn--tonal" @click="deleteAllTmux">Delete All</button>
|
<button type="button" class="gx-btn gx-btn--tonal" @click="deleteAllTmux">Delete All</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,264 @@
|
|||||||
|
import { api, showSnackbar } from "../api.js"
|
||||||
|
import { usePolling } from "../composables.js"
|
||||||
|
|
||||||
|
export const ModelLaboratory = {
|
||||||
|
name: "ModelLaboratory",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true,
|
||||||
|
saving: false,
|
||||||
|
error: "",
|
||||||
|
message: "",
|
||||||
|
dirty: false,
|
||||||
|
chestnutReady: false,
|
||||||
|
isOnroad: false,
|
||||||
|
configuration: { enabled: false, lateralModel: "", longitudinalModel: "" },
|
||||||
|
runtime: {},
|
||||||
|
summary: {},
|
||||||
|
models: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
readyModels() {
|
||||||
|
return this.models.filter((m) => m && m.modelLabArtifactAvailable)
|
||||||
|
},
|
||||||
|
candidates() {
|
||||||
|
const ready = this.readyModels
|
||||||
|
const lat = this.configuration.lateralModel
|
||||||
|
return ready.filter((m) => !lat || m.value !== lat)
|
||||||
|
},
|
||||||
|
selectionError() {
|
||||||
|
if (!this.chestnutReady) return "Connect a firmware-ready Chestnut first."
|
||||||
|
if (this.isOnroad) return "Park before changing the laboratory pair."
|
||||||
|
const lat = this.modelById(this.configuration.lateralModel)
|
||||||
|
const lon = this.modelById(this.configuration.longitudinalModel)
|
||||||
|
if (!lat || !lon) return "Choose two small models with published Chestnut artifacts."
|
||||||
|
if (lat.value === lon.value) return "Lateral and longitudinal models must be different."
|
||||||
|
if (!lat.modelLabArtifactAvailable || !lon.modelLabArtifactAvailable) {
|
||||||
|
return "Both models need a precompiled AMD artifact in the manifest."
|
||||||
|
}
|
||||||
|
if (!lat.modelLabArtifactInstalled || !lon.modelLabArtifactInstalled) {
|
||||||
|
return "Prepare both precompiled AMD artifacts first."
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
},
|
||||||
|
runtimeState() {
|
||||||
|
const r = this.runtime || {}
|
||||||
|
return r.active ? "Pair active" : r.requested ? "Pair requested" : "Inactive"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.poll = usePolling(() => this.refresh(), { interval: 5000 })
|
||||||
|
this.poll.start()
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
this.poll?.destroy()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
modelById(id) {
|
||||||
|
return this.models.find((m) => m.value === id)
|
||||||
|
},
|
||||||
|
modelLabel(id) {
|
||||||
|
return this.modelById(id)?.label || id || "not selected"
|
||||||
|
},
|
||||||
|
artifactStatus(m) {
|
||||||
|
if (m.modelLabArtifactInstalled) return { text: "AMD ready", good: true }
|
||||||
|
if (m.modelLabArtifactAvailable) return { text: "AMD download needed", good: false }
|
||||||
|
return { text: "AMD not published", good: false }
|
||||||
|
},
|
||||||
|
async refresh() {
|
||||||
|
try {
|
||||||
|
const payload = await api.getModelLab()
|
||||||
|
this.applyPayload(payload)
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e?.message || String(e)
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
applyPayload(payload) {
|
||||||
|
payload = payload || {}
|
||||||
|
this.chestnutReady = Boolean(payload.chestnutReady)
|
||||||
|
this.isOnroad = Boolean(payload.isOnroad)
|
||||||
|
this.error = String(payload.configurationError || "")
|
||||||
|
this.runtime = payload.runtime && typeof payload.runtime === "object" ? payload.runtime : {}
|
||||||
|
this.summary = payload.summary && typeof payload.summary === "object" ? payload.summary : {}
|
||||||
|
this.models = Array.isArray(payload.models) ? payload.models : []
|
||||||
|
const cfg = payload.configuration && typeof payload.configuration === "object" ? payload.configuration : {}
|
||||||
|
const draft = { ...this.configuration }
|
||||||
|
this.configuration = {
|
||||||
|
enabled: Boolean(cfg.enabled),
|
||||||
|
lateralModel: this.dirty ? draft.lateralModel : String(cfg.lateralModel || ""),
|
||||||
|
longitudinalModel: this.dirty ? draft.longitudinalModel : String(cfg.longitudinalModel || ""),
|
||||||
|
}
|
||||||
|
this.normalizeSelection()
|
||||||
|
},
|
||||||
|
normalizeSelection() {
|
||||||
|
const ready = this.readyModels
|
||||||
|
if (!this.modelById(this.configuration.lateralModel) && ready.length) {
|
||||||
|
this.configuration.lateralModel = ready[0].value
|
||||||
|
}
|
||||||
|
if (!this.modelById(this.configuration.longitudinalModel) && ready.length > 1) {
|
||||||
|
const lon = ready.find((m) => m.value !== this.configuration.lateralModel)
|
||||||
|
this.configuration.longitudinalModel = lon?.value || ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLateralChange() {
|
||||||
|
this.dirty = true
|
||||||
|
const lon = this.modelById(this.configuration.longitudinalModel)
|
||||||
|
const lat = this.modelById(this.configuration.lateralModel)
|
||||||
|
if (lon && lat && lon.value === lat.value) {
|
||||||
|
this.configuration.longitudinalModel = this.candidates[0]?.value || ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async save(enabled) {
|
||||||
|
if (this.saving) return
|
||||||
|
if (enabled && this.selectionError) {
|
||||||
|
this.error = this.selectionError
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.saving = true
|
||||||
|
this.error = ""
|
||||||
|
this.message = ""
|
||||||
|
try {
|
||||||
|
const payload = await api.saveModelLab({
|
||||||
|
enabled,
|
||||||
|
lateralModel: this.configuration.lateralModel,
|
||||||
|
longitudinalModel: this.configuration.longitudinalModel,
|
||||||
|
})
|
||||||
|
this.dirty = false
|
||||||
|
this.applyPayload(payload)
|
||||||
|
this.message = String(payload?.message || "Model Laboratory configuration saved.")
|
||||||
|
showSnackbar("Model Laboratory saved", "info")
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e?.message || String(e)
|
||||||
|
} finally {
|
||||||
|
this.saving = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async prepareModel(modelId) {
|
||||||
|
if (this.saving || !modelId) return
|
||||||
|
this.saving = true
|
||||||
|
this.error = ""
|
||||||
|
this.message = ""
|
||||||
|
try {
|
||||||
|
const payload = await api.prepareModelLabArtifact(modelId)
|
||||||
|
this.message = String(payload?.message || "Chestnut artifact download queued.")
|
||||||
|
showSnackbar("Chestnut artifact download queued", "info")
|
||||||
|
await this.refresh()
|
||||||
|
} catch (e) {
|
||||||
|
this.error = e?.message || String(e)
|
||||||
|
} finally {
|
||||||
|
this.saving = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div class="gx-view">
|
||||||
|
<div v-if="loading" class="gx-card"><div class="gx-loading">Loading laboratory status...</div></div>
|
||||||
|
<template v-else>
|
||||||
|
<div class="gx-card">
|
||||||
|
<div class="gx-section__header">
|
||||||
|
<i class="bi bi-bezier2"></i>
|
||||||
|
<span class="gx-section__title">Model Laboratory</span>
|
||||||
|
<span class="gx-chip" :style="chestnutReady ? 'color:var(--success);' : 'color:var(--warning);'">{{ chestnutReady ? 'Chestnut ready' : 'Chestnut required' }}</span>
|
||||||
|
<span class="gx-chip" :style="isOnroad ? 'color:var(--warning);' : 'color:var(--success);'">{{ isOnroad ? 'Onroad · locked' : 'Parked · configurable' }}</span>
|
||||||
|
</div>
|
||||||
|
<div style="padding: 0 var(--sp-4) var(--sp-3); color:var(--text-muted); font-size:var(--fs-sm);">
|
||||||
|
Use the lateral judgment of one small model and the longitudinal judgment of another.
|
||||||
|
</div>
|
||||||
|
<div v-if="error" class="gx-alert" style="margin:0 var(--sp-4) var(--sp-3);">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill" style="color:var(--error);"></i>
|
||||||
|
<div class="gx-alert__body"><span style="color:var(--error);">{{ error }}</span></div>
|
||||||
|
</div>
|
||||||
|
<div v-if="message" class="gx-alert gx-alert--info" style="margin:0 var(--sp-4) var(--sp-3);">
|
||||||
|
<i class="bi bi-check-circle-fill"></i>
|
||||||
|
<div class="gx-alert__body"><span>{{ message }}</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gx-card">
|
||||||
|
<div class="gx-section__header">
|
||||||
|
<i class="bi bi-collection"></i>
|
||||||
|
<span class="gx-section__title">Compose a pair</span>
|
||||||
|
<span class="gx-chip" :style="configuration.enabled ? 'background:var(--success);color:var(--on-secondary);' : ''">{{ configuration.enabled ? 'Enabled' : 'Disabled' }}</span>
|
||||||
|
</div>
|
||||||
|
<div style="padding: var(--sp-4); display:grid; gap:var(--sp-3);">
|
||||||
|
<label style="display:grid; gap:4px;">
|
||||||
|
<strong style="font-size:var(--fs-sm);">Lateral model</strong>
|
||||||
|
<small style="color:var(--text-muted); font-size:var(--fs-xs);">Path shape, curvature, lane geometry, and driving desire</small>
|
||||||
|
<select class="gx-field" :value="configuration.lateralModel" @change="configuration.lateralModel = $event.target.value; onLateralChange()">
|
||||||
|
<option value="">Choose a model</option>
|
||||||
|
<option v-for="m in readyModels" :key="m.value" :value="m.value">{{ m.label }} · {{ m.version }}</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label style="display:grid; gap:4px;">
|
||||||
|
<strong style="font-size:var(--fs-sm);">Longitudinal model</strong>
|
||||||
|
<small style="color:var(--text-muted); font-size:var(--fs-xs);">Speed, acceleration, stopping, leads, and scene confidence</small>
|
||||||
|
<select class="gx-field" :value="configuration.longitudinalModel" @change="configuration.longitudinalModel = $event.target.value; dirty = true">
|
||||||
|
<option value="">Choose a model</option>
|
||||||
|
<option v-for="m in candidates" :key="m.value" :value="m.value">{{ m.label }} · {{ m.version }}</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<div style="display:flex; flex-wrap:wrap; gap:6px; align-items:center;">
|
||||||
|
<strong>{{ modelLabel(configuration.lateralModel) }}</strong><span class="gx-row__desc" style="margin:0;">steers</span>
|
||||||
|
<i class="bi bi-arrow-left-right"></i>
|
||||||
|
<strong>{{ modelLabel(configuration.longitudinalModel) }}</strong><span class="gx-row__desc" style="margin:0;">paces</span>
|
||||||
|
</div>
|
||||||
|
<p v-if="selectionError" class="gx-row__desc" style="margin:0; color:var(--warning);">{{ selectionError }}</p>
|
||||||
|
<div style="display:flex; gap:8px; flex-wrap:wrap;">
|
||||||
|
<button type="button" class="gx-btn" :disabled="saving || !!selectionError" @click="save(true)">
|
||||||
|
<i class="bi bi-play-fill"></i> Enable for next drive
|
||||||
|
</button>
|
||||||
|
<button type="button" class="gx-btn gx-btn--tonal" :disabled="saving || isOnroad || !configuration.enabled" @click="save(false)">
|
||||||
|
<i class="bi bi-stop-fill"></i> Disable
|
||||||
|
</button>
|
||||||
|
<button type="button" class="gx-btn gx-btn--tonal" :disabled="saving" @click="refresh">
|
||||||
|
<i class="bi bi-arrow-clockwise"></i> Refresh
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gx-card">
|
||||||
|
<div class="gx-section__header">
|
||||||
|
<i class="bi bi-activity"></i>
|
||||||
|
<span class="gx-section__title">Runtime</span>
|
||||||
|
<span class="gx-chip" :style="runtime.active ? 'background:var(--success);color:var(--on-secondary);' : ''">{{ runtimeState }}</span>
|
||||||
|
</div>
|
||||||
|
<div style="padding: var(--sp-4); display:grid; gap:6px;">
|
||||||
|
<div class="gx-row" style="border-top:none;"><span class="gx-row__label">Lateral</span><span class="gx-row__value">{{ modelLabel(runtime.lateralModel) }}</span></div>
|
||||||
|
<div class="gx-row" style="border-top:none;"><span class="gx-row__label">Longitudinal</span><span class="gx-row__value">{{ modelLabel(runtime.longitudinalModel) }}</span></div>
|
||||||
|
<div v-if="runtime.error" class="gx-alert" style="margin:0;"><i class="bi bi-exclamation-triangle-fill" style="color:var(--error);"></i><div class="gx-alert__body"><span style="color:var(--error);">{{ runtime.error }}</span></div></div>
|
||||||
|
<p class="gx-row__desc" style="margin:0;">Both roles evaluate the same frame at 20 Hz. A runtime failure suppresses that frame and falls back to the built-in QCOM model.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="gx-card">
|
||||||
|
<div class="gx-section__header">
|
||||||
|
<i class="bi bi-cpu"></i>
|
||||||
|
<span class="gx-section__title">Available models</span>
|
||||||
|
<span class="gx-section__count">{{ summary.ready || 0 }} ready to pair · {{ Math.max((summary.published || 0) - (summary.ready || 0), 0) }} available to download</span>
|
||||||
|
</div>
|
||||||
|
<article v-for="m in readyModels" :key="m.value" class="gx-row">
|
||||||
|
<div class="gx-row__info">
|
||||||
|
<span class="gx-row__label">{{ m.label }}</span>
|
||||||
|
<span class="gx-row__desc">{{ m.value }} · {{ m.series || 'Unknown series' }}</span>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex; gap:6px; flex-wrap:wrap; align-items:center;">
|
||||||
|
<span class="gx-chip">{{ m.version || 'unknown version' }}</span>
|
||||||
|
<span class="gx-chip">{{ m.modelSize || 'small' }}</span>
|
||||||
|
<span class="gx-chip" :style="artifactStatus(m).good ? 'color:var(--success);' : 'color:var(--warning);'">{{ artifactStatus(m).text }}</span>
|
||||||
|
<button v-if="m.modelLabArtifactAvailable && !m.modelLabArtifactInstalled" type="button" class="gx-btn gx-btn--tonal" :disabled="saving || isOnroad" @click="prepareModel(m.value)">
|
||||||
|
Prepare for Chestnut
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<div style="padding: var(--sp-3);">
|
||||||
|
<p class="gx-row__desc" style="margin:0;">Model Manager downloads the manifest's precompiled AMD variants. Nothing is compiled on the comma. A normal installed model may still need its separate Chestnut artifact.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}
|
||||||
@@ -59,6 +59,8 @@ export const Pip = {
|
|||||||
mounted() {
|
mounted() {
|
||||||
this._img = null
|
this._img = null
|
||||||
this._sizedFor = null
|
this._sizedFor = null
|
||||||
|
const canvas = this.canvas()
|
||||||
|
if (canvas) { canvas.width = CANVAS_W; canvas.height = CANVAS_H }
|
||||||
this.loadExistingConfig()
|
this.loadExistingConfig()
|
||||||
this.loadSnapshot()
|
this.loadSnapshot()
|
||||||
this.$nextTick(() => this.redraw())
|
this.$nextTick(() => this.redraw())
|
||||||
@@ -70,6 +72,14 @@ export const Pip = {
|
|||||||
canvas() {
|
canvas() {
|
||||||
return this.$refs?.canvas || null
|
return this.$refs?.canvas || null
|
||||||
},
|
},
|
||||||
|
sizeCanvas() {
|
||||||
|
const canvas = this.canvas()
|
||||||
|
const img = this._img
|
||||||
|
if (!canvas || !img) return
|
||||||
|
const w = Math.min(img.naturalWidth, 1280)
|
||||||
|
canvas.width = w
|
||||||
|
canvas.height = Math.round(w * (img.naturalHeight / img.naturalWidth))
|
||||||
|
},
|
||||||
canvasScale() {
|
canvasScale() {
|
||||||
const canvas = this.canvas()
|
const canvas = this.canvas()
|
||||||
const img = this._img
|
const img = this._img
|
||||||
@@ -165,8 +175,7 @@ export const Pip = {
|
|||||||
const img = this._img
|
const img = this._img
|
||||||
if (img && this._sizedFor !== img) {
|
if (img && this._sizedFor !== img) {
|
||||||
this._sizedFor = img
|
this._sizedFor = img
|
||||||
canvas.width = Math.min(img.naturalWidth, 1280)
|
this.sizeCanvas()
|
||||||
canvas.height = Math.round(canvas.width * (img.naturalHeight / img.naturalWidth))
|
|
||||||
} else if (!img && (canvas.width === 0 || this._sizedFor)) {
|
} else if (!img && (canvas.width === 0 || this._sizedFor)) {
|
||||||
this._sizedFor = null
|
this._sizedFor = null
|
||||||
canvas.width = CANVAS_W
|
canvas.width = CANVAS_W
|
||||||
@@ -257,6 +266,7 @@ export const Pip = {
|
|||||||
this._sizedFor = null
|
this._sizedFor = null
|
||||||
this.image = true
|
this.image = true
|
||||||
this.success = "Camera snapshot loaded. Place a center point on each window, then adjust the zoom."
|
this.success = "Camera snapshot loaded. Place a center point on each window, then adjust the zoom."
|
||||||
|
this.sizeCanvas()
|
||||||
this.applyConfigToCanvas()
|
this.applyConfigToCanvas()
|
||||||
this.redraw()
|
this.redraw()
|
||||||
if (cleanup) cleanup()
|
if (cleanup) cleanup()
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { api, showSnackbar } from "../api.js"
|
import { api, showSnackbar } from "../api.js"
|
||||||
import { GalaxyConfirm } from "../components/GalaxyModal.js"
|
import { GalaxyConfirm } from "../components/GalaxyModal.js"
|
||||||
import { GalaxySection } from "../components/GalaxySection.js"
|
|
||||||
import { GalaxyTabs } from "../components/GalaxyTabs.js"
|
import { GalaxyTabs } from "../components/GalaxyTabs.js"
|
||||||
|
import { GxNotice } from "../components/GxNotice.js"
|
||||||
|
import { isFirestarOrigin } from "../components/PwaInstallSection.js"
|
||||||
|
|
||||||
function fmtDuration(seconds) {
|
function fmtDuration(seconds) {
|
||||||
seconds = Number(seconds) || 0
|
seconds = Number(seconds) || 0
|
||||||
@@ -16,6 +17,26 @@ function formatBytes(bytes) {
|
|||||||
return mb >= 1000 ? `${(mb / 1000).toFixed(2)} GB` : `${mb.toFixed(1)} MB`
|
return mb >= 1000 ? `${(mb / 1000).toFixed(2)} GB` : `${mb.toFixed(1)} MB`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getOrdinalSuffix(n) {
|
||||||
|
const s = ["th", "st", "nd", "rd"]
|
||||||
|
const v = n % 100
|
||||||
|
return s[(v - 20) % 10] || s[v] || s[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatScreenDate(dateString) {
|
||||||
|
const date = new Date(dateString)
|
||||||
|
if (Number.isNaN(date.getTime())) return String(dateString || "Unknown date")
|
||||||
|
const month = date.toLocaleString("en-US", { month: "long" })
|
||||||
|
const day = date.getDate()
|
||||||
|
const year = date.getFullYear()
|
||||||
|
let hour = date.getHours()
|
||||||
|
const minute = date.getMinutes()
|
||||||
|
const ampm = hour >= 12 ? "pm" : "am"
|
||||||
|
hour = hour % 12 || 12
|
||||||
|
const minuteStr = minute < 10 ? "0" + minute : minute
|
||||||
|
return `${month} ${day}${getOrdinalSuffix(day)}, ${year} - ${hour}:${minuteStr}${ampm}`
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeRoute(r) {
|
function normalizeRoute(r) {
|
||||||
const name = String(r?.name || "")
|
const name = String(r?.name || "")
|
||||||
const isCustomName = !!r?.isCustomName
|
const isCustomName = !!r?.isCustomName
|
||||||
@@ -33,9 +54,10 @@ function normalizeRoute(r) {
|
|||||||
|
|
||||||
export const Recordings = {
|
export const Recordings = {
|
||||||
name: "Recordings",
|
name: "Recordings",
|
||||||
components: { GalaxySection, GalaxyTabs },
|
components: { GalaxyTabs, GxNotice },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
sub: "routes",
|
||||||
loading: true,
|
loading: true,
|
||||||
error: "",
|
error: "",
|
||||||
routes: [],
|
routes: [],
|
||||||
@@ -52,6 +74,13 @@ export const Recordings = {
|
|||||||
selectedCamera: "",
|
selectedCamera: "",
|
||||||
logsRoute: null,
|
logsRoute: null,
|
||||||
logsData: null,
|
logsData: null,
|
||||||
|
onFirestar: isFirestarOrigin(),
|
||||||
|
// Screen recordings subtab
|
||||||
|
screenLoading: false,
|
||||||
|
screenError: "",
|
||||||
|
screenProgress: 0,
|
||||||
|
recordings: [],
|
||||||
|
recPlay: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -81,6 +110,13 @@ export const Recordings = {
|
|||||||
methods: {
|
methods: {
|
||||||
fmtDuration,
|
fmtDuration,
|
||||||
formatBytes,
|
formatBytes,
|
||||||
|
setSub(key) {
|
||||||
|
this.sub = key === "screen" ? "screen" : "routes"
|
||||||
|
if (this.sub === "screen" && !this.recordings.length && !this.screenLoading) this.loadScreenRecordings()
|
||||||
|
},
|
||||||
|
screenDisplayName(rec) {
|
||||||
|
return rec.is_custom_name ? rec.filename.replace(/\.mp4$/i, "").replace(/_/g, " ") : formatScreenDate(rec.timestamp)
|
||||||
|
},
|
||||||
async loadRoutes() {
|
async loadRoutes() {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
this.error = ""
|
this.error = ""
|
||||||
@@ -107,6 +143,35 @@ export const Recordings = {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async loadScreenRecordings() {
|
||||||
|
this.screenLoading = true
|
||||||
|
this.screenError = ""
|
||||||
|
this.recordings = []
|
||||||
|
this.screenProgress = 0
|
||||||
|
const seen = new Set()
|
||||||
|
try {
|
||||||
|
this.recController?.abort()
|
||||||
|
this.recController = new AbortController()
|
||||||
|
await api.screenRecordingsStream({
|
||||||
|
signal: this.recController.signal,
|
||||||
|
onProgress: (p) => { this.screenProgress = p },
|
||||||
|
onRecordings: (raw) => {
|
||||||
|
for (const r of raw) {
|
||||||
|
if (seen.has(r.filename)) continue
|
||||||
|
seen.add(r.filename)
|
||||||
|
this.recordings.push(r)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
if (e?.name !== "AbortError") this.screenError = "Couldn't load recordings."
|
||||||
|
} finally {
|
||||||
|
this.screenLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
refreshScreenRecordings() {
|
||||||
|
this.loadScreenRecordings()
|
||||||
|
},
|
||||||
async deleteRoute(route) {
|
async deleteRoute(route) {
|
||||||
if (!(await GalaxyConfirm({ title: "Delete route?", message: `Delete “${route.displayName}”?`, confirmLabel: "Delete", danger: true }))) return
|
if (!(await GalaxyConfirm({ title: "Delete route?", message: `Delete “${route.displayName}”?`, confirmLabel: "Delete", danger: true }))) return
|
||||||
try {
|
try {
|
||||||
@@ -148,13 +213,14 @@ export const Recordings = {
|
|||||||
this.routes = []
|
this.routes = []
|
||||||
showSnackbar(payload?.message || "Routes deleted!")
|
showSnackbar(payload?.message || "Routes deleted!")
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showSnackbar("Failed to delete routes.", "error")
|
showSnackbar(e?.message || "Failed to delete routes.", "error")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async openPlayer(route) {
|
async openPlayer(route) {
|
||||||
this.playerRoute = route
|
this.playerRoute = route
|
||||||
this.playerLoading = true
|
this.playerLoading = true
|
||||||
this.playerError = ""
|
this.playerError = ""
|
||||||
|
this._playRetries = 0
|
||||||
try {
|
try {
|
||||||
const data = await api.getRoute(route.name)
|
const data = await api.getRoute(route.name)
|
||||||
const segments = Array.isArray(data.segment_urls) ? data.segment_urls.filter((u) => typeof u === "string") : []
|
const segments = Array.isArray(data.segment_urls) ? data.segment_urls.filter((u) => typeof u === "string") : []
|
||||||
@@ -173,13 +239,23 @@ export const Recordings = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
cameraUrl(url, low) {
|
cameraUrl(url, low) {
|
||||||
if (this.selectedCamera === "forward") return low && !url.includes("?" ) ? `${url}?quality=low` : url
|
if (this.selectedCamera === "forward") return low && !url.includes("?") ? `${url}?quality=low` : url
|
||||||
const sep = url.includes("?") ? "&" : "?"
|
const sep = url.includes("?") ? "&" : "?"
|
||||||
return `${url}${sep}camera=${encodeURIComponent(this.selectedCamera)}${low ? "&quality=low" : ""}`
|
return `${url}${sep}camera=${encodeURIComponent(this.selectedCamera)}${low ? "&quality=low" : ""}`
|
||||||
},
|
},
|
||||||
playSegment() {
|
playSegment() {
|
||||||
const video = this.$refs.player
|
const video = this.$refs.player
|
||||||
if (!video || !this.segments[this.current]) return
|
if (!this.segments[this.current]) return
|
||||||
|
// The player mounts inside a Teleport + transition after openPlayer clears
|
||||||
|
// playerLoading, so the video element may not exist on the very first call.
|
||||||
|
if (!video) {
|
||||||
|
this._playRetries = (this._playRetries || 0) + 1
|
||||||
|
if (this._playRetries <= 15) {
|
||||||
|
requestAnimationFrame(() => this.playSegment())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this._playRetries = 0
|
||||||
video.src = this.cameraUrl(this.segments[this.current])
|
video.src = this.cameraUrl(this.segments[this.current])
|
||||||
video.load()
|
video.load()
|
||||||
video.play().catch(() => {})
|
video.play().catch(() => {})
|
||||||
@@ -192,6 +268,7 @@ export const Recordings = {
|
|||||||
a.click()
|
a.click()
|
||||||
},
|
},
|
||||||
closePlayer() {
|
closePlayer() {
|
||||||
|
this._playRetries = 0
|
||||||
if (this.$refs.player) { this.$refs.player.pause(); this.$refs.player.removeAttribute("src") }
|
if (this.$refs.player) { this.$refs.player.pause(); this.$refs.player.removeAttribute("src") }
|
||||||
this.playerRoute = null
|
this.playerRoute = null
|
||||||
this.playerLoading = false
|
this.playerLoading = false
|
||||||
@@ -207,13 +284,71 @@ export const Recordings = {
|
|||||||
showSnackbar("Could not read logs.", "error")
|
showSnackbar("Could not read logs.", "error")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
closeRecPlayer() {
|
||||||
|
this.recPlay = null
|
||||||
|
},
|
||||||
|
screenUrl(filename) {
|
||||||
|
return api.screenRecordingVideoUrl(filename)
|
||||||
|
},
|
||||||
|
playRec(rec) {
|
||||||
|
this.recPlay = rec
|
||||||
|
},
|
||||||
|
downloadRec(rec) {
|
||||||
|
const a = document.createElement("a")
|
||||||
|
a.href = api.screenRecordingVideoUrl(rec.filename)
|
||||||
|
a.download = rec.filename
|
||||||
|
a.click()
|
||||||
|
},
|
||||||
|
async renameRec(rec) {
|
||||||
|
const base = rec.filename.replace(/\.mp4$/i, "")
|
||||||
|
const val = prompt("Rename recording:", base)
|
||||||
|
if (!val || val === base) return
|
||||||
|
try {
|
||||||
|
await api.renameScreenRecording(rec.filename, val + ".mp4")
|
||||||
|
showSnackbar("Recording renamed!")
|
||||||
|
this.refreshScreenRecordings()
|
||||||
|
} catch (e) {
|
||||||
|
showSnackbar("Rename failed.", "error")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async deleteRec(rec) {
|
||||||
|
if (!(await GalaxyConfirm({ title: "Delete recording?", message: `Delete “${rec.filename}”?`, confirmLabel: "Delete", danger: true }))) return
|
||||||
|
try {
|
||||||
|
await api.deleteScreenRecording(rec.filename)
|
||||||
|
this.recordings = this.recordings.filter((r) => r.filename !== rec.filename)
|
||||||
|
if (this.recPlay?.filename === rec.filename) this.recPlay = null
|
||||||
|
showSnackbar("Recording deleted!")
|
||||||
|
} catch (e) {
|
||||||
|
showSnackbar("Delete failed.", "error")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async deleteAllRecs() {
|
||||||
|
if (!(await GalaxyConfirm({ title: "Delete all recordings?", message: "This permanently deletes every screen recording.", confirmLabel: "Delete All", danger: true }))) return
|
||||||
|
try {
|
||||||
|
const payload = await api.deleteAllScreenRecordings()
|
||||||
|
this.recordings = []
|
||||||
|
this.recPlay = null
|
||||||
|
showSnackbar(payload?.message || "All screen recordings deleted!")
|
||||||
|
} catch (e) {
|
||||||
|
showSnackbar(e?.message || "Delete failed.", "error")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
if (!this.onFirestar) await this.loadRoutes()
|
||||||
|
},
|
||||||
|
beforeUnmount() {
|
||||||
|
this.controller?.abort()
|
||||||
|
this.recController?.abort()
|
||||||
},
|
},
|
||||||
async mounted() { await this.loadRoutes() },
|
|
||||||
beforeUnmount() { this.controller?.abort() },
|
|
||||||
template: `
|
template: `
|
||||||
<div>
|
<div>
|
||||||
|
<template v-if="!onFirestar">
|
||||||
<h2 style="margin-top:0;">Recordings</h2>
|
<h2 style="margin-top:0;">Recordings</h2>
|
||||||
|
|
||||||
|
<GalaxyTabs :items="{ routes: 'Dashcam Routes', screen: 'Screen Recordings' }" :active="sub" @select="setSub" />
|
||||||
|
|
||||||
|
<template v-if="sub === 'routes'">
|
||||||
<section class="gx-card">
|
<section class="gx-card">
|
||||||
<div class="gx-section__header">
|
<div class="gx-section__header">
|
||||||
<i class="bi bi-camera-reels"></i>
|
<i class="bi bi-camera-reels"></i>
|
||||||
@@ -277,10 +412,47 @@ export const Recordings = {
|
|||||||
<a class="gx-btn gx-btn--tonal" :href="seg.url" download>Download</a>
|
<a class="gx-btn gx-btn--tonal" :href="seg.url" download>Download</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<section class="gx-card">
|
||||||
|
<div class="gx-section__header">
|
||||||
|
<i class="bi bi-record-circle"></i>
|
||||||
|
<span class="gx-section__title">Screen Recordings</span>
|
||||||
|
<span class="gx-section__count">{{ recordings.length }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="screenLoading && !recordings.length" class="gx-loading">Loading screen recordings...</div>
|
||||||
|
<div v-else-if="screenError" class="gx-empty" style="color: var(--error);">{{ screenError }}</div>
|
||||||
|
<div v-else-if="!recordings.length" class="gx-empty">No screen recordings found.</div>
|
||||||
|
<article v-for="r in recordings" :key="r.filename" class="gx-row" style="cursor:pointer;" @click="playRec(r)">
|
||||||
|
<img :src="r.png" alt="" loading="lazy" style="width:84px; height:auto; border-radius:var(--radius-sm); object-fit:cover; flex:none;">
|
||||||
|
<div class="gx-row__info">
|
||||||
|
<span class="gx-row__label">{{ screenDisplayName(r) }}</span>
|
||||||
|
<span class="gx-row__desc">{{ r.filename }}</span>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex; gap:6px; flex-wrap:wrap;">
|
||||||
|
<button type="button" class="gx-btn gx-btn--tonal" title="Play" @click.stop="playRec(r)"><i class="bi bi-play-fill"></i></button>
|
||||||
|
<button type="button" class="gx-btn gx-btn--tonal" title="Rename" @click.stop="renameRec(r)"><i class="bi bi-pencil"></i></button>
|
||||||
|
<button type="button" class="gx-btn gx-btn--tonal" title="Download" @click.stop="downloadRec(r)"><i class="bi bi-download"></i></button>
|
||||||
|
<button type="button" class="gx-btn gx-btn--danger" title="Delete" @click.stop="deleteRec(r)"><i class="bi bi-trash"></i></button>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="gx-card" v-if="recordings.length">
|
||||||
|
<div class="gx-section__header">
|
||||||
|
<i class="bi bi-exclamation-triangle"></i>
|
||||||
|
<span class="gx-section__title">Delete recordings</span>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex; gap:8px; padding: var(--sp-3); flex-wrap:wrap;">
|
||||||
|
<button type="button" class="gx-btn gx-btn--danger" @click="deleteAllRecs">Delete All Recordings</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<transition name="gx-fade">
|
<transition name="gx-fade">
|
||||||
<div v-if="playerRoute" class="gx-scrim gx-scrim--bottomsheet" @click.self="closePlayer">
|
<div v-if="sub === 'routes' && playerRoute" class="gx-scrim gx-scrim--bottomsheet" @click.self="closePlayer">
|
||||||
<div class="gx-sheet" role="dialog" aria-label="Route video player">
|
<div class="gx-sheet" role="dialog" aria-label="Route video player">
|
||||||
<div class="gx-section__header" style="cursor:default;">
|
<div class="gx-section__header" style="cursor:default;">
|
||||||
<i class="bi bi-camera-video"></i>
|
<i class="bi bi-camera-video"></i>
|
||||||
@@ -307,6 +479,32 @@ export const Recordings = {
|
|||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
|
|
||||||
|
<Teleport to="body">
|
||||||
|
<transition name="gx-fade">
|
||||||
|
<div v-if="recPlay" class="gx-scrim gx-scrim--bottomsheet" @click.self="closeRecPlayer">
|
||||||
|
<div class="gx-sheet" role="dialog" aria-label="Screen recording player">
|
||||||
|
<div class="gx-section__header" style="cursor:default;">
|
||||||
|
<i class="bi bi-record-circle"></i>
|
||||||
|
<span class="gx-section__title">{{ screenDisplayName(recPlay) }}</span>
|
||||||
|
<button type="button" class="gx-icon-btn" aria-label="Close player" @click="closeRecPlayer"><i class="bi bi-x-lg"></i></button>
|
||||||
|
</div>
|
||||||
|
<div style="padding: var(--sp-3);">
|
||||||
|
<video class="gx-video" controls autoplay playsinline :src="screenUrl(recPlay.filename)"></video>
|
||||||
|
<div style="display:flex; gap:8px; padding: var(--sp-3) 0 0; flex-wrap:wrap;">
|
||||||
|
<button type="button" class="gx-btn" @click="downloadRec(recPlay)"><i class="bi bi-download"></i> Download</button>
|
||||||
|
<button type="button" class="gx-btn gx-btn--tonal" @click="renameRec(recPlay)"><i class="bi bi-pencil"></i> Rename</button>
|
||||||
|
<button type="button" class="gx-btn gx-btn--danger" @click="deleteRec(recPlay)"><i class="bi bi-trash"></i> Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<GxNotice v-else tone="info" icon="bi-satellite" title="Recordings Unavailable via Galaxy"
|
||||||
|
text="Loading recordings requires a direct connection. Connect to your device's local network to use this feature." />
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ export const SystemTools = {
|
|||||||
<div v-if="fastStatus.message" class="gx-note">{{ fastStatus.message }}</div>
|
<div v-if="fastStatus.message" class="gx-note">{{ fastStatus.message }}</div>
|
||||||
<div v-if="fastStatus.warning && (fastStatus.running || fastStatus.updateAvailable)" class="gx-note gx-note--danger">{{ fastStatus.warning }}</div>
|
<div v-if="fastStatus.warning && (fastStatus.running || fastStatus.updateAvailable)" class="gx-note gx-note--danger">{{ fastStatus.warning }}</div>
|
||||||
<div v-if="fastStatus.agnosUpdate?.available && fastStatus.agnosUpdate?.warnings?.length" style="margin-top:4px;">
|
<div v-if="fastStatus.agnosUpdate?.available && fastStatus.agnosUpdate?.warnings?.length" style="margin-top:4px;">
|
||||||
<div v-for="w in fastStatus.agnosUpdate.warnings" :key="w" class="gx-note gx-note--danger">⚠ {{ w }}</div>
|
<div v-for="w in fastStatus.agnosUpdate.warnings" :key="w" class="gx-note gx-note--danger"><i class="bi bi-exclamation-triangle-fill"></i> {{ w }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user