This commit is contained in:
sebseb7
2025-12-21 23:00:05 +01:00
parent 7b0fb8ce6f
commit a913162b6e

View File

@@ -179,113 +179,131 @@ discover_and_report_controls() {
log "Discovering available camera controls..."
# Helper function to escape strings for JSON
json_escape() {
local str="$1"
# Escape backslashes first, then quotes
str="${str//\\/\\\\}"
str="${str//\"/\\\"}"
# Remove any control characters
str=$(echo "$str" | tr -d '\n\r\t')
echo "$str"
}
# Get v4l2-ctl output
local v4l2_output
v4l2_output=$(v4l2-ctl -d "$VIDEO_DEVICE" -L 2>/dev/null) || true
# Parse v4l2-ctl -L output into JSON
# Example lines:
# brightness 0x00980900 (int) : min=-64 max=64 step=1 default=0 value=0
# exposure_auto 0x009a0901 (menu) : min=0 max=3 default=3 value=3
# 1: Manual Mode
# 3: Aperture Priority Mode
local controls_json="["
local current_values_json="{"
local first_control=true
local first_value=true
local current_ctrl=""
local ctrl_json=""
local menu_options=""
local in_menu=false
while IFS= read -r line || [[ -n "$line" ]]; do
# Check if this is a control line (starts with control name)
if [[ "$line" =~ ^[[:space:]]*([a-z_][a-z0-9_]*)[[:space:]]+0x[0-9a-f]+[[:space:]]+\(([a-z]+)\)[[:space:]]*:[[:space:]]*(.*) ]]; then
# Save previous control if exists
if [[ -n "$current_ctrl" ]]; then
if [[ "$in_menu" == "true" && -n "$menu_options" ]]; then
ctrl_json="${ctrl_json%, }, \"options\": {${menu_options%,}}}"
else
ctrl_json="${ctrl_json%,}}"
fi
if [[ "$first_control" == "true" ]]; then
first_control=false
else
controls_json+=","
fi
controls_json+="$ctrl_json"
fi
current_ctrl="${BASH_REMATCH[1]}"
local ctrl_type="${BASH_REMATCH[2]}"
local params="${BASH_REMATCH[3]}"
ctrl_json="{\"name\": \"$current_ctrl\", \"type\": \"$ctrl_type\","
menu_options=""
in_menu=false
# Parse parameters
if [[ "$params" =~ min=(-?[0-9]+) ]]; then
ctrl_json+=" \"min\": ${BASH_REMATCH[1]},"
fi
if [[ "$params" =~ max=(-?[0-9]+) ]]; then
ctrl_json+=" \"max\": ${BASH_REMATCH[1]},"
fi
if [[ "$params" =~ step=([0-9]+) ]]; then
ctrl_json+=" \"step\": ${BASH_REMATCH[1]},"
fi
if [[ "$params" =~ default=(-?[0-9]+) ]]; then
ctrl_json+=" \"default\": ${BASH_REMATCH[1]},"
fi
if [[ "$params" =~ value=(-?[0-9]+) ]]; then
local current_value="${BASH_REMATCH[1]}"
if [[ "$first_value" == "true" ]]; then
first_value=false
else
current_values_json+=","
fi
current_values_json+="\"$current_ctrl\": $current_value"
fi
if [[ "$ctrl_type" == "menu" ]]; then
in_menu=true
fi
# Check if this is a menu option line (indented with number: description)
elif [[ "$in_menu" == "true" && "$line" =~ ^[[:space:]]+([0-9]+):[[:space:]]+(.+)$ ]]; then
local opt_val="${BASH_REMATCH[1]}"
local opt_name
opt_name=$(json_escape "${BASH_REMATCH[2]}")
menu_options+="\"$opt_val\": \"$opt_name\","
fi
done < <(v4l2-ctl -d "$VIDEO_DEVICE" -L 2>/dev/null)
# Save last control
if [[ -n "$current_ctrl" ]]; then
if [[ "$in_menu" == "true" && -n "$menu_options" ]]; then
ctrl_json="${ctrl_json%, }, \"options\": {${menu_options%,}}}"
else
ctrl_json="${ctrl_json%,}}"
fi
if [[ "$first_control" != "true" ]]; then
controls_json+=","
fi
controls_json+="$ctrl_json"
if [[ -z "$v4l2_output" ]]; then
log "No v4l2 controls found"
return
fi
controls_json+="]"
current_values_json+="}"
local payload
if command -v jq &>/dev/null; then
# Use jq for proper JSON generation
local controls_array="[]"
local values_obj="{}"
local current_ctrl=""
local current_type=""
local current_min=""
local current_max=""
local current_step=""
local current_default=""
local current_value=""
local menu_opts="{}"
while IFS= read -r line; do
# Control line pattern: name 0xhex (type) : params
if [[ "$line" =~ ^[[:space:]]*([a-z_][a-z0-9_]*)[[:space:]]+0x[0-9a-f]+[[:space:]]+\(([a-z]+)\)[[:space:]]*:[[:space:]]*(.*) ]]; then
# Save previous control
if [[ -n "$current_ctrl" ]]; then
local ctrl_obj
ctrl_obj=$(jq -n \
--arg name "$current_ctrl" \
--arg type "$current_type" \
--argjson min "${current_min:-null}" \
--argjson max "${current_max:-null}" \
--argjson step "${current_step:-null}" \
--argjson default "${current_default:-null}" \
--argjson opts "$menu_opts" \
'{name: $name, type: $type} +
(if $min != null then {min: $min} else {} end) +
(if $max != null then {max: $max} else {} end) +
(if $step != null then {step: $step} else {} end) +
(if $default != null then {default: $default} else {} end) +
(if ($opts | length) > 0 then {options: $opts} else {} end)')
controls_array=$(echo "$controls_array" | jq --argjson ctrl "$ctrl_obj" '. + [$ctrl]')
if [[ -n "$current_value" ]]; then
values_obj=$(echo "$values_obj" | jq --arg k "$current_ctrl" --argjson v "$current_value" '. + {($k): $v}')
fi
fi
current_ctrl="${BASH_REMATCH[1]}"
current_type="${BASH_REMATCH[2]}"
local params="${BASH_REMATCH[3]}"
menu_opts="{}"
current_min="" current_max="" current_step="" current_default="" current_value=""
[[ "$params" =~ min=(-?[0-9]+) ]] && current_min="${BASH_REMATCH[1]}"
[[ "$params" =~ max=(-?[0-9]+) ]] && current_max="${BASH_REMATCH[1]}"
[[ "$params" =~ step=([0-9]+) ]] && current_step="${BASH_REMATCH[1]}"
[[ "$params" =~ default=(-?[0-9]+) ]] && current_default="${BASH_REMATCH[1]}"
[[ "$params" =~ value=(-?[0-9]+) ]] && current_value="${BASH_REMATCH[1]}"
# Menu option line
elif [[ "$current_type" == "menu" && "$line" =~ ^[[:space:]]+([0-9]+):[[:space:]]+(.+)$ ]]; then
local opt_key="${BASH_REMATCH[1]}"
local opt_val="${BASH_REMATCH[2]}"
menu_opts=$(echo "$menu_opts" | jq --arg k "$opt_key" --arg v "$opt_val" '. + {($k): $v}')
fi
done <<< "$v4l2_output"
# Save last control
if [[ -n "$current_ctrl" ]]; then
local ctrl_obj
ctrl_obj=$(jq -n \
--arg name "$current_ctrl" \
--arg type "$current_type" \
--argjson min "${current_min:-null}" \
--argjson max "${current_max:-null}" \
--argjson step "${current_step:-null}" \
--argjson default "${current_default:-null}" \
--argjson opts "$menu_opts" \
'{name: $name, type: $type} +
(if $min != null then {min: $min} else {} end) +
(if $max != null then {max: $max} else {} end) +
(if $step != null then {step: $step} else {} end) +
(if $default != null then {default: $default} else {} end) +
(if ($opts | length) > 0 then {options: $opts} else {} end)')
controls_array=$(echo "$controls_array" | jq --argjson ctrl "$ctrl_obj" '. + [$ctrl]')
if [[ -n "$current_value" ]]; then
values_obj=$(echo "$values_obj" | jq --arg k "$current_ctrl" --argjson v "$current_value" '. + {($k): $v}')
fi
fi
payload=$(jq -n --argjson controls "$controls_array" --argjson values "$values_obj" \
'{controls: $controls, currentValues: $values}')
else
# Fallback: simple approach without jq (no menu options, basic controls only)
log "jq not available, using simple control discovery"
local controls="["
local values="{"
local first_ctrl=true
local first_val=true
while IFS= read -r line; do
if [[ "$line" =~ ^[[:space:]]*([a-z_][a-z0-9_]*)[[:space:]]+0x[0-9a-f]+[[:space:]]+\(([a-z]+)\)[[:space:]]*:.*value=(-?[0-9]+) ]]; then
local name="${BASH_REMATCH[1]}"
local type="${BASH_REMATCH[2]}"
local value="${BASH_REMATCH[3]}"
[[ "$first_ctrl" == "true" ]] && first_ctrl=false || controls+=","
controls+="{\"name\":\"$name\",\"type\":\"$type\"}"
[[ "$first_val" == "true" ]] && first_val=false || values+=","
values+="\"$name\":$value"
fi
done <<< "$v4l2_output"
controls+="]"
values+="}"
payload="{\"controls\":$controls,\"currentValues\":$values}"
fi
# POST to server
local payload="{\"controls\": $controls_json, \"currentValues\": $current_values_json}"
local response
response=$(curl -s --max-time 10 \
-X POST \
@@ -296,7 +314,11 @@ discover_and_report_controls() {
if echo "$response" | grep -q '"success"'; then
local count
count=$(echo "$response" | grep -o '"controlsRegistered":[0-9]*' | cut -d: -f2)
if command -v jq &>/dev/null; then
count=$(echo "$response" | jq -r '.controlsRegistered // "?"')
else
count=$(echo "$response" | grep -o '"controlsRegistered":[0-9]*' | cut -d: -f2)
fi
log "Reported $count available controls to server"
else
log "Failed to report available controls: $response"