rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
motor_screen.c File Reference

The motor and ESC (electronic speed controller) bench screen, a workbench (ui_workbench.h) with the tasks LIVE, PROGRAM and SETTINGS. More...

#include "motor_screen.h"
#include <stdint.h>
#include <string.h>
#include "ui_pinlist.h"
#include "ui_plot.h"
#include "link_pages.h"
#include "settings.h"
#include "ui_slider.h"
#include "ui_tabs.h"
#include "ui_value_gate.h"
#include "prog_registry.h"
#include "outputs_screen.h"
#include "port_view.h"
#include "ui_text.h"
#include "ui_theme.h"
#include "ui_widgets.h"
#include "motor_screen_int.h"
#include "motor_live_int.h"

Functions

void motor_invalidate (void)
void mo_bind_colours (void)
 Sets the plot's and the slider's colours from the active theme.
static void reset (void)
 The screen laid out afresh: the strip, the pages, the plot, PLOT | TABLE, the throttle's track and step keys, ARM and RESET PEAKS.
bool mo_value_live (void)
 Returns whether the throttle follows its controls: only in UI_VALUE_LIVE, not on a disarmed bench, not between the ARM hold and the bench's answer, and not after a DISARM or STOP until the bench reports disarmed.
void mo_end_drag (void)
 Ends a drag on the track and keeps the knob out of the frame.
static void value_edge (ui_value_edge_t edge, ui_value_state_t before)
void mo_post (motor_cmd_kind_t kind, float value)
 Posts a command in the one slot, coalescing: a new command overwrites the pending one, except that a pending DISARM survives everything.
bool motor_screen_poll_cmd (motor_cmd_t *out)
void motor_screen_push (const bench_state_t *b)
motor_plot_state_t motor_screen_plot_state (void)
int motor_screen_plot_samples (void)
bool motor_screen_peak_shown (int channel)
 Whether channel channel's peak is drawn as a value – 0 voltage, 1 current, 2 power, 3rpm: a valid reading of it has arrived since the run started or the peaks were reset. It stays drawn when the live reading goes empty, as when a source stops answering mid-run and the run's peaks it measured stand.
bool mo_no_motor_pin (void)
 Whether the throttle's binding is read and names no motor pin: no GPIO (general-purpose input/output) pin and no DShot port. The TARGET row then reads NO MOTOR PIN, and nothing can be driven.
bool mo_arm_locked (void)
 Whether ARM takes no press: the servo programmer holds a port, or the binding names no motor pin. DISARM takes a press in both.
void motor_screen_cancel_arm (void)
void mo_throttle_from_zero (void)
 Puts the slider, the readout and the step keys at 0% across an arm or disarm edge, drops a pending throttle and releases a drag.
void motor_screen_set_armed (bool armed)
 What the bench is doing, which is what bounds a run.
void motor_screen_set_esc_kv (int kv)
void motor_screen_set_throttle_pins (uint64_t gpio_mask, bool known)
void motor_screen_set_throttle_protocol (uint8_t proto)
bool mo_bench_safe (void)
 Returns whether the bench is SAFE as this screen sees it: disarmed, with no ARM or DISARM asked and unanswered.
bool mo_endpoints_free (void)
 Returns whether the Idle pulse and Full pulse may change: SAFE and ARM not held.
bool mo_target_locked (void)
 Returns whether the TARGET row takes no press: the bench is not SAFE, ARM is held or the servo programmer holds its port.
bool motor_screen_target_locked (void)
int motor_screen_task (void)
bool motor_screen_session_shown (void)
int motor_screen_pane (void)
float motor_screen_throttle (void)
void motor_screen_set_throttle (float pct)
void motor_screen_knob_frame (void)
void motor_screen_knob_cancel (void)
void motor_screen_knob (float span_fraction)
static void leave (void)
static void enter (void)
static bool back (void)
static void cancel (void)
const ui_screen_t * motor_screen (void)

Variables

const ui_plot_series_t mo_series [S_COUNT]
 The four channels' plot series: volts, amps, power and RPM.
const uint16_t mo_ok [S_COUNT]
 Per channel, the bench report flags that make its reading valid.
const ui_text_id_t mo_names [S_COUNT]
 Per channel, the text id of its name.
static const ui_text_id_t k_tab_labels []
mo_state_t mo_s
 MOTOR & ESC's LIVE state, in motor_screen.c.
static const ui_screen_t k_screen

Detailed Description

The motor and ESC (electronic speed controller) bench screen, a workbench (ui_workbench.h) with the tasks LIVE, PROGRAM and SETTINGS.

This file is the screen and LIVE's page: the plot or the table, the throttle, the readouts and the CONTROL card on the right. It holds their state and commands; motor_events.c takes their touch events and frames, motor_draw.c draws them, and motor_live_int.h is what the three share. The strip and the CONTROL card's TARGET row are motor_workbench.c's, PROGRAM's list and its sessions motor_program_page.c's, SETTINGS' page motor_settings_page.c's; the layout they share is motor_screen_int.h. The rail on the right, the readouts and the CONTROL card with TARGET, ARM and RESET PEAKS, is the same on every task, until a session on PROGRAM opens: a full-width session takes the whole body, and the strip row shows the output strip in place of the tabs and the card.

SPDX-License-Identifier: MIT

Function Documentation

◆ mo_arm_locked()

bool mo_arm_locked ( void )

Whether ARM takes no press: the servo programmer holds a port, or the binding names no motor pin. DISARM takes a press in both.

Returns
true when ARM is dimmed and refused

◆ mo_bench_safe()

bool mo_bench_safe ( void )

Returns whether the bench is SAFE as this screen sees it: disarmed, with no ARM or DISARM asked and unanswered.

Returns
true when SAFE

◆ mo_endpoints_free()

bool mo_endpoints_free ( void )

Returns whether the Idle pulse and Full pulse may change: SAFE and ARM not held.

Returns
true when the endpoints are free

◆ mo_no_motor_pin()

bool mo_no_motor_pin ( void )

Whether the throttle's binding is read and names no motor pin: no GPIO (general-purpose input/output) pin and no DShot port. The TARGET row then reads NO MOTOR PIN, and nothing can be driven.

Returns
true when the binding is read and empty

◆ mo_post()

void mo_post ( motor_cmd_kind_t kind,
float value )

Posts a command in the one slot, coalescing: a new command overwrites the pending one, except that a pending DISARM survives everything.

Parameters
kindthe command
valuethe throttle for MOTOR_CMD_THROTTLE, percent

◆ mo_target_locked()

bool mo_target_locked ( void )

Returns whether the TARGET row takes no press: the bench is not SAFE, ARM is held or the servo programmer holds its port.

Returns
true when the row is locked

◆ mo_value_live()

bool mo_value_live ( void )

Returns whether the throttle follows its controls: only in UI_VALUE_LIVE, not on a disarmed bench, not between the ARM hold and the bench's answer, and not after a DISARM or STOP until the bench reports disarmed.

Returns
true when the throttle is live

◆ motor_screen_cancel_arm()

void motor_screen_cancel_arm ( void )

Abandon a hold that is under way, because the bench has been stopped. A stop on a bench that was not armed changes nothing about whether it is armed, and the gesture must end all the same.

◆ motor_screen_knob()

void motor_screen_knob ( float span_fraction)

Move the throttle by span_fraction of the slider's span, from the rotary knob (knob.h). Relative: the value changes by how far the knob turned. Nothing happens for a zero fraction, while a finger is dragging the slider, while the bench is not armed, or on a task other than LIVE, where the throttle is out of sight: a turn made then is not kept for the next arm. It posts the same throttle command a touch does and never arms. It posts only into an empty slot or over a throttle: any other pending command (an arm, a disarm, a peak reset) stays and the knob's motion is dropped.

◆ motor_screen_knob_cancel()

void motor_screen_knob_cancel ( void )

Withdraw the knob's throttle command if it is still waiting to be taken: the slider returns to its value from before the knob, and a throttle that was pending before the knob moved it is pending again with that value. A command posted by a touch since, or already taken, is left alone.

◆ motor_screen_knob_frame()

void motor_screen_knob_frame ( void )

Start of a frame, before its touch events: forget that a finger owned the slider. The knob moves nothing in a frame in which a finger owned the slider at any point, including a press and release inside it, because the touch has already set the value the knob would move.

◆ motor_screen_pane()

int motor_screen_pane ( void )

LIVE's view shown, a motor_pane_t: PLOT or TABLE.

◆ motor_screen_peak_shown()

bool motor_screen_peak_shown ( int channel)

Whether channel channel's peak is drawn as a value – 0 voltage, 1 current, 2 power, 3rpm: a valid reading of it has arrived since the run started or the peaks were reset. It stays drawn when the live reading goes empty, as when a source stops answering mid-run and the run's peaks it measured stand.

Parameters
channel0 voltage, 1 current, 2 power, 3rpm
Returns
true while that peak is drawn as a value

◆ motor_screen_plot_samples()

int motor_screen_plot_samples ( void )

Samples in the trace, capped at UI_PLOT_HISTORY. The plot is narrower than that, so a longer run is drawn truncated to its newest columns.

◆ motor_screen_poll_cmd()

bool motor_screen_poll_cmd ( motor_cmd_t * out)

True when a command was waiting; clears it.

◆ motor_screen_push()

void motor_screen_push ( const bench_state_t * b)

Called per sample, so the plot's time base is the sample rate. The readouts take every sample; the plot takes them only while armed.

◆ motor_screen_session_shown()

bool motor_screen_session_shown ( void )

Whether PROGRAM's session is shown, full width with the output strip over it.

◆ motor_screen_set_armed()

void motor_screen_set_armed ( bool armed)

What the bench is doing, which is what bounds a run.

Arming clears the plot and starts it; disarming holds it as it stood. The caller reports the bench's own arm state, not a request made of it: a disarm that has been asked for and not yet answered must not erase the run it is ending.

The throttle follows the bench, through ui_value_gate.h. Outside UI_VALUE_LIVE no control changes the value: the slider, its -1 and +1 buttons and motor_screen_knob() post nothing and move nothing, from the first frame to the bench's answer to an ARM, and from a MOTOR_CMD_DISARM being posted or motor_screen_cancel_arm() on an armed bench until this is called with false. The change to disarmed returns the slider to 0%, drops a throttle command waiting to be polled and ends a drag under way.

The hold that posts MOTOR_CMD_ARM does the same. The change to armed does it for an arm that hold did not ask for; after the hold's ask it leaves the slider, which only motor_screen_set_throttle() can have moved since, as it is. Reporting the same state again changes nothing.

◆ motor_screen_set_esc_kv()

void motor_screen_set_esc_kv ( int kv)

The kV the connected ESC reports, or 0 when it reports none. Preferred over the SET_MOTOR_KV setting when it is non-zero.

◆ motor_screen_set_throttle()

void motor_screen_set_throttle ( float pct)

The application's hook: sets the slider on an armed or a disarmed bench and posts nothing. Not a control, and not held to the armed state.

◆ motor_screen_set_throttle_pins()

void motor_screen_set_throttle_pins ( uint64_t gpio_mask,
bool known )

The GPIOs the throttle drives now: every pin bound as MOTOR PWM or DShot, bit n for GPIO n, from the binding the application last read. known is false while no binding was read; the mask is then taken as empty. The CONTROL card's TARGET row names them, or says there are none or that the binding is not read.

◆ motor_screen_set_throttle_protocol()

void motor_screen_set_throttle_protocol ( uint8_t proto)

The protocol the throttle's pins are bound as, an index into outbind_protos() (outbind_role_proto()): 0 when none is known, MOTOR_PROTO_MIXED when they are bound as several. The TARGET row puts its name before the pins.

◆ motor_screen_target_locked()

bool motor_screen_target_locked ( void )

Whether the TARGET row takes no press now: the bench is not SAFE (an ARM held, asked or in force, or a DISARM not yet answered), or the servo programmer holds its port.

◆ motor_screen_task()

int motor_screen_task ( void )

The task shown, a ui_wb_task_t: LIVE, PROGRAM or SETTINGS. A tile opens LIVE; the home tag over SETTINGS' keypad closes the keypad, and in PROGRAM's session climbs it one level (back()).

Variable Documentation

◆ k_screen

const ui_screen_t k_screen
static
Initial value:
= {
.title = "MOTOR & ESC",
.reset = reset,
.enter = enter,
.leave = leave,
.tick = mo_tick,
.event = mo_event,
.cancel = cancel,
.render = mo_render,
.back = back,
.safe_at = mo_safe_at,
}
static void cancel(void)
The panel could not hand over every touch event, so this screen's record of the glass is stale.
Definition analyser_screen.c:658
static void reset(void)
The screen's state cleared: CHANNELS shown, nothing decoded, the tabs laid out.
Definition analyser_screen.c:176
static bool back(void)
The home tag: over the keypad it is CANCEL.
Definition balance_screen.c:251
static void leave(void)
The screen is left: the keypad closes, with nothing typed taken.
Definition balance_screen.c:264
void mo_render(gfx_canvas_t *c, int buffer_index)
Draws the screen into frame buffer buffer_index.
Definition motor_draw.c:601
void mo_event(const touch_event_t *evt)
Takes a touch event.
Definition motor_events.c:120
void mo_tick(float dt_s)
Advances the screen by one frame: the ARM hold and flash animations, the knob and the polled state.
Definition motor_events.c:292
bool mo_safe_at(int x, int y)
Returns whether a DOWN at (x, y) is on a control whose press stops what the bench drives: a session's...
Definition motor_events.c:111

◆ k_tab_labels

const ui_text_id_t k_tab_labels[]
static
Initial value:
= { TX_MO_TAB_PLOT,
TX_MO_TAB_TABLE }

◆ mo_names

const ui_text_id_t mo_names[S_COUNT]
Initial value:
= { TX_MO_VOLT, TX_MO_CURR,
TX_MO_PWR, TX_MO_RPM }

Per channel, the text id of its name.

◆ mo_ok

const uint16_t mo_ok[S_COUNT]
Initial value:
= {
LINK_BN_VOLTAGE_OK, LINK_BN_CURRENT_OK,
LINK_BN_VOLTAGE_OK | LINK_BN_CURRENT_OK, LINK_BN_RPM_OK,
}

Per channel, the bench report flags that make its reading valid.

◆ mo_series

const ui_plot_series_t mo_series[S_COUNT]
Initial value:
= {
{ "VOLT", "V", 0, 2, 5.0f, 0 },
{ "CURR", "A", 0, 1, 1.0f, 0 },
{ "PWR", "W", 0, 0, 50.0f, 0 },
{ "RPM", "RPM", 0, 0, 1000.0f, 0 },
}

The four channels' plot series: volts, amps, power and RPM.