Merge branch 'feature/tcp-randomizer' of github.com:quartiq/stabilizer into feature/tcp-randomizer
This commit is contained in:
commit
a9858873d8
|
@ -0,0 +1,4 @@
|
||||||
|
# add changes-hitl label if any hitl scripts are changed
|
||||||
|
# REVIEW those changes before approving HITL deployment!
|
||||||
|
changes-hitl:
|
||||||
|
- any: [hitl/*]
|
|
@ -1,4 +1,4 @@
|
||||||
name: HITL
|
name: HITL Trigger
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
@ -6,7 +6,7 @@ on:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
hitl:
|
hitl-trigger:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: hitl
|
environment: hitl
|
||||||
steps:
|
steps:
|
||||||
|
@ -16,3 +16,12 @@ jobs:
|
||||||
event-type: stabilizer
|
event-type: stabilizer
|
||||||
repository: quartiq/hitl
|
repository: quartiq/hitl
|
||||||
client-payload: '{"github": ${{ toJson(github) }}}'
|
client-payload: '{"github": ${{ toJson(github) }}}'
|
||||||
|
|
||||||
|
- name: Wait for startup
|
||||||
|
run: sleep 30
|
||||||
|
|
||||||
|
- uses: fountainhead/action-wait-for-check@v1.0.0
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
checkName: HITL Run Status
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
|
@ -0,0 +1,12 @@
|
||||||
|
name: "Pull Request Labeler"
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
labeler:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/labeler@v3
|
||||||
|
with:
|
||||||
|
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
|
@ -1,6 +1,6 @@
|
||||||
[![QUARTIQ Matrix Chat](https://img.shields.io/matrix/quartiq:matrix.org)](https://matrix.to/#/#quartiq:matrix.org)
|
[![QUARTIQ Matrix Chat](https://img.shields.io/matrix/quartiq:matrix.org)](https://matrix.to/#/#quartiq:matrix.org)
|
||||||
[![Continuous Integration](https://github.com/quartiq/stabilizer/actions/workflows/ci.yml/badge.svg)](https://github.com/quartiq/stabilizer/actions/workflows/ci.yml)
|
[![Continuous Integration](https://github.com/quartiq/stabilizer/actions/workflows/ci.yml/badge.svg)](https://github.com/quartiq/stabilizer/actions/workflows/ci.yml)
|
||||||
[![HITL (private)](https://github.com/quartiq/hitl/workflows/Stabilizer/badge.svg)](https://github.com/quartiq/hitl/actions?query=workflow%3AStabilizer)
|
[![Stabilizer HITL [Nightly]](https://github.com/quartiq/hitl/actions/workflows/stabilizer-nightly.yml/badge.svg)](https://github.com/quartiq/hitl/actions/workflows/stabilizer-nightly.yml)
|
||||||
|
|
||||||
# Stabilizer Firmware
|
# Stabilizer Firmware
|
||||||
|
|
||||||
|
|
|
@ -558,13 +558,15 @@ impl ProfileSerializer {
|
||||||
/// * `channels` - A list of channels to apply the configuration to.
|
/// * `channels` - A list of channels to apply the configuration to.
|
||||||
/// * `ftw` - If provided, indicates a frequency tuning word for the channels.
|
/// * `ftw` - If provided, indicates a frequency tuning word for the channels.
|
||||||
/// * `pow` - If provided, indicates a phase offset word for the channels.
|
/// * `pow` - If provided, indicates a phase offset word for the channels.
|
||||||
/// * `acr` - If provided, indicates the amplitude control register for the channels.
|
/// * `acr` - If provided, indicates the amplitude control register for the channels. The ACR
|
||||||
|
/// should be stored in the 3 LSB of the word. Note that if amplitude scaling is to be used,
|
||||||
|
/// the "Amplitude multiplier enable" bit must be set.
|
||||||
pub fn update_channels(
|
pub fn update_channels(
|
||||||
&mut self,
|
&mut self,
|
||||||
channels: &[Channel],
|
channels: &[Channel],
|
||||||
ftw: Option<u32>,
|
ftw: Option<u32>,
|
||||||
pow: Option<u16>,
|
pow: Option<u16>,
|
||||||
acr: Option<u16>,
|
acr: Option<u32>,
|
||||||
) {
|
) {
|
||||||
let mut csr: u8 = *0u8.set_bits(1..3, self.mode as u8);
|
let mut csr: u8 = *0u8.set_bits(1..3, self.mode as u8);
|
||||||
for channel in channels.iter() {
|
for channel in channels.iter() {
|
||||||
|
@ -582,7 +584,7 @@ impl ProfileSerializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(acr) = acr {
|
if let Some(acr) = acr {
|
||||||
self.add_write(Register::ACR, &acr.to_be_bytes());
|
self.add_write(Register::ACR, &acr.to_be_bytes()[1..=3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,14 +608,14 @@ impl ProfileSerializer {
|
||||||
// Pad the buffer to 32-bit alignment by adding dummy writes to CSR and LSRR.
|
// Pad the buffer to 32-bit alignment by adding dummy writes to CSR and LSRR.
|
||||||
let padding = 4 - (self.index % 4);
|
let padding = 4 - (self.index % 4);
|
||||||
match padding {
|
match padding {
|
||||||
0 => {}
|
|
||||||
1 => {
|
1 => {
|
||||||
// For a pad size of 1, we have to pad with 5 bytes to align things.
|
// For a pad size of 1, we have to pad with 5 bytes to align things.
|
||||||
self.add_write(Register::CSR, &[(self.mode as u8) << 1]);
|
self.add_write(Register::CSR, &[(self.mode as u8) << 1]);
|
||||||
self.add_write(Register::LSRR, &[0, 0, 0]);
|
self.add_write(Register::LSRR, &[0, 0]);
|
||||||
}
|
}
|
||||||
2 => self.add_write(Register::CSR, &[(self.mode as u8) << 1]),
|
2 => self.add_write(Register::CSR, &[(self.mode as u8) << 1]),
|
||||||
3 => self.add_write(Register::LSRR, &[0, 0, 0]),
|
3 => self.add_write(Register::LSRR, &[0, 0]),
|
||||||
|
4 => {}
|
||||||
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ python3 -m venv --system-site-packages py
|
||||||
. py/bin/activate
|
. py/bin/activate
|
||||||
python3 -m pip install -r requirements.txt
|
python3 -m pip install -r requirements.txt
|
||||||
|
|
||||||
|
cargo flash --elf target/thumbv7em-none-eabihf/release/dual-iir --chip STM32H743ZITx
|
||||||
|
|
||||||
# Test pinging Stabilizer. This exercises that:
|
# Test pinging Stabilizer. This exercises that:
|
||||||
# * DHCP is functional and an IP has been acquired
|
# * DHCP is functional and an IP has been acquired
|
||||||
# * Stabilizer's network is functioning as intended
|
# * Stabilizer's network is functioning as intended
|
||||||
|
@ -22,4 +24,6 @@ python3 -m pip install -r requirements.txt
|
||||||
ping -c 5 -w 20 stabilizer-hitl
|
ping -c 5 -w 20 stabilizer-hitl
|
||||||
|
|
||||||
# Test the MQTT interface.
|
# Test the MQTT interface.
|
||||||
python3 miniconf.py dt/sinara/stabilizer afe/0 '"G2"'
|
python3 miniconf.py dt/sinara/stabilizer afe/0='"G2"'
|
||||||
|
python3 miniconf.py dt/sinara/stabilizer afe/0='"G1"' iir_ch/0/0=\
|
||||||
|
'{"y_min": -32767, "y_max": 32767, "y_offset": 0, "ba": [1.0, 0, 0, 0, 0]}'
|
||||||
|
|
20
miniconf.py
20
miniconf.py
|
@ -83,19 +83,19 @@ class Miniconf:
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description='Miniconf command line interface.',
|
description='Miniconf command line interface.',
|
||||||
epilog='''Example:
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
%(prog)s -v -b mqtt dt/sinara/stabilizer afe/0 '"G10"'
|
epilog='''Examples:
|
||||||
''')
|
%(prog)s dt/sinara/stabilizer afe/0='"G2"' iir_ch/0/0=\
|
||||||
|
'{"y_min": -32767, "y_max": 32767, "y_offset": 0, "ba": [1.0, 0, 0, 0, 0]}'
|
||||||
|
''')
|
||||||
parser.add_argument('-v', '--verbose', action='count', default=0,
|
parser.add_argument('-v', '--verbose', action='count', default=0,
|
||||||
help='Increase logging verbosity')
|
help='Increase logging verbosity')
|
||||||
parser.add_argument('--broker', '-b', default='mqtt', type=str,
|
parser.add_argument('--broker', '-b', default='mqtt', type=str,
|
||||||
help='The MQTT broker address')
|
help='The MQTT broker address')
|
||||||
parser.add_argument('prefix', type=str,
|
parser.add_argument('prefix', type=str,
|
||||||
help='The MQTT topic prefix of the target')
|
help='The MQTT topic prefix of the target')
|
||||||
parser.add_argument('path', type=str,
|
parser.add_argument('settings', metavar="KEY=VALUE", nargs='+',
|
||||||
help='The setting path to configure')
|
help='JSON encoded values for settings path keys.')
|
||||||
parser.add_argument('value', type=str,
|
|
||||||
help='The value of setting in JSON format')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
@ -107,8 +107,10 @@ def main():
|
||||||
|
|
||||||
async def configure_settings():
|
async def configure_settings():
|
||||||
interface = await Miniconf.create(args.prefix, args.broker)
|
interface = await Miniconf.create(args.prefix, args.broker)
|
||||||
response = await interface.command(args.path, json.loads(args.value))
|
for kv in args.settings:
|
||||||
print(f"Response: {response}")
|
path, value = kv.split("=", 1)
|
||||||
|
response = await interface.command(path, json.loads(value))
|
||||||
|
print(response)
|
||||||
|
|
||||||
loop.run_until_complete(configure_settings())
|
loop.run_until_complete(configure_settings())
|
||||||
|
|
||||||
|
|
|
@ -495,13 +495,10 @@ pub fn setup(
|
||||||
.set_speed(hal::gpio::Speed::VeryHigh);
|
.set_speed(hal::gpio::Speed::VeryHigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mac_addr = match eeprom::read_eui48(&mut eeprom_i2c) {
|
let mac_addr = smoltcp::wire::EthernetAddress(eeprom::read_eui48(
|
||||||
Err(_) => {
|
&mut eeprom_i2c,
|
||||||
info!("Could not read EEPROM, using default MAC address");
|
&mut delay,
|
||||||
smoltcp::wire::EthernetAddress([0x10, 0xE2, 0xD5, 0x00, 0x03, 0x00])
|
));
|
||||||
}
|
|
||||||
Ok(raw_mac) => smoltcp::wire::EthernetAddress(raw_mac),
|
|
||||||
};
|
|
||||||
|
|
||||||
let network_devices = {
|
let network_devices = {
|
||||||
// Configure the ethernet controller
|
// Configure the ethernet controller
|
||||||
|
|
|
@ -1,12 +1,42 @@
|
||||||
use embedded_hal::blocking::i2c::WriteRead;
|
use embedded_hal::blocking::{delay::DelayMs, i2c::WriteRead};
|
||||||
|
|
||||||
|
// The EEPROM is a variant without address bits, so the 3 LSB of this word are "dont-cares".
|
||||||
const I2C_ADDR: u8 = 0x50;
|
const I2C_ADDR: u8 = 0x50;
|
||||||
|
|
||||||
pub fn read_eui48<T>(i2c: &mut T) -> Result<[u8; 6], T::Error>
|
// The MAC address is stored in the last 6 bytes of the 256 byte address space.
|
||||||
|
const MAC_POINTER: u8 = 0xFA;
|
||||||
|
|
||||||
|
pub fn read_eui48<T>(i2c: &mut T, delay: &mut impl DelayMs<u8>) -> [u8; 6]
|
||||||
where
|
where
|
||||||
T: WriteRead,
|
T: WriteRead,
|
||||||
{
|
{
|
||||||
let mut buffer = [0u8; 6];
|
let mut previous_read: Option<[u8; 6]> = None;
|
||||||
i2c.write_read(I2C_ADDR, &[0xFA_u8], &mut buffer)?;
|
// On Stabilizer v1.1 and earlier hardware, there is a fault where the I2C bus is not connected
|
||||||
Ok(buffer)
|
// to the CPU until the P12V0A rail enables, which can take many seconds, or may never come up
|
||||||
|
// at all. During these transient turn-on conditions, we may fail the I2C read operation. To
|
||||||
|
// accomodate this, we repeat the I2C read for a set number of attempts with a fixed delay
|
||||||
|
// between them. Then, we wait for the bus to stabilize by waiting until the MAC address
|
||||||
|
// read-out is identical for two consecutive reads.
|
||||||
|
for _ in 0..40 {
|
||||||
|
let mut buffer = [0u8; 6];
|
||||||
|
if i2c
|
||||||
|
.write_read(I2C_ADDR, &[MAC_POINTER], &mut buffer)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
if let Some(old_read) = previous_read {
|
||||||
|
if old_read == buffer {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previous_read.replace(buffer);
|
||||||
|
} else {
|
||||||
|
// Remove any pending previous read if we failed the last attempt.
|
||||||
|
previous_read.take();
|
||||||
|
}
|
||||||
|
|
||||||
|
delay.delay_ms(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Failed to read MAC address");
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,14 +144,15 @@ impl<'a> ProfileBuilder<'a> {
|
||||||
/// * `channels` - A list of channels to apply the configuration to.
|
/// * `channels` - A list of channels to apply the configuration to.
|
||||||
/// * `ftw` - If provided, indicates a frequency tuning word for the channels.
|
/// * `ftw` - If provided, indicates a frequency tuning word for the channels.
|
||||||
/// * `pow` - If provided, indicates a phase offset word for the channels.
|
/// * `pow` - If provided, indicates a phase offset word for the channels.
|
||||||
/// * `acr` - If provided, indicates the amplitude control register for the channels.
|
/// * `acr` - If provided, indicates the amplitude control register for the channels. The
|
||||||
|
/// 24-bits of the ACR should be stored in the last 3 LSB.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn update_channels(
|
pub fn update_channels(
|
||||||
mut self,
|
mut self,
|
||||||
channels: &[Channel],
|
channels: &[Channel],
|
||||||
ftw: Option<u32>,
|
ftw: Option<u32>,
|
||||||
pow: Option<u16>,
|
pow: Option<u16>,
|
||||||
acr: Option<u16>,
|
acr: Option<u32>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.serializer.update_channels(channels, ftw, pow, acr);
|
self.serializer.update_channels(channels, ftw, pow, acr);
|
||||||
self
|
self
|
||||||
|
|
Loading…
Reference in New Issue