From 1cff400d0091f864708a4c041551fcbecb18e7b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 28 May 2019 10:15:15 +0000 Subject: [PATCH] cleanup, robustify --- README.md | 21 +++++++++++++++++---- src/iir.rs | 1 + src/main.rs | 14 +++++++++----- stabilizer.py | 8 +++++--- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c786184..3a51d16 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,20 @@ * dual channel * SPI ADC * SPI DAC -* fixed AFE gains -* 500 kHz rate, timed -* < 2 µs latency, unmatched +* 500 kHz rate, timed sampling +* 2 µs latency, unmatched between channels * f32 IIR math * generic biquad (second order) IIR filter * anti-windup * derivative kick avoidance -* configurable output limits + +## Limitations/TODOs + +* Fixed AFE gains +* The IP and MAC address are [hardcoded](src/main.rs) +* Expose configurable limits +* 100Base-T only +* Digital IO, GPIO header, AFE header, EEM header are not handled ## Hardware @@ -33,3 +39,10 @@ See https://github.com/sinara-hw/Stabilizer * `rustup target add thumbv7em-none-eabihf` * `openocd -f stabilizer.cfg` and leave it running * `cargo run --release` + + +## Protocol + +Stabilizer can be configured via newline-delimited JSON over TCP. +It listens on port 1235. [stabilizer.py](stabilizer.py) contains a reference +implementation of the protocol. diff --git a/src/iir.rs b/src/iir.rs index 85c3787..344028f 100644 --- a/src/iir.rs +++ b/src/iir.rs @@ -39,6 +39,7 @@ fn macc(y0: T, x: &[T], a: &[T]) -> T x.iter().zip(a.iter()).map(|(&i, &j)| i * j).fold(y0, |y, xa| y + xa) } +#[allow(unused)] impl IIR { pub fn set_pi(&mut self, kp: f32, ki: f32, g: f32) -> Result<(), &str> { let ki = copysign(ki, kp); diff --git a/src/main.rs b/src/main.rs index 6248406..cee7123 100644 --- a/src/main.rs +++ b/src/main.rs @@ -692,7 +692,7 @@ fn main() -> ! { #[derive(Deserialize,Serialize)] struct Request { - channel: i8, + channel: u8, iir: IIR, } @@ -731,10 +731,14 @@ fn handle_command(socket: &mut net::socket::TcpSocket) { } else { match from_slice::(&data) { Ok(request) => { - cortex_m::interrupt::free(|_| { - unsafe { IIR_CH[request.channel as usize] = request.iir; }; - }); - Response{ code: 200, message: "ok" } + if request.channel > 1 { + Response{ code: 500, message: "invalid channel" } + } else { + cortex_m::interrupt::free(|_| { + unsafe { IIR_CH[request.channel as usize] = request.iir; }; + }); + Response{ code: 200, message: "ok" } + } }, Err(err) => { warn!("parse error {}", err); diff --git a/stabilizer.py b/stabilizer.py index beecd50..0b1e86a 100644 --- a/stabilizer.py +++ b/stabilizer.py @@ -32,12 +32,13 @@ class StabilizerConfig: class IIR: t_update = 2e-6 + full_scale = float((1 << 15) - 1) def __init__(self): self.ba = np.zeros(5, np.float32) self.y_offset = 0. - self.y_min = -float(1 << 15) - self.y_max = float(1 << 15) - 1 + self.y_min = -self.full_scale - 1 + self.y_max = self.full_scale def as_dict(self): iir = OD() @@ -70,7 +71,7 @@ class IIR: self.ba[4] = 0. def set_x_offset(self, o): - b = self.ba[:3].sum()*((1 << 15) - 1) + b = self.ba[:3].sum()*self.full_scale self.y_offset = b*o @@ -100,6 +101,7 @@ if __name__ == "__main__": i.set_x_offset(args.offset) s = StabilizerConfig() await s.connect(args.stabilizer) + assert args.channel in range(2) r = await s.set(args.channel, i) loop.run_until_complete(main())