liftof_rb/
memory.rs

1//! On-board memory management for readoutboards
2//! 
3//! The DRS4 is able to map its registers and the 
4//! data buffer directly into OS memory.
5//!
6//! memory locations for the control 
7//! registers
8//! /dev/uio0 - DRS4 control
9//! /dev/uio1 - buffer 1 for blobs
10//! /dev/uio2 - buffer 2 for blobs
11
12extern crate memmap;
13
14use std::error::Error;
15use std::fs::File;
16use std::fmt;
17
18use memmap::{Mmap,
19             MmapMut};
20
21use std::ptr;
22
23//use tof_dataclasses::io::RBEventMemoryStreamer;
24use gondola_core::io::RBEventMemoryStreamer;
25
26pub const UIO0 : &'static str = "/dev/uio0";
27pub const UIO1 : &'static str = "/dev/uio1";
28pub const UIO2 : &'static str = "/dev/uio2";
29
30/// Data buffer related constants
31/// The data buffer is /dev/uio1 
32/// and /dev/uio2 are internally
33/// a single buffer but with 2 halves.
34/// 
35/// Interestingly, there is a discrepancy 
36/// between the dma_reset when it writes
37/// 68176064
38pub const DATABUF_TOTAL_SIZE : usize = 66524928;
39pub const EVENT_SIZE         : usize = 18530; 
40//pub const UIO1_MIN_OCCUPANCY : u32 = 68176064;
41pub const UIO1_MIN_OCCUPANCY : u32 = 68157440;
42pub const UIO2_MIN_OCCUPANCY : u32 = 135266304;
43
44pub const UIO1_MAX_OCCUPANCY : u32 = 117089408;
45pub const UIO2_MAX_OCCUPANCY : u32 = 201788800;
46
47/// The size of a 32bit unsigned int in byte
48/// (all words in registers are u32)
49pub const SIZEOF_U32 : usize = 4;
50
51
52#[derive(Debug, Copy, Clone)]
53pub enum RegisterError {
54  RegisterTimeOut,
55  MMapFail,
56  Unknown,
57}
58
59impl fmt::Display for RegisterError {
60  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61    let etype : String;
62    match self {
63      RegisterError::RegisterTimeOut => {
64        etype = String::from("RegisterTimeOut");
65      },
66      RegisterError::Unknown => {
67        etype = String::from("Unknown");
68      },
69      _ => {
70        etype = String::from("not defined");
71      }
72    }
73    write!(f, "<RegisterError: {}>", etype)
74  }
75}
76
77impl Error for RegisterError {
78}
79
80
81///! There are 2 data buffers, commonly 
82///  denoted as "A" and "B".
83///  A -> /dev/uio1
84///  B -> /dev/uio2
85#[derive(Debug, Copy, Clone)]
86pub enum RamBuffer {
87  A,
88  B,
89  //Both
90}
91
92impl RamBuffer {
93  pub fn invert(&self) -> RamBuffer {
94    match self {
95      RamBuffer::A => {return RamBuffer::B},
96      RamBuffer::B => {return RamBuffer::A}
97    }
98  }
99}
100
101/// Get a size which accomodates nevents
102///
103/// This means if the given size is too small
104/// make sure that at least the whole next
105/// event "fits in"
106pub fn size_in_events(size : usize) -> usize {
107  size/EVENT_SIZE
108}
109
110/// Allow READ access to the memory registers at /dev/uio**
111///
112/// Remember we have a 32bit system
113///
114///
115pub fn map_physical_mem_read(addr_space : &str,
116                             addr: u32,
117                             len: usize) -> Result<Mmap, Box<dyn Error>> {
118  let m = unsafe {
119    memmap::MmapOptions::new()
120      .offset(addr as u64)
121      .len(len)
122      .map(&File::open(addr_space)?)?
123    };
124  Ok(m)
125}
126
127/// Allow WRITE access to the memory registers at /dev/uio0
128/// 
129/// Write control registers.
130/// Remember we have a 32bit system
131///
132/// # Arguments
133///
134/// addr : The memory address (address8) the register
135///        is mapped to.
136///
137///
138pub fn map_physical_mem_write(addr_space : &str,
139                              addr       : u32,
140                              len        : usize)
141  -> Result<MmapMut, Box<dyn Error>> {
142  let m = unsafe {
143    memmap::MmapOptions::new()
144      .offset(addr as u64)
145      .len(len)
146      .map_mut(&File::options()
147        .read(true)
148        .write(true)
149        .open(addr_space)?)?
150    };
151  Ok(m)
152}
153
154///! Get a single value from a 32bit (1 word) register
155///  This reads ONLY control registers 
156///  (in /dev/uio0)
157///  
158///  # Arguments:
159///
160///  * addr : The addr8 of the register 
161///           in /dev/uio0
162/// 
163pub fn read_control_reg(addr : u32) 
164  -> Result<u32, RegisterError> 
165  where
166    u32: std::fmt::LowerHex, {
167  
168  //let sz = std::mem::size_of::<u32>();
169  let m = match map_physical_mem_read(UIO0, addr, SIZEOF_U32) {
170    Ok(m) => m,
171    Err(err) => {
172      error!("Failed to mmap: {:?}", err);
173      return Err(RegisterError::MMapFail);
174    }
175  };
176  let p = m.as_ptr() as *const u32;
177  let value : u32;
178  unsafe {
179    value = std::ptr::read_volatile(p.offset(0));
180  }
181  Ok(value)
182}
183
184/// 
185pub fn write_control_reg(addr       : u32,
186                         data       : u32) 
187  -> Result<(), RegisterError> 
188  where
189    u32: std::fmt::LowerHex, {
190  
191  trace!("Attempting to write {data} at addr {addr}");
192  //let sz = std::mem::size_of::<u32>();
193  let m = match map_physical_mem_write(UIO0,addr,SIZEOF_U32) {
194    Ok(m) => m,
195    Err(err) => {
196      warn!("[write_control_reg] Failed to mmap! {:?}", err);
197      return Err(RegisterError::MMapFail);
198    }
199  };
200  let p = m.as_ptr() as *mut u32;
201  unsafe {
202    std::ptr::write_volatile(p.offset(0), data);
203  }
204  Ok(())
205}
206
207
208///  Read one of the data buffers and return a bytestream 
209///  from the given address with the length in events.
210///  
211///  # Arguments
212///
213///  * which : Select data buffer to read 
214///  * size  : in bytes
215///
216pub fn read_data_buffer(which : &RamBuffer, 
217                        size  : usize)
218    -> Result<Vec::<u8>, RegisterError> 
219  where
220    u32: std::fmt::LowerHex, {
221
222  let addr_space;
223  match which {
224    RamBuffer::A => addr_space = UIO1,
225    RamBuffer::B => addr_space = UIO2
226  }
227  //let blobsize = BlobData::SERIALIZED_SIZE;
228  //let vec_size = blobsize*len;
229  // FIXME - allocate the vector elsewhere and 
230  // pass it by reference
231  let mut bytestream = Vec::<u8>::with_capacity(size);
232  let m = match map_physical_mem_read(addr_space, 0x0, size) {
233  //let mut m = match map_physical_mem_write(addr_space, 0x0, size) {
234    Ok(m) => m,
235    Err(err) => {
236      //let error = RegisterError {};
237      warn!("Failed to mmap! {:?}", err);
238      return Err(RegisterError::MMapFail);
239    }
240  };
241 
242  //ptr::slice_from_raw_parts(raw_pointer, 3) 
243
244  let p = m.as_ptr() as *const u8;
245  //let p = m.as_mut_ptr() as *mut u8;
246  let slice = ptr::slice_from_raw_parts(p, size);
247  unsafe {
248    //bytestream  = Vec::<u8>::from_raw_parts(p, size, size);
249    bytestream.extend_from_slice(&*slice); 
250  }
251  Ok(bytestream)
252}
253
254///  Read a data buffer directly into a RBEventMemory streamer,
255///  avoiding the detour over vector.extend (which performs 
256///  clones), so this *should* actually be much more efficient.
257///
258///  # Arguments
259///     * which    : Select data buffer to read 
260///     * size     : in bytes
261///     * streamer : an instance of a RBEventMemoryStreamer
262pub fn read_buffer_into_streamer(which    : &RamBuffer, 
263                                 size     : usize,
264                                 streamer : &mut RBEventMemoryStreamer)
265    -> Result<(), RegisterError> 
266  where
267    u32: std::fmt::LowerHex, {
268
269  let addr_space;
270  match which {
271    RamBuffer::A => addr_space = UIO1,
272    RamBuffer::B => addr_space = UIO2
273  }
274  let m = match map_physical_mem_read(addr_space, 0x0, size) {
275  //let mut m = match map_physical_mem_write(addr_space, 0x0, size) {
276    Ok(m) => m,
277    Err(err) => {
278      warn!("Failed to mmap: {:?}", err);
279      return Err(RegisterError::MMapFail);
280    }
281  };
282  let p = m.as_ptr() as *const u8;
283  //println!("Trying to get slice from raw parts");
284  let slice = ptr::slice_from_raw_parts(p, size);
285  //let mut bytestream : Vec::<u8>;
286  let mut bytestream = Vec::<u8>::with_capacity(200000);
287  println!("Trying to get bytestream from raw parts!");
288  unsafe {
289    //bytestream = Vec::from_raw_parts(p as *mut u8, size, size);
290    bytestream.extend_from_slice(&*slice); 
291  }
292  streamer.consume(&mut bytestream);
293  println!(".. done!");
294  //Ok(bytestream)
295  Ok(())
296}
297
298