adccmds: Support batching multiple reports into a single message

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2026-02-11 12:27:24 -05:00
parent 187481e251
commit 41bc240b16
2 changed files with 55 additions and 12 deletions

View file

@ -1,9 +1,9 @@
# Interface to Klipper micro-controller code
#
# Copyright (C) 2016-2025 Kevin O'Connor <kevin@koconnor.net>
# Copyright (C) 2016-2026 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import sys, os, zlib, logging, math
import sys, os, zlib, logging, math, struct
import serialhdl, msgproto, pins, chelper, clocksync
class error(Exception):
@ -541,6 +541,7 @@ class MCU_adc:
self._oid = self._callback = None
self._mcu.register_config_callback(self._build_config)
self._inv_max_adc = 0.
self._unpack_from = struct.Struct('<H').unpack_from
def get_mcu(self):
return self._mcu
def setup_adc_sample(self, sample_time, sample_count,
@ -570,15 +571,32 @@ class MCU_adc:
min_sample = max(0, min(0xffff, int(self._min_sample * max_adc)))
max_sample = max(0, min(0xffff, int(
math.ceil(self._max_sample * max_adc))))
# Setup periodic query and register response handler
oldcmd = (
"query_analog_in oid=%c clock=%u sample_ticks=%u sample_count=%c"
" rest_ticks=%u min_value=%hu max_value=%hu range_check_count=%c")
if self._mcu.try_lookup_command(oldcmd) is not None:
self._mcu.add_config_cmd(
"query_analog_in oid=%d clock=%d sample_ticks=%d"
" sample_count=%d rest_ticks=%d"
" min_value=%d max_value=%d range_check_count=%d" % (
self._oid, clock, sample_ticks, self._sample_count,
self._report_clock, min_sample, max_sample,
self._range_check_count), is_init=True)
self._mcu.register_response(self._old_handle_analog_in_state,
"analog_in_state", self._oid)
return
BYTES_PER_SAMPLE = 2
self._mcu.add_config_cmd(
"query_analog_in oid=%d clock=%d sample_ticks=%d sample_count=%d"
" rest_ticks=%d min_value=%d max_value=%d range_check_count=%d" % (
" rest_ticks=%d bytes_per_report=%d"
" min_value=%d max_value=%d range_check_count=%d" % (
self._oid, clock, sample_ticks, self._sample_count,
self._report_clock, min_sample, max_sample,
self._report_clock, BYTES_PER_SAMPLE, min_sample, max_sample,
self._range_check_count), is_init=True)
self._mcu.register_response(self._handle_analog_in_state,
"analog_in_state", self._oid)
def _handle_analog_in_state(self, params):
def _old_handle_analog_in_state(self, params):
last_value = params['value'] * self._inv_max_adc
next_clock = self._mcu.clock32_to_clock64(params['next_clock'])
last_read_clock = next_clock - self._report_clock
@ -586,6 +604,15 @@ class MCU_adc:
self._last_state = (last_value, last_read_time)
if self._callback is not None:
self._callback(last_read_time, last_value)
def _handle_analog_in_state(self, params):
values = self._unpack_from(params['values'])
last_value = values[0] * self._inv_max_adc
next_clock = self._mcu.clock32_to_clock64(params['next_clock'])
last_read_clock = next_clock - self._report_clock
last_read_time = self._mcu.clock_to_print_time(last_read_clock)
self._last_state = (last_value, last_read_time)
if self._callback is not None:
self._callback(last_read_time, last_value)
######################################################################

View file

@ -1,6 +1,6 @@
// Commands for controlling GPIO analog-to-digital input pins
//
// Copyright (C) 2016 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2016-2026 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
@ -17,6 +17,8 @@ struct analog_in {
struct gpio_adc pin;
uint8_t invalid_count, range_check_count;
uint8_t state, sample_count;
uint8_t bytes_per_report, data_count;
uint8_t data[48];
};
static struct task_wake analog_wake;
@ -82,16 +84,23 @@ command_query_analog_in(uint32_t *args)
a->sample_count = args[3];
a->state = a->sample_count + 1;
a->rest_time = args[4];
a->min_value = args[5];
a->max_value = args[6];
a->range_check_count = args[7];
a->bytes_per_report = args[5];
a->data_count = 0;
a->min_value = args[6];
a->max_value = args[7];
a->range_check_count = args[8];
if (! a->sample_count)
return;
if (a->bytes_per_report > ARRAY_SIZE(a->data))
shutdown("Invalid analog_in bytes_per_report");
sched_add_timer(&a->timer);
}
DECL_COMMAND(command_query_analog_in,
"query_analog_in oid=%c clock=%u sample_ticks=%u sample_count=%c"
" rest_ticks=%u min_value=%hu max_value=%hu range_check_count=%c");
" rest_ticks=%u bytes_per_report=%c"
" min_value=%hu max_value=%hu range_check_count=%c");
#define BYTES_PER_SAMPLE 2
void
analog_in_task(void)
@ -112,8 +121,15 @@ analog_in_task(void)
uint32_t next_begin_time = a->next_begin_time;
a->state++;
irq_enable();
sendf("analog_in_state oid=%c next_clock=%u value=%hu"
, oid, next_begin_time, value);
uint8_t *d = &a->data[a->data_count];
d[0] = value;
d[1] = value >> 8;
a->data_count += BYTES_PER_SAMPLE;
if (a->data_count + BYTES_PER_SAMPLE > a->bytes_per_report) {
sendf("analog_in_state oid=%c next_clock=%u values=%*s"
, oid, next_begin_time, a->data_count, a->data);
a->data_count = 0;
}
}
}
DECL_TASK(analog_in_task);