diff --git a/src/libksupport/src/kernel/api.rs b/src/libksupport/src/kernel/api.rs index 91fffc0..f778891 100644 --- a/src/libksupport/src/kernel/api.rs +++ b/src/libksupport/src/kernel/api.rs @@ -4,7 +4,7 @@ use core::{ffi::VaList, ptr, str}; use libc::{c_char, c_int, size_t}; use log::{info, warn}; -#[cfg(has_cxp_grabber)] +#[cfg(any(has_drtio, has_cxp_grabber))] use super::cxp; #[cfg(has_drtio)] use super::subkernel; @@ -129,15 +129,15 @@ pub fn resolve(required: &[u8]) -> Option { api!(subkernel_await_message = subkernel::await_message), // cxp grabber - #[cfg(has_cxp_grabber)] + #[cfg(any(has_drtio, has_cxp_grabber))] api!(cxp_download_xml_file = cxp::download_xml_file), - #[cfg(has_cxp_grabber)] + #[cfg(any(has_drtio, has_cxp_grabber))] api!(cxp_read32 = cxp::read32), - #[cfg(has_cxp_grabber)] + #[cfg(any(has_drtio, has_cxp_grabber))] api!(cxp_write32 = cxp::write32), - #[cfg(has_cxp_grabber)] + #[cfg(any(has_drtio, has_cxp_grabber))] api!(cxp_start_roi_viewer = cxp::start_roi_viewer), - #[cfg(has_cxp_grabber)] + #[cfg(any(has_drtio, has_cxp_grabber))] api!(cxp_download_roi_viewer_frame = cxp::download_roi_viewer_frame), // Double-precision floating-point arithmetic helper functions diff --git a/src/libksupport/src/kernel/cxp.rs b/src/libksupport/src/kernel/cxp.rs index e050b52..c3c2ef6 100644 --- a/src/libksupport/src/kernel/cxp.rs +++ b/src/libksupport/src/kernel/cxp.rs @@ -4,12 +4,18 @@ use core::fmt; use byteorder::{ByteOrder, NetworkEndian}; use cslice::CMutSlice; -use libboard_artiq::{cxp_ctrl::{DATA_MAXSIZE, Error as CtrlErr}, +use libboard_artiq::drtioaux_proto::CXP_PAYLOAD_MAX_SIZE; +#[cfg(has_cxp_grabber)] +use libboard_artiq::{cxp_ctrl::DATA_MAXSIZE, cxp_grabber::{camera_connected, roi_viewer_setup, with_tag}, cxp_packet::{read_bytes, read_u32, write_u32}}; use log::info; -use crate::{artiq_raise, pl::csr::cxp_grabber}; +#[cfg(has_drtio)] +use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message}; +use crate::artiq_raise; +#[cfg(has_cxp_grabber)] +use crate::pl::csr::cxp_grabber; const ROI_MAX_SIZE: usize = 4096; @@ -24,13 +30,6 @@ enum Error { BufferSizeTooSmall(usize, usize), ROISizeTooBig(usize, usize), InvalidLocalUrl(String), - CtrlPacketError(CtrlErr), -} - -impl From for Error { - fn from(value: CtrlErr) -> Error { - Error::CtrlPacketError(value) - } } impl fmt::Display for Error { @@ -58,20 +57,22 @@ impl fmt::Display for Error { &Error::InvalidLocalUrl(ref s) => { write!(f, "InvalidLocalUrl - Cannot download xml file locally from {}", s) } - &Error::CtrlPacketError(ref err) => write!(f, "{}", err), } } } -fn read_xml_url(with_tag: bool) -> Result { - let mut addr = read_u32(0x0018, with_tag)?; +fn read_xml_url(read_bytes_f: F) -> Result +where F: Fn(u32, &mut [u8]) { + let mut bytes: [u8; 4] = [0; 4]; + read_bytes_f(0x0018, &mut bytes); + let mut addr = NetworkEndian::read_u32(&bytes); let mut buffer = Vec::new(); // Strings stored in the bootstrap and manufacturer-specific registers space shall be NULL-terminated, encoded ASCII - Section 12.3.1 (CXP-001-2021) // String length is not known during runtime, grabber must read 4 bytes at a time until NULL-terminated loop { let mut bytes: [u8; 4] = [0; 4]; - read_bytes(addr, &mut bytes, with_tag)?; + read_bytes_f(addr, &mut bytes); addr += 4; for b in bytes { @@ -86,9 +87,7 @@ fn read_xml_url(with_tag: bool) -> Result { } } -fn read_xml_location(with_tag: bool) -> Result<(String, u32, u32), Error> { - let url = read_xml_url(with_tag)?; - +fn read_xml_location(url: String) -> Result<(String, u32, u32), Error> { // url example - Section 13.2.3 (CXP-001-2021) // Available on camera - "Local:MyFilename.zip;B8000;33A?SchemaVersion=1.0.0" // => ZIP file starting at address 0xB8000 in the Device with a length of 0x33A bytes @@ -107,22 +106,24 @@ fn read_xml_location(with_tag: bool) -> Result<(String, u32, u32), Error> { Err(Error::InvalidLocalUrl(url.to_string())) } -fn read_xml_file(buffer: &mut [i32], with_tag: bool) -> Result { - let (file_name, base_addr, size) = read_xml_location(with_tag)?; +fn read_xml_file(buffer: &mut [i32], read_bytes_f: F, max_read_length: usize) -> Result +where F: Fn(u32, &mut [u8]) { + let url = read_xml_url(&read_bytes_f)?; + let (file_name, base_addr, size) = read_xml_location(url)?; if buffer.len() * 4 < size as usize { - return Err(Error::BufferSizeTooSmall(size as usize, buffer.len() * 4)); + return Err(Error::BufferSizeTooSmall(size as usize, buffer.len() * 4).into()); }; info!("downloading xml file {} with {} bytes...", file_name, size); let mut v: Vec = Vec::new(); let mut addr = base_addr; let mut bytesleft = size; - let mut bytes: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE]; + let mut bytes: [u8; CXP_PAYLOAD_MAX_SIZE] = [0; CXP_PAYLOAD_MAX_SIZE]; while bytesleft > 0 { - let read_len = DATA_MAXSIZE.min(bytesleft as usize); - read_bytes(addr, &mut bytes[..read_len], with_tag)?; + let read_len = max_read_length.min(bytesleft as usize); + read_bytes_f(addr, &mut bytes[..read_len]); v.extend(&bytes[..read_len]); addr += read_len as u32; bytesleft -= read_len as u32; @@ -139,49 +140,184 @@ fn read_xml_file(buffer: &mut [i32], with_tag: bool) -> Result { Ok((size + padding) / 4) } -pub extern "C" fn download_xml_file(buffer: &mut CMutSlice) -> i32 { - if camera_connected() { - match read_xml_file(buffer.as_mut_slice(), with_tag()) { - Ok(size_read) => size_read as i32, - Err(e) => artiq_raise!("CXPError", format!("{}", e)), +#[cfg(has_drtio)] +fn kernel_channel_transact(content: Message) -> Message { + unsafe { + KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(content); + KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv() + } +} +#[cfg(has_drtio)] +fn drtio_read_bytes(dest: u8, addr: u32, bytes: &mut [u8]) { + let length = bytes.len() as u16; + if length as usize > CXP_PAYLOAD_MAX_SIZE { + panic!("CXPReadRequest length is too long") + } + + match kernel_channel_transact(Message::CXPReadRequest { + destination: dest, + address: addr, + length, + }) { + Message::CXPReadReply { length, data } => { + bytes.copy_from_slice(&data[..length as usize]); + } + Message::CXPError(err_msg) => artiq_raise!("CXPError", err_msg), + _ => unreachable!(), + }; +} + +pub extern "C" fn download_xml_file(dest: i32, buffer: &mut CMutSlice) -> i32 { + match dest { + 0 => { + #[cfg(has_cxp_grabber)] + { + if !camera_connected() { + artiq_raise!("CXPError", "Camera is not connected"); + }; + match read_xml_file( + buffer.as_mut_slice(), + |addr, bytes| { + if let Err(e) = read_bytes(addr, bytes, with_tag()) { + artiq_raise!("CXPError", format!("{}", e)); + }; + }, + DATA_MAXSIZE, + ) { + Ok(size_read) => size_read as i32, + Err(e) => artiq_raise!("CXPError", format!("{}", e)), + } + } + #[cfg(not(has_cxp_grabber))] + artiq_raise!("CXPError", "CXP Grabber is not available on destination 0"); + } + _ => { + #[cfg(has_drtio)] + { + match read_xml_file( + buffer.as_mut_slice(), + |addr, bytes| drtio_read_bytes(dest as u8, addr, bytes), + CXP_PAYLOAD_MAX_SIZE, + ) { + Ok(size_read) => size_read as i32, + Err(e) => artiq_raise!("CXPError", format!("{}", e)), + } + } + #[cfg(not(has_drtio))] + artiq_raise!("CXPError", "Destination cannot be reached"); } - } else { - artiq_raise!("CXPError", "Camera is not connected"); } } -pub extern "C" fn read32(addr: i32) -> i32 { - if camera_connected() { - match read_u32(addr as u32, with_tag()) { - Ok(result) => result as i32, - Err(e) => artiq_raise!("CXPError", format!("{}", e)), +pub extern "C" fn read32(dest: i32, addr: i32) -> i32 { + match dest { + 0 => { + #[cfg(has_cxp_grabber)] + { + if !camera_connected() { + artiq_raise!("CXPError", "Camera is not connected"); + }; + match read_u32(addr as u32, with_tag()) { + Ok(result) => result as i32, + Err(e) => artiq_raise!("CXPError", format!("{}", e)), + } + } + #[cfg(not(has_cxp_grabber))] + artiq_raise!("CXPError", "CXP Grabber is not available on destination 0"); + } + _ => { + #[cfg(has_drtio)] + { + let mut bytes: [u8; 4] = [0; 4]; + drtio_read_bytes(dest as u8, addr as u32, &mut bytes); + NetworkEndian::read_i32(&bytes) + } + #[cfg(not(has_drtio))] + artiq_raise!( + "CXPError", + format!("DRTIO is not avaiable, destination {} cannot be reached", dest) + ); } - } else { - artiq_raise!("CXPError", "Camera is not connected"); } } -pub extern "C" fn write32(addr: i32, val: i32) { - if camera_connected() { - match write_u32(addr as u32, val as u32, with_tag()) { - Ok(_) => {} - Err(e) => artiq_raise!("CXPError", format!("{}", e)), +pub extern "C" fn write32(dest: i32, addr: i32, val: i32) { + match dest { + 0 => { + #[cfg(has_cxp_grabber)] + { + if !camera_connected() { + artiq_raise!("CXPError", "Camera is not connected"); + }; + match write_u32(addr as u32, val as u32, with_tag()) { + Ok(_) => {} + Err(e) => artiq_raise!("CXPError", format!("{}", e)), + } + } + #[cfg(not(has_cxp_grabber))] + artiq_raise!("CXPError", "CXP Grabber is not available on destination 0"); + } + _ => { + #[cfg(has_drtio)] + { + match kernel_channel_transact(Message::CXPWrite32Request { + destination: dest as u8, + address: addr as u32, + value: val as u32, + }) { + Message::CXPWrite32Reply => return, + Message::CXPError(err_msg) => artiq_raise!("CXPError", err_msg), + _ => unreachable!(), + } + } + #[cfg(not(has_drtio))] + artiq_raise!( + "CXPError", + format!("DRTIO is not avaiable, destination {} cannot be reached", dest) + ); } - } else { - artiq_raise!("CXPError", "Camera is not connected"); } } -pub extern "C" fn start_roi_viewer(x0: i32, y0: i32, x1: i32, y1: i32) { +pub extern "C" fn start_roi_viewer(dest: i32, x0: i32, y0: i32, x1: i32, y1: i32) { let (width, height) = ((x1 - x0) as usize, (y1 - y0) as usize); if width * height > ROI_MAX_SIZE || height > ROI_MAX_SIZE / 4 { artiq_raise!("CXPError", format!("{}", Error::ROISizeTooBig(width, height))); - } else { - roi_viewer_setup(x0 as u16, y0 as u16, x1 as u16, y1 as u16); + } + + match dest { + 0 => { + #[cfg(has_cxp_grabber)] + { + roi_viewer_setup(x0 as u16, y0 as u16, x1 as u16, y1 as u16) + } + #[cfg(not(has_cxp_grabber))] + artiq_raise!("CXPError", "CXP Grabber is not available on destination 0"); + } + _ => { + #[cfg(has_drtio)] + { + match kernel_channel_transact(Message::CXPROIViewerSetupRequest { + destination: dest as u8, + x0: x0 as u16, + y0: y0 as u16, + x1: x1 as u16, + y1: y1 as u16, + }) { + Message::CXPROIViewerSetupReply => return, + _ => unreachable!(), + } + } + #[cfg(not(has_drtio))] + artiq_raise!( + "CXPError", + format!("DRTIO is not avaiable, destination {} cannot be reached", dest) + ); + } } } -pub extern "C" fn download_roi_viewer_frame(buffer: &mut CMutSlice) -> ROIViewerFrame { +pub extern "C" fn download_roi_viewer_frame(dest: i32, buffer: &mut CMutSlice) -> ROIViewerFrame { if buffer.len() * 4 < ROI_MAX_SIZE { // each pixel is 16 bits artiq_raise!( @@ -191,30 +327,71 @@ pub extern "C" fn download_roi_viewer_frame(buffer: &mut CMutSlice) -> ROIV }; let buf = buffer.as_mut_slice(); - unsafe { - while cxp_grabber::roi_viewer_ready_read() == 0 {} - cxp_grabber::roi_viewer_ready_write(1); + let (width, height, pixel_code); + match dest { + 0 => { + #[cfg(has_cxp_grabber)] + unsafe { + while cxp_grabber::roi_viewer_ready_read() == 0 {} + let mut i = 0; + while cxp_grabber::roi_viewer_fifo_stb_read() == 1 { + buf[i] = cxp_grabber::roi_viewer_fifo_data_read() as i64; + i += 1; + cxp_grabber::roi_viewer_fifo_ack_write(1); + } + cxp_grabber::roi_viewer_ready_write(1); - let mut i = 0; - while cxp_grabber::roi_viewer_fifo_stb_read() == 1 { - buf[i] = cxp_grabber::roi_viewer_fifo_data_read() as i64; - i += 1; - cxp_grabber::roi_viewer_fifo_ack_write(1); + width = cxp_grabber::roi_viewer_x1_read() - cxp_grabber::roi_viewer_x0_read(); + height = cxp_grabber::roi_viewer_y1_read() - cxp_grabber::roi_viewer_y0_read(); + pixel_code = cxp_grabber::stream_decoder_pixel_format_code_read(); + } + #[cfg(not(has_cxp_grabber))] + artiq_raise!("CXPError", "CXP Grabber is not available on destination 0"); } - let width = (cxp_grabber::roi_viewer_x1_read() - cxp_grabber::roi_viewer_x0_read()) as i32; - let height = (cxp_grabber::roi_viewer_y1_read() - cxp_grabber::roi_viewer_y0_read()) as i32; - let pixel_width = match cxp_grabber::stream_decoder_pixel_format_code_read() { - 0x0101 => 8, - 0x0102 => 10, - 0x0103 => 12, - 0x0104 => 14, - 0x0105 => 16, - _ => artiq_raise!("CXPError", "UnsupportedPixelFormat"), - }; - ROIViewerFrame { - width, - height, - pixel_width, + _ => { + #[cfg(has_drtio)] + { + let mut i = 0; + loop { + match kernel_channel_transact(Message::CXPROIViewerDataRequest { + destination: dest as u8, + }) { + Message::CXPROIVIewerPixelDataReply { length, data } => { + for d in &data[..length as usize] { + buf[i] = *d as i64; + i += 1; + } + } + Message::CXPROIVIewerFrameDataReply { + width: w, + height: h, + pixel_code: p, + } => { + (width, height, pixel_code) = (w, h, p); + break; + } + _ => unreachable!(), + } + } + } + #[cfg(not(has_drtio))] + artiq_raise!( + "CXPError", + format!("DRTIO is not avaiable, destination {} cannot be reached", dest) + ); } + }; + let pixel_width = match pixel_code { + 0x0101 => 8, + 0x0102 => 10, + 0x0103 => 12, + 0x0104 => 14, + 0x0105 => 16, + _ => artiq_raise!("CXPError", "UnsupportedPixelFormat"), + }; + ROIViewerFrame { + width: width as i32, + height: height as i32, + pixel_width: pixel_width as i32, } }