diff --git a/dev/cli/controller_cli.c b/dev/cli/controller_cli.c index e4e1ad4..5ef67ec 100644 --- a/dev/cli/controller_cli.c +++ b/dev/cli/controller_cli.c @@ -163,7 +163,7 @@ static void on_standalone( (*idx)++; } -static const char *scale_name(uint8_t s) +static const char *scale_mode_name(uint8_t s) { switch (s) { case 0: return "stretch"; @@ -179,13 +179,13 @@ static void on_display( uint16_t stream_id, int16_t win_x, int16_t win_y, uint16_t win_w, uint16_t win_h, - uint8_t scale, uint8_t anchor, + uint8_t scale_mode, uint8_t anchor, void *ud) { (void)ud; - printf(" [%u] display stream=%u pos=%d,%d size=%ux%u scale=%s anchor=%s\n", + printf(" [%u] display stream=%u pos=%d,%d size=%ux%u scale_mode=%s anchor=%s\n", device_id, stream_id, win_x, win_y, win_w, win_h, - scale_name(scale), + scale_mode_name(scale_mode), anchor == 0 ? "center" : "topleft"); } diff --git a/include/protocol.h b/include/protocol.h index 5f27c7b..428d98e 100644 --- a/include/protocol.h +++ b/include/protocol.h @@ -157,7 +157,7 @@ struct Proto_Display_Device_Info { uint16_t stream_id; int16_t win_x, win_y; uint16_t win_w, win_h; - uint8_t scale; + uint8_t scale_mode; uint8_t anchor; }; @@ -166,7 +166,7 @@ struct Proto_Display_Device_Info { * SET_CONTROL for display device indices returned by ENUM_DEVICES. * ------------------------------------------------------------------------- */ -#define PROTO_DISPLAY_CTRL_SCALE 0x00D00001u /* int 0-3: stretch/fit/fill/1:1 */ +#define PROTO_DISPLAY_CTRL_SCALE_MODE 0x00D00001u /* int 0-3: stretch/fit/fill/1:1 */ #define PROTO_DISPLAY_CTRL_ANCHOR 0x00D00002u /* int 0-1: center/topleft */ #define PROTO_DISPLAY_CTRL_NO_SIGNAL_FPS 0x00D00003u /* int 1-60: no-signal animation fps */ @@ -262,7 +262,7 @@ struct Proto_Stop_Ingest { * display incoming VIDEO_FRAME messages for the given stream_id. * win_x/win_y are screen-space window position (signed: multi-monitor). * win_w/win_h of 0 mean use a default size. - * scale: 0=stretch 1=fit 2=fill 3=1:1 (PROTO_DISPLAY_SCALE_*) + * scale_mode: 0=stretch 1=fit 2=fill 3=1:1 (PROTO_DISPLAY_SCALE_*) * anchor: 0=center 1=topleft (PROTO_DISPLAY_ANCHOR_*) */ struct Proto_Start_Display { @@ -272,7 +272,7 @@ struct Proto_Start_Display { int16_t win_y; uint16_t win_w; uint16_t win_h; - uint8_t scale; + uint8_t scale_mode; uint8_t anchor; uint8_t no_signal_fps; /* 0 = default (15); no-signal animation frame rate */ /* 1 byte reserved */ @@ -365,7 +365,7 @@ struct App_Error proto_write_stop_ingest(struct Transport_Conn *conn, struct App_Error proto_write_start_display(struct Transport_Conn *conn, uint16_t request_id, uint16_t stream_id, int16_t win_x, int16_t win_y, uint16_t win_w, uint16_t win_h, - uint8_t scale, uint8_t anchor, uint8_t no_signal_fps); + uint8_t scale_mode, uint8_t anchor, uint8_t no_signal_fps); /* CONTROL_REQUEST: STOP_DISPLAY */ struct App_Error proto_write_stop_display(struct Transport_Conn *conn, @@ -510,7 +510,7 @@ struct App_Error proto_read_enum_devices_response( uint16_t stream_id, int16_t win_x, int16_t win_y, uint16_t win_w, uint16_t win_h, - uint8_t scale, uint8_t anchor, + uint8_t scale_mode, uint8_t anchor, void *userdata), void *userdata); diff --git a/planning.md b/planning.md index 7b928b6..9f34fd2 100644 --- a/planning.md +++ b/planning.md @@ -136,3 +136,4 @@ These are open questions tracked in `architecture.md` that do not need to be res - controller_cli is a temporary dev tool; the long-term replacement is a dedicated `controller` binary outside `dev/cli/` that maintains simultaneous connections to all discovered nodes (not switching between them). Commands address a specific node by peer index. This mirrors the web UI's model of administering the whole network rather than one node at a time. The `connect` / active-connection model in the current controller_cli is an interim design choice that should not be carried forward. - start-ingest peer addressing: the `dest_host` + `dest_port` in START_INGEST is awkward to type manually and requires the caller to know the target's TCP port. Should accept a peer ID (index from the discovered peer table on the node) so the node can resolve the address itself. Requires the node to run discovery and expose its peer table. - Connection multiplexing: currently each ingest stream opens its own outbound TCP connection to the destination. Multiple streams between the same two peers should share one connection, with stream_id used to demultiplex frames. This is the priority/encapsulation scheme described in the architecture — high-priority and low-latency frames from different streams travel over the same socket rather than competing across separate sockets. +- Control grouping: controls should be organizable into named groups for both display organisation (collapsible sections in a UI) and protocol semantics (enumerate controls within a group, set a group of related controls atomically). Relevant for display devices where scale_mode, anchor, position, and size are logically related, and for cameras where white balance, exposure, and gain belong together. The current flat list of (control_id, name, type, value) tuples does not capture this. diff --git a/src/modules/protocol/protocol.c b/src/modules/protocol/protocol.c index cf6729f..ac756fc 100644 --- a/src/modules/protocol/protocol.c +++ b/src/modules/protocol/protocol.c @@ -420,7 +420,7 @@ struct App_Error proto_write_enum_devices_response(struct Transport_Conn *conn, e = wbuf_i16(&b, d->win_y); if (!APP_IS_OK(e)) { goto fail; } e = wbuf_u16(&b, d->win_w); if (!APP_IS_OK(e)) { goto fail; } e = wbuf_u16(&b, d->win_h); if (!APP_IS_OK(e)) { goto fail; } - e = wbuf_u8 (&b, d->scale); if (!APP_IS_OK(e)) { goto fail; } + e = wbuf_u8 (&b, d->scale_mode); if (!APP_IS_OK(e)) { goto fail; } e = wbuf_u8 (&b, d->anchor); if (!APP_IS_OK(e)) { goto fail; } } @@ -624,11 +624,11 @@ struct App_Error proto_read_stop_ingest( } /* START_DISPLAY: request_id(2) cmd(2) stream_id(2) win_x(2) win_y(2) - * win_w(2) win_h(2) scale(1) anchor(1) no_signal_fps(1) reserved(1) = 18 bytes */ + * win_w(2) win_h(2) scale_mode(1) anchor(1) no_signal_fps(1) reserved(1) = 18 bytes */ struct App_Error proto_write_start_display(struct Transport_Conn *conn, uint16_t request_id, uint16_t stream_id, int16_t win_x, int16_t win_y, uint16_t win_w, uint16_t win_h, - uint8_t scale, uint8_t anchor, uint8_t no_signal_fps) + uint8_t scale_mode, uint8_t anchor, uint8_t no_signal_fps) { uint8_t buf[18]; uint32_t o = 0; @@ -639,7 +639,7 @@ struct App_Error proto_write_start_display(struct Transport_Conn *conn, put_i16(buf, o, win_y); o += 2; put_u16(buf, o, win_w); o += 2; put_u16(buf, o, win_h); o += 2; - put_u8 (buf, o, scale); o += 1; + put_u8 (buf, o, scale_mode); o += 1; put_u8 (buf, o, anchor); o += 1; put_u8 (buf, o, no_signal_fps); o += 1; put_u8 (buf, o, 0); o += 1; /* reserved */ @@ -669,7 +669,7 @@ struct App_Error proto_read_start_display( out->win_y = get_i16(payload, 8); out->win_w = get_u16(payload, 10); out->win_h = get_u16(payload, 12); - out->scale = get_u8 (payload, 14); + out->scale_mode = get_u8 (payload, 14); out->anchor = get_u8 (payload, 15); out->no_signal_fps = length >= 18 ? get_u8(payload, 16) : 0; return APP_OK; @@ -731,7 +731,7 @@ struct App_Error proto_read_enum_devices_response( uint16_t stream_id, int16_t win_x, int16_t win_y, uint16_t win_w, uint16_t win_h, - uint8_t scale, uint8_t anchor, + uint8_t scale_mode, uint8_t anchor, void *userdata), void *userdata) { @@ -798,12 +798,12 @@ struct App_Error proto_read_enum_devices_response( int16_t win_y = (int16_t)cur_u16(&c); uint16_t win_w = cur_u16(&c); uint16_t win_h = cur_u16(&c); - uint8_t scale = cur_u8(&c); - uint8_t anchor = cur_u8(&c); + uint8_t scale_mode = cur_u8(&c); + uint8_t anchor = cur_u8(&c); CUR_CHECK(c); if (on_display) { on_display(device_id, stream_id, win_x, win_y, - win_w, win_h, scale, anchor, userdata); + win_w, win_h, scale_mode, anchor, userdata); } } } diff --git a/src/node/main.c b/src/node/main.c index cc5fa0d..ff53b38 100644 --- a/src/node/main.c +++ b/src/node/main.c @@ -178,7 +178,7 @@ struct Display_Slot { /* Config — written by handle_start_display before setting wanted */ int win_x, win_y; int win_w, win_h; - Xorg_Scale scale; + Xorg_Scale scale_mode; Xorg_Anchor anchor; /* Pending frame — deposited by transport thread, consumed by main */ @@ -485,7 +485,7 @@ static void display_loop_tick(struct Node *node) Xorg_Viewer *v = xorg_viewer_open( d->win_x, d->win_y, d->win_w, d->win_h, title); if (v) { - xorg_viewer_set_scale(v, d->scale); + xorg_viewer_set_scale(v, d->scale_mode); xorg_viewer_set_anchor(v, d->anchor); d->viewer = v; pthread_mutex_lock(&d->mutex); @@ -512,7 +512,7 @@ static void display_loop_tick(struct Node *node) /* Sync scale/anchor — may be updated live via SET_CONTROL */ pthread_mutex_lock(&d->mutex); - Xorg_Scale cur_scale = d->scale; + Xorg_Scale cur_scale = d->scale_mode; Xorg_Anchor cur_anchor = d->anchor; pthread_mutex_unlock(&d->mutex); xorg_viewer_set_scale(d->viewer, cur_scale); @@ -889,7 +889,7 @@ static void handle_enum_devices(struct Node *node, .win_y = (int16_t)d->win_y, .win_w = (uint16_t)d->win_w, .win_h = (uint16_t)d->win_h, - .scale = (uint8_t)d->scale, + .scale_mode = (uint8_t)d->scale_mode, .anchor = (uint8_t)d->anchor, }; pthread_mutex_unlock(&d->mutex); @@ -923,15 +923,15 @@ static void handle_enum_controls(struct Node *node, return; } pthread_mutex_lock(&disp->mutex); - int scale = (int)disp->scale; + int scale_mode = (int)disp->scale_mode; int anchor = (int)disp->anchor; int no_signal_fps = disp->no_signal_fps > 0 ? disp->no_signal_fps : 15; pthread_mutex_unlock(&disp->mutex); struct Proto_Control_Info ctrls[] = { - { .id = PROTO_DISPLAY_CTRL_SCALE, - .type = 1, .name = "Scale", + { .id = PROTO_DISPLAY_CTRL_SCALE_MODE, + .type = 1, .name = "Scale Mode", .min = 0, .max = 3, .step = 1, .default_val = 1, - .current_val = scale }, + .current_val = scale_mode }, { .id = PROTO_DISPLAY_CTRL_ANCHOR, .type = 1, .name = "Anchor", .min = 0, .max = 1, .step = 1, .default_val = 0, @@ -981,7 +981,7 @@ static void handle_get_control(struct Node *node, int32_t value = 0; int found = 1; switch (req.control_id) { - case PROTO_DISPLAY_CTRL_SCALE: value = (int32_t)disp->scale; break; + case PROTO_DISPLAY_CTRL_SCALE_MODE: value = (int32_t)disp->scale_mode; break; case PROTO_DISPLAY_CTRL_ANCHOR: value = (int32_t)disp->anchor; break; case PROTO_DISPLAY_CTRL_NO_SIGNAL_FPS: value = disp->no_signal_fps > 0 ? disp->no_signal_fps : 15; break; default: found = 0; break; @@ -1032,9 +1032,9 @@ static void handle_set_control(struct Node *node, pthread_mutex_lock(&disp->mutex); int found = 1; switch (req.control_id) { - case PROTO_DISPLAY_CTRL_SCALE: + case PROTO_DISPLAY_CTRL_SCALE_MODE: if (req.value >= 0 && req.value <= 3) { - disp->scale = (Xorg_Scale)req.value; + disp->scale_mode = (Xorg_Scale)req.value; } break; case PROTO_DISPLAY_CTRL_ANCHOR: @@ -1250,7 +1250,7 @@ static void handle_start_display(struct Node *node, d->win_y = (int)req.win_y; d->win_w = req.win_w > 0 ? (int)req.win_w : 1280; d->win_h = req.win_h > 0 ? (int)req.win_h : 720; - d->scale = proto_scale_to_xorg(req.scale); + d->scale_mode = proto_scale_to_xorg(req.scale_mode); d->anchor = proto_anchor_to_xorg(req.anchor); d->no_signal_fps = req.no_signal_fps > 0 ? (int)req.no_signal_fps : 15; d->wanted_state = DISP_OPEN; /* reconciled by display_loop_tick */