git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
218 lines
5.6 KiB
Rust
218 lines
5.6 KiB
Rust
//! Event Types and Trait Definitions
|
||
//!
|
||
//! Implements DVS (Dynamic Vision Sensor) events and sparse event surfaces.
|
||
|
||
use std::sync::atomic::{AtomicU64, Ordering};
|
||
|
||
/// Core event trait for timestamped event streams
|
||
pub trait Event: Send + Sync {
|
||
/// Get event timestamp (microseconds)
|
||
fn timestamp(&self) -> u64;
|
||
|
||
/// Get source identifier (e.g., pixel coordinate hash)
|
||
fn source_id(&self) -> u16;
|
||
|
||
/// Get event payload/data
|
||
fn payload(&self) -> u32;
|
||
}
|
||
|
||
/// Dynamic Vision Sensor event
|
||
///
|
||
/// Represents a single event from a DVS camera or general event source.
|
||
/// Typically 10-1000× more efficient than frame-based data.
|
||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||
pub struct DVSEvent {
|
||
/// Event timestamp in microseconds
|
||
pub timestamp: u64,
|
||
|
||
/// Source identifier (e.g., pixel index or sensor ID)
|
||
pub source_id: u16,
|
||
|
||
/// Payload data (application-specific)
|
||
pub payload_id: u32,
|
||
|
||
/// Polarity (on/off, increase/decrease)
|
||
pub polarity: bool,
|
||
|
||
/// Optional confidence score
|
||
pub confidence: Option<f32>,
|
||
}
|
||
|
||
impl Event for DVSEvent {
|
||
#[inline]
|
||
fn timestamp(&self) -> u64 {
|
||
self.timestamp
|
||
}
|
||
|
||
#[inline]
|
||
fn source_id(&self) -> u16 {
|
||
self.source_id
|
||
}
|
||
|
||
#[inline]
|
||
fn payload(&self) -> u32 {
|
||
self.payload_id
|
||
}
|
||
}
|
||
|
||
impl DVSEvent {
|
||
/// Create a new DVS event
|
||
pub fn new(timestamp: u64, source_id: u16, payload_id: u32, polarity: bool) -> Self {
|
||
Self {
|
||
timestamp,
|
||
source_id,
|
||
payload_id,
|
||
polarity,
|
||
confidence: None,
|
||
}
|
||
}
|
||
|
||
/// Create event with confidence score
|
||
pub fn with_confidence(mut self, confidence: f32) -> Self {
|
||
self.confidence = Some(confidence);
|
||
self
|
||
}
|
||
}
|
||
|
||
/// Sparse event surface for tracking last event per source
|
||
///
|
||
/// Efficiently tracks active events across a 2D surface (e.g., DVS camera pixels)
|
||
/// using atomic operations for lock-free updates.
|
||
pub struct EventSurface {
|
||
surface: Vec<AtomicU64>,
|
||
width: usize,
|
||
height: usize,
|
||
}
|
||
|
||
impl EventSurface {
|
||
/// Create new event surface
|
||
pub fn new(width: usize, height: usize) -> Self {
|
||
let size = width * height;
|
||
let mut surface = Vec::with_capacity(size);
|
||
for _ in 0..size {
|
||
surface.push(AtomicU64::new(0));
|
||
}
|
||
|
||
Self {
|
||
surface,
|
||
width,
|
||
height,
|
||
}
|
||
}
|
||
|
||
/// Update surface with new event
|
||
#[inline]
|
||
pub fn update(&self, event: &DVSEvent) {
|
||
let idx = event.source_id as usize;
|
||
if idx < self.surface.len() {
|
||
self.surface[idx].store(event.timestamp, Ordering::Relaxed);
|
||
}
|
||
}
|
||
|
||
/// Get all events that occurred since timestamp
|
||
pub fn get_active_events(&self, since: u64) -> Vec<(usize, usize, u64)> {
|
||
let mut active = Vec::new();
|
||
|
||
for (idx, timestamp_atom) in self.surface.iter().enumerate() {
|
||
let timestamp = timestamp_atom.load(Ordering::Relaxed);
|
||
if timestamp > since {
|
||
let x = idx % self.width;
|
||
let y = idx / self.width;
|
||
active.push((x, y, timestamp));
|
||
}
|
||
}
|
||
|
||
active
|
||
}
|
||
|
||
/// Get timestamp at specific coordinate
|
||
pub fn get_timestamp(&self, x: usize, y: usize) -> Option<u64> {
|
||
if x < self.width && y < self.height {
|
||
let idx = y * self.width + x;
|
||
Some(self.surface[idx].load(Ordering::Relaxed))
|
||
} else {
|
||
None
|
||
}
|
||
}
|
||
|
||
/// Clear all events
|
||
pub fn clear(&self) {
|
||
for atom in &self.surface {
|
||
atom.store(0, Ordering::Relaxed);
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_dvs_event_creation() {
|
||
let event = DVSEvent::new(1000, 42, 123, true);
|
||
assert_eq!(event.timestamp(), 1000);
|
||
assert_eq!(event.source_id(), 42);
|
||
assert_eq!(event.payload(), 123);
|
||
assert_eq!(event.polarity, true);
|
||
assert_eq!(event.confidence, None);
|
||
}
|
||
|
||
#[test]
|
||
fn test_dvs_event_with_confidence() {
|
||
let event = DVSEvent::new(1000, 42, 123, false).with_confidence(0.95);
|
||
|
||
assert_eq!(event.confidence, Some(0.95));
|
||
}
|
||
|
||
#[test]
|
||
fn test_event_surface_update() {
|
||
let surface = EventSurface::new(640, 480);
|
||
|
||
let event1 = DVSEvent::new(1000, 0, 0, true);
|
||
let event2 = DVSEvent::new(2000, 100, 0, false);
|
||
|
||
surface.update(&event1);
|
||
surface.update(&event2);
|
||
|
||
assert_eq!(surface.get_timestamp(0, 0), Some(1000));
|
||
assert_eq!(surface.get_timestamp(100, 0), Some(2000));
|
||
}
|
||
|
||
#[test]
|
||
fn test_event_surface_active_events() {
|
||
let surface = EventSurface::new(10, 10);
|
||
|
||
// Add events at different times
|
||
for i in 0..5 {
|
||
let event = DVSEvent::new(1000 + i * 100, i as u16, 0, true);
|
||
surface.update(&event);
|
||
}
|
||
|
||
// Query events since timestamp 1200
|
||
let active = surface.get_active_events(1200);
|
||
assert_eq!(active.len(), 2); // Events at 1300 and 1400
|
||
}
|
||
|
||
#[test]
|
||
fn test_event_surface_clear() {
|
||
let surface = EventSurface::new(10, 10);
|
||
|
||
let event = DVSEvent::new(1000, 5, 0, true);
|
||
surface.update(&event);
|
||
|
||
assert_eq!(surface.get_timestamp(5, 0), Some(1000));
|
||
|
||
surface.clear();
|
||
assert_eq!(surface.get_timestamp(5, 0), Some(0));
|
||
}
|
||
|
||
#[test]
|
||
fn test_event_surface_bounds() {
|
||
let surface = EventSurface::new(10, 10);
|
||
|
||
// Out of bounds should return None
|
||
assert_eq!(surface.get_timestamp(10, 0), None);
|
||
assert_eq!(surface.get_timestamp(0, 10), None);
|
||
}
|
||
}
|