Add Test_Upload item for development/product cloud

This commit is contained in:
miketsai 2026-07-06 15:02:11 +08:00
parent aa75c47772
commit 83e2256192
4 changed files with 79 additions and 31 deletions

View File

@ -10,7 +10,7 @@
* A) Real-time JSON UART DX-BT24 BLE iPad (bt_uart_send_json) * A) Real-time JSON UART DX-BT24 BLE iPad (bt_uart_send_json)
* B) tar.gz archive POST <upload_url> (OOB / cloud path) * B) tar.gz archive POST <upload_url> (OOB / cloud path)
* Simulation: http://192.168.0.114:8081/api/upload * Simulation: http://192.168.0.114:8081/api/upload
* Production: http://192.168.0.99/api/golf.cgi * Production: http://192.168.0.99/api/golf-golface.cgi
* *
* Grass events use a 4-level state machine (L1/L2/L3/resolved). * Grass events use a 4-level state machine (L1/L2/L3/resolved).
* Hazard + person events are single-shot. * Hazard + person events are single-shot.
@ -27,7 +27,9 @@ void event_recorder_init(const char *upload_url,
const char *sd_path, const char *sd_path,
int sd_max_mb, int sd_max_mb,
int upload_delay_ms, int upload_delay_ms,
int enable); int enable,
const char *device_id,
int dev_mode);
/* Drive the state machine — call from app_header_recv_inference. */ /* Drive the state machine — call from app_header_recv_inference. */
void event_recorder_update(const stdc_analysis_t *ana); void event_recorder_update(const stdc_analysis_t *ana);

View File

@ -99,8 +99,8 @@ bt_name = BT-24 # Reported in status_ch
; Leave empty to auto-detect on first boot; value is written back automatically. ; Leave empty to auto-detect on first boot; value is written back automatically.
; BLE broadcast name (event:bt_name) is derived as AresX-{lower 16-bit hex}. ; BLE broadcast name (event:bt_name) is derived as AresX-{lower 16-bit hex}.
device_id = device_id =
upload_url = http://192.168.0.99/api/golf.cgi # Channel B: tar.gz upload (OOB/cloud path) upload_url = http://192.168.0.99/api/golf-golface.cgi # Channel B: tar.gz upload (OOB/cloud path)
# Production: http://192.168.0.99/api/golf.cgi upload_dev = 1 # 1: append &dev=1 to upload URL (dev); 0: production
sd_path = /tmp/sdcard/events # SD card event archive path sd_path = /tmp/sdcard/events # SD card event archive path
sd_max_mb = 7168 # 7 GB ??delete oldest when exceeded sd_max_mb = 7168 # 7 GB ??delete oldest when exceeded
upload_delay_ms = 0 # 0: upload immediately after tar.gz built (tar is built after event ends, no extra delay needed) upload_delay_ms = 0 # 0: upload immediately after tar.gz built (tar is built after event ends, no extra delay needed)

View File

@ -109,7 +109,9 @@ static int msg_send(const char *fifo,
* Production: http://192.168.0.99/api/golf.cgi */ * Production: http://192.168.0.99/api/golf.cgi */
static char s_up_host[64] = "192.168.0.99"; static char s_up_host[64] = "192.168.0.99";
static int s_up_port = 80; static int s_up_port = 80;
static char s_up_path[128] = "/api/golf.cgi"; static char s_up_path[128] = "/api/golf-golface.cgi";
static char s_device_id[64] = "";
static int s_upload_dev = 0;
static char s_sd_path[256] = "/tmp/sdcard/events"; static char s_sd_path[256] = "/tmp/sdcard/events";
static long long s_sd_max_bytes = (long long)7 * 1024 * 1024 * 1024; static long long s_sd_max_bytes = (long long)7 * 1024 * 1024 * 1024;
@ -244,14 +246,29 @@ static int open_socket_to(const char *host, int port)
/* ── Channel B: POST tar.gz via kCurl ───────────────────────────────────── */ /* ── Channel B: POST tar.gz via kCurl ───────────────────────────────────── */
#define KCURL_PATH "/mnt/flash/plus/kp_firmware/kp_firmware_0/kp_firmware/bin/kCurl" #define KCURL_PATH "/mnt/flash/plus/kp_firmware/kp_firmware_0/kp_firmware/bin/kCurl"
static int http_post_file(const char *filepath) /* returns 0=OK, -1=fail */ static int http_post_file(const char *filepath, const char *event_id) /* returns 0=OK, -1=fail */
{ {
const char *basename = strrchr(filepath, '/');
basename = basename ? basename + 1 : filepath;
char url[320]; char url[320];
snprintf(url, sizeof(url), "http://%s:%d%s?filename=%s",
s_up_host, s_up_port, s_up_path, basename); if (s_upload_dev) {
/* Dev mode: fixed test credentials, append &dev=1 */
snprintf(url, sizeof(url), "http://%s:%d%s?did=GOLF20001&vid=1620029793&dev=1",
s_up_host, s_up_port, s_up_path);
} else {
/* Production: strip "0x"/"0X" prefix from device_id */
const char *did = s_device_id;
if (did[0] == '0' && (did[1] == 'x' || did[1] == 'X'))
did += 2;
/* Strip any non-numeric prefix from event_id (e.g. "TEST") */
const char *vid = event_id;
while (*vid && (*vid < '0' || *vid > '9'))
vid++;
if (!*vid) vid = event_id; /* fallback: all non-digit, use as-is */
snprintf(url, sizeof(url), "http://%s:%d%s?did=%s&vid=%s",
s_up_host, s_up_port, s_up_path, did, vid);
}
char cmd[640]; char cmd[640];
snprintf(cmd, sizeof(cmd), snprintf(cmd, sizeof(cmd),
@ -264,7 +281,7 @@ static int http_post_file(const char *filepath) /* returns 0=OK, -1=fail */
printf("[EVT] upload: kCurl failed (rc=%d)\n", rc); printf("[EVT] upload: kCurl failed (rc=%d)\n", rc);
return -1; return -1;
} }
printf("[EVT] upload: %s sent OK\n", basename); printf("[EVT] upload: %s sent OK\n", event_id);
return 0; return 0;
} }
@ -590,29 +607,49 @@ static void *test_upload_thread(void *arg)
(void)arg; (void)arg;
test_reply("TEST_UPLOAD_START"); test_reply("TEST_UPLOAD_START");
/* Build a minimal test event ----------------------------------------- */ /* Build event — format depends on upload_dev:
* dev=1 (test env) : type=test_upload, snap=test.jpg, isolated work_dir
* dev=0 (production): type=grass, snap=level1.jpg, real work_dir */
char event_id[24]; char event_id[24];
snprintf(event_id, sizeof(event_id), "TEST%ld", (long)time(NULL)); snprintf(event_id, sizeof(event_id), "%ld", (long)time(NULL));
const char *snap_name = s_upload_dev ? "test.jpg" : "level1.jpg";
const char *evt_type = s_upload_dev ? "test_upload" : "grass";
float duration = s_upload_dev ? 0.0f : 5.0f;
char work_dir[256]; char work_dir[256];
make_work_dir(event_id, work_dir, sizeof(work_dir)); if (s_upload_dev)
snprintf(work_dir, sizeof(work_dir), "/tmp/ev_TEST%s", event_id);
else
snprintf(work_dir, sizeof(work_dir), "/tmp/ev_%s", event_id);
mkdir(work_dir, 0755);
/* Request one JPEG snapshot from the VMF thread */ /* Request one JPEG snapshot from the VMF thread */
request_snap("test.jpg", work_dir, event_id, "test_upload", 1, 0); request_snap(snap_name, work_dir, event_id, evt_type, 1, 0);
usleep(800000); /* up to 800 ms for VMF to deliver the frame */
/* Check whether the snapshot arrived */ /* Poll up to 5 s (50 × 100 ms) — stop as soon as file arrives */
char snap_path[320]; char snap_path[320];
snprintf(snap_path, sizeof(snap_path), "%s/test.jpg", work_dir); snprintf(snap_path, sizeof(snap_path), "%s/%s", work_dir, snap_name);
struct stat _st; struct stat _st;
int has_snap = (stat(snap_path, &_st) == 0 && _st.st_size > 0) ? 1 : 0; int has_snap = 0;
printf("[TEST] upload: snapshot %s (%s)\n", for (int _i = 0; _i < 50; _i++) {
snap_path, has_snap ? "OK" : "missing — continuing without image"); usleep(100000); /* 100 ms */
if (stat(snap_path, &_st) == 0 && _st.st_size > 0) {
has_snap = 1;
printf("[TEST] upload: snapshot %s OK (%ld bytes, waited %d00ms)\n",
snap_path, (long)_st.st_size, _i + 1);
break;
}
}
if (!has_snap)
printf("[TEST] upload: snapshot %s missing after 5s\n", snap_path);
/* Write event.json */ /* Write event.json */
const char imgs[4][64] = { "test.jpg", "", "", "" }; char imgs[4][64];
write_event_json(work_dir, event_id, "test_upload", 1, 0.0f, memset(imgs, 0, sizeof(imgs));
has_snap ? imgs : NULL, has_snap ? 1 : 0); snprintf(imgs[0], sizeof(imgs[0]), "%s", snap_name);
write_event_json(work_dir, event_id, evt_type, 1, duration,
has_snap ? (const char (*)[64])imgs : NULL, has_snap ? 1 : 0);
/* Build tar.gz */ /* Build tar.gz */
char tgz_path[384]; char tgz_path[384];
@ -625,8 +662,11 @@ static void *test_upload_thread(void *arg)
return NULL; return NULL;
} }
/* Upload via kCurl */ /* Upload via kCurl.
int ok = http_post_file(tgz_path); * dev=1: http_post_file already uses fixed GOLF20001/1620029793.
* dev=0: use fixed test vid so cloud vendor can verify receipt easily. */
const char *upload_vid = s_upload_dev ? event_id : "1122334455";
int ok = http_post_file(tgz_path, upload_vid);
if (ok == 0) if (ok == 0)
test_reply("TEST_UPLOAD_OK"); test_reply("TEST_UPLOAD_OK");
else else
@ -874,7 +914,7 @@ static void *upload_thread(void *arg)
if (tgz_path[0]) { if (tgz_path[0]) {
printf("[EVT] upload: posting %s to %s:%d%s\n", printf("[EVT] upload: posting %s to %s:%d%s\n",
tgz_path, s_up_host, s_up_port, s_up_path); tgz_path, s_up_host, s_up_port, s_up_path);
http_post_file(tgz_path); http_post_file(tgz_path, a->event_id);
} }
sd_cleanup(); sd_cleanup();
@ -1004,7 +1044,9 @@ void event_recorder_init(const char *upload_url,
const char *sd_path, const char *sd_path,
int sd_max_mb, int sd_max_mb,
int upload_delay_ms, int upload_delay_ms,
int enable) int enable,
const char *device_id,
int dev_mode)
{ {
s_enabled = enable; s_enabled = enable;
s_upload_delay_ms = (upload_delay_ms >= 0) ? upload_delay_ms : 60000; s_upload_delay_ms = (upload_delay_ms >= 0) ? upload_delay_ms : 60000;
@ -1015,10 +1057,13 @@ void event_recorder_init(const char *upload_url,
&s_up_port, &s_up_port,
s_up_path, sizeof(s_up_path)); s_up_path, sizeof(s_up_path));
if (sd_path && *sd_path) snprintf(s_sd_path, sizeof(s_sd_path), "%s", sd_path); if (sd_path && *sd_path) snprintf(s_sd_path, sizeof(s_sd_path), "%s", sd_path);
if (device_id && *device_id) snprintf(s_device_id, sizeof(s_device_id), "%s", device_id);
s_upload_dev = dev_mode;
printf("[EVT] init: enable=%d ch_a=bt_uart ch_b=%s:%d%s sd=%s max=%dMB delay=%dms\n", printf("[EVT] init: enable=%d ch_a=bt_uart ch_b=%s:%d%s did=%s dev=%d sd=%s max=%dMB delay=%dms\n",
s_enabled, s_enabled,
s_up_host, s_up_port, s_up_path, s_up_host, s_up_port, s_up_path,
s_device_id, s_upload_dev,
s_sd_path, sd_max_mb, s_upload_delay_ms); s_sd_path, sd_max_mb, s_upload_delay_ms);
bt_uart_set_extra_cmd_cb(handle_test_cmd); bt_uart_set_extra_cmd_cb(handle_test_cmd);
} }

View File

@ -238,6 +238,7 @@ int loadConfig(HOST_STREAM_INIT_OPT_T* pHostStreamInit)
const char *ev_sd = iniparser_getstring(ini, "event:sd_path", "/tmp/sdcard/events"); const char *ev_sd = iniparser_getstring(ini, "event:sd_path", "/tmp/sdcard/events");
int ev_max_mb = iniparser_getint(ini, "event:sd_max_mb", 7168); int ev_max_mb = iniparser_getint(ini, "event:sd_max_mb", 7168);
int ev_delay = iniparser_getint(ini, "event:upload_delay_ms", 60000); int ev_delay = iniparser_getint(ini, "event:upload_delay_ms", 60000);
int ev_dev = iniparser_getint(ini, "event:upload_dev", 0);
/* device_id (event:device_id): raw Kn chip number string, e.g. "0xCE7B562C". /* device_id (event:device_id): raw Kn chip number string, e.g. "0xCE7B562C".
* bt_name (event:bt_name): BLE broadcast name derived from kn, e.g. "AresX-562C". * bt_name (event:bt_name): BLE broadcast name derived from kn, e.g. "AresX-562C".
@ -317,7 +318,7 @@ int loadConfig(HOST_STREAM_INIT_OPT_T* pHostStreamInit)
printf("[BT] WARNING: sed INI update returned %d (%s)\n", rc, HOST_STREAM_CONFIG_PATH); printf("[BT] WARNING: sed INI update returned %d (%s)\n", rc, HOST_STREAM_CONFIG_PATH);
} }
event_recorder_init(ev_up, ev_sd, ev_max_mb, ev_delay, ev_enable); event_recorder_init(ev_up, ev_sd, ev_max_mb, ev_delay, ev_enable, device_id, ev_dev);
} }
/* --- [can] section: MCP2515 CAN bus via J15 SPI connector --- */ /* --- [can] section: MCP2515 CAN bus via J15 SPI connector --- */