forked from M-Labs/nac3
mgmt: implemented config write
This commit is contained in:
parent
1695076baf
commit
7dbffadf08
|
@ -25,6 +25,10 @@ The following configuration keys are available:
|
||||||
- ``ip6``: IPv6 address.
|
- ``ip6``: IPv6 address.
|
||||||
- ``startup``: startup kernel in ELF format (as produced by ``artiq_compile``).
|
- ``startup``: startup kernel in ELF format (as produced by ``artiq_compile``).
|
||||||
- ``rtioclk``: source of RTIO clock; valid values are ``external`` and ``internal``.
|
- ``rtioclk``: source of RTIO clock; valid values are ``external`` and ``internal``.
|
||||||
|
- ``boot``: SD card "boot.bin" file, for replacing the boot firmware/gateware. Write only.
|
||||||
|
|
||||||
|
Configurations can be read/written/removed via ``artiq_coremgmt``. Config erase is
|
||||||
|
not implemented as it seems not very useful.
|
||||||
|
|
||||||
Development instructions
|
Development instructions
|
||||||
------------------------
|
------------------------
|
||||||
|
|
|
@ -14,7 +14,7 @@ let
|
||||||
name = "zc706-firmware";
|
name = "zc706-firmware";
|
||||||
|
|
||||||
src = ./src;
|
src = ./src;
|
||||||
cargoSha256 = "0hjpxqz9ilr4fxi3w3xswn9dcrsh3g2m42vig80xdkpb7wn9gvs0";
|
cargoSha256 = "1hmhnwvkn3z7qw4z6lxhczjl9r402k7xpycp987fnw7rfrqj9cp7";
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
pkgs.gnumake
|
pkgs.gnumake
|
||||||
|
|
|
@ -56,7 +56,7 @@ checksum = "e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core_io"
|
name = "core_io"
|
||||||
version = "0.1.20200410"
|
version = "0.1.20200410"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
@ -186,7 +186,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libasync"
|
name = "libasync"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
"libcortex_a9",
|
"libcortex_a9",
|
||||||
|
@ -198,7 +198,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libboard_zynq"
|
name = "libboard_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
|
@ -222,7 +222,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libconfig"
|
name = "libconfig"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core_io",
|
"core_io",
|
||||||
"fatfs",
|
"fatfs",
|
||||||
|
@ -233,7 +233,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcortex_a9"
|
name = "libcortex_a9"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"libregister",
|
"libregister",
|
||||||
|
@ -249,7 +249,7 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libregister"
|
name = "libregister"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit_field",
|
"bit_field",
|
||||||
"vcell",
|
"vcell",
|
||||||
|
@ -259,7 +259,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsupport_zynq"
|
name = "libsupport_zynq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773"
|
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compiler_builtins",
|
"compiler_builtins",
|
||||||
"libboard_zynq",
|
"libboard_zynq",
|
||||||
|
|
|
@ -6,7 +6,7 @@ authors = ["M-Labs"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706"]
|
||||||
default = ["target_zc706"]
|
default = ["target_zc706"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
|
@ -343,8 +343,8 @@ async fn handle_connection(stream: &TcpStream, control: Rc<RefCell<kernel::Contr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(timer: GlobalTimer, cfg: &Config) {
|
pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||||
let net_addresses = net_settings::get_adresses(cfg);
|
let net_addresses = net_settings::get_adresses(&cfg);
|
||||||
info!("network addresses: {}", net_addresses);
|
info!("network addresses: {}", net_addresses);
|
||||||
|
|
||||||
let eth = zynq::eth::Eth::eth0(net_addresses.hardware_addr.0.clone());
|
let eth = zynq::eth::Eth::eth0(net_addresses.hardware_addr.0.clone());
|
||||||
|
@ -384,7 +384,6 @@ pub fn main(timer: GlobalTimer, cfg: &Config) {
|
||||||
|
|
||||||
Sockets::init(32);
|
Sockets::init(32);
|
||||||
|
|
||||||
mgmt::start();
|
|
||||||
analyzer::start();
|
analyzer::start();
|
||||||
moninj::start(timer);
|
moninj::start(timer);
|
||||||
|
|
||||||
|
@ -401,6 +400,8 @@ pub fn main(timer: GlobalTimer, cfg: &Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mgmt::start(cfg);
|
||||||
|
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let connection = Rc::new(Semaphore::new(1, 1));
|
let connection = Rc::new(Semaphore::new(1, 1));
|
||||||
let terminate = Rc::new(Semaphore::new(0, 1));
|
let terminate = Rc::new(Semaphore::new(0, 1));
|
||||||
|
|
|
@ -192,5 +192,5 @@ pub fn main_core0() {
|
||||||
init_rtio(&mut timer, &cfg);
|
init_rtio(&mut timer, &cfg);
|
||||||
task::spawn(report_async_rtio_errors());
|
task::spawn(report_async_rtio_errors());
|
||||||
|
|
||||||
comms::main(timer, &cfg);
|
comms::main(timer, cfg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use futures::{future::poll_fn, task::Poll};
|
use futures::{future::poll_fn, task::Poll};
|
||||||
use libasync::{smoltcp::TcpStream, task};
|
use libasync::{smoltcp::TcpStream, task};
|
||||||
use libboard_zynq::smoltcp;
|
use libboard_zynq::smoltcp;
|
||||||
|
use libconfig::Config;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use alloc::rc::Rc;
|
use alloc::{rc::Rc, vec::Vec, string::String};
|
||||||
use log::{self, info, warn, LevelFilter};
|
use log::{self, info, debug, warn, error, LevelFilter};
|
||||||
|
|
||||||
use crate::logger::{BufferLogger, LogBufferRef};
|
use crate::logger::{BufferLogger, LogBufferRef};
|
||||||
use crate::proto_async::*;
|
use crate::proto_async::*;
|
||||||
|
@ -44,12 +45,18 @@ pub enum Request {
|
||||||
PullLog = 7,
|
PullLog = 7,
|
||||||
SetLogFilter = 3,
|
SetLogFilter = 3,
|
||||||
SetUartLogFilter = 6,
|
SetUartLogFilter = 6,
|
||||||
|
|
||||||
|
ConfigRead = 12,
|
||||||
|
ConfigWrite = 13,
|
||||||
|
ConfigRemove = 14,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(i8)]
|
#[repr(i8)]
|
||||||
pub enum Reply {
|
pub enum Reply {
|
||||||
Success = 1,
|
Success = 1,
|
||||||
LogContent = 2,
|
LogContent = 2,
|
||||||
|
Error = 6,
|
||||||
|
ConfigData = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn read_log_level_filter(stream: &mut TcpStream) -> Result<log::LevelFilter> {
|
async fn read_log_level_filter(stream: &mut TcpStream) -> Result<log::LevelFilter> {
|
||||||
|
@ -85,7 +92,28 @@ async fn get_logger_buffer() -> LogBufferRef<'static> {
|
||||||
get_logger_buffer_pred(|_| true).await
|
get_logger_buffer_pred(|_| true).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>) -> Result<()> {
|
async fn read_key(stream: &mut TcpStream) -> Result<String> {
|
||||||
|
let len = read_i32(stream).await?;
|
||||||
|
if len <= 0 {
|
||||||
|
write_i8(stream, Reply::Error as i8).await?;
|
||||||
|
return Err(Error::UnexpectedPattern);
|
||||||
|
}
|
||||||
|
let mut buffer = Vec::with_capacity(len as usize);
|
||||||
|
for _ in 0..len {
|
||||||
|
buffer.push(0);
|
||||||
|
}
|
||||||
|
read_chunk(stream, &mut buffer).await?;
|
||||||
|
if !buffer.is_ascii() {
|
||||||
|
write_i8(stream, Reply::Error as i8).await?;
|
||||||
|
return Err(Error::UnexpectedPattern);
|
||||||
|
}
|
||||||
|
Ok(String::from_utf8(buffer).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_connection(
|
||||||
|
stream: &mut TcpStream,
|
||||||
|
pull_id: Rc<RefCell<u32>>,
|
||||||
|
cfg: Rc<Config>) -> Result<()> {
|
||||||
if !expect(&stream, b"ARTIQ management\n").await? {
|
if !expect(&stream, b"ARTIQ management\n").await? {
|
||||||
return Err(Error::UnexpectedPattern);
|
return Err(Error::UnexpectedPattern);
|
||||||
}
|
}
|
||||||
|
@ -150,19 +178,70 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>) ->
|
||||||
}
|
}
|
||||||
write_i8(stream, Reply::Success as i8).await?;
|
write_i8(stream, Reply::Success as i8).await?;
|
||||||
}
|
}
|
||||||
|
Request::ConfigRead => {
|
||||||
|
let key = read_key(stream).await?;
|
||||||
|
debug!("read key: {}", key);
|
||||||
|
let value = cfg.read(&key);
|
||||||
|
if let Ok(value) = value {
|
||||||
|
debug!("got value");
|
||||||
|
write_i8(stream, Reply::ConfigData as i8).await?;
|
||||||
|
write_chunk(stream, &value).await?;
|
||||||
|
} else {
|
||||||
|
warn!("read error: no such key");
|
||||||
|
write_i8(stream, Reply::Error as i8).await?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Request::ConfigWrite => {
|
||||||
|
let key = read_key(stream).await?;
|
||||||
|
warn!("write key: {}", key);
|
||||||
|
let len = read_i32(stream).await?;
|
||||||
|
let len = if len <= 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
len as usize
|
||||||
|
};
|
||||||
|
let mut buffer = Vec::with_capacity(len);
|
||||||
|
unsafe {
|
||||||
|
buffer.set_len(len);
|
||||||
|
}
|
||||||
|
read_chunk(stream, &mut buffer).await?;
|
||||||
|
let value = cfg.write(&key, buffer);
|
||||||
|
if value.is_ok() {
|
||||||
|
debug!("write success");
|
||||||
|
write_i8(stream, Reply::Success as i8).await?;
|
||||||
|
} else {
|
||||||
|
// this is an error because we do not expect write to fail
|
||||||
|
error!("failed to write: {:?}", value);
|
||||||
|
write_i8(stream, Reply::Error as i8).await?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Request::ConfigRemove => {
|
||||||
|
let key = read_key(stream).await?;
|
||||||
|
debug!("erase key: {}", key);
|
||||||
|
let value = cfg.remove(&key);
|
||||||
|
if value.is_ok() {
|
||||||
|
debug!("erase success");
|
||||||
|
write_i8(stream, Reply::Success as i8).await?;
|
||||||
|
} else {
|
||||||
|
warn!("erase failed");
|
||||||
|
write_i8(stream, Reply::Error as i8).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start() {
|
pub fn start(cfg: Config) {
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let pull_id = Rc::new(RefCell::new(0u32));
|
let pull_id = Rc::new(RefCell::new(0u32));
|
||||||
|
let cfg = Rc::new(cfg);
|
||||||
loop {
|
loop {
|
||||||
let mut stream = TcpStream::accept(1380, 2048, 2048).await.unwrap();
|
let mut stream = TcpStream::accept(1380, 2048, 2048).await.unwrap();
|
||||||
let pull_id = pull_id.clone();
|
let pull_id = pull_id.clone();
|
||||||
|
let cfg = cfg.clone();
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
info!("received connection");
|
info!("received connection");
|
||||||
let _ = handle_connection(&mut stream, pull_id)
|
let _ = handle_connection(&mut stream, pull_id, cfg)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| warn!("connection terminated: {:?}", e));
|
.map_err(|e| warn!("connection terminated: {:?}", e));
|
||||||
let _ = stream.flush().await;
|
let _ = stream.flush().await;
|
||||||
|
|
Loading…
Reference in New Issue