1use {
8 ocsd::client::{base_address, OcsdContext},
9 ocsd::{
10 Celsius, MemoryMapped, OcsdDevice, OcsdDeviceHeader, OcsdSensor, OcsdSensorLocation,
11 OcsdSensorStatus, OcsdSensorType,
12 },
13 serde::{Deserialize, Serialize},
14 std::fs::OpenOptions,
15 std::sync::atomic::{self, AtomicBool, AtomicU16},
16 std::sync::Arc,
17 std::{cmp::min, time::Duration},
18};
19
20fn print_struct_bytes(bytes: &Vec<u8>) {
21 let num_chunks = bytes.len() / 8;
22
23 for chunk_idx in 0..num_chunks {
24 let max_idx = min((chunk_idx + 1) * 8, bytes.len());
25 for b in &bytes[chunk_idx * 8..max_idx] {
26 print!("{b:02x} ");
27 }
28 if chunk_idx % 2 == 0 {
29 print!(" ");
30 } else {
31 println!();
32 }
33 }
34}
35
36fn make_device(count: u16) -> OcsdDevice {
37 let header = OcsdDeviceHeader {
38 version: ocsd::DeviceVersion::Version1,
39 pci_bus: 0x04,
40 pci_device: 0x00,
41 flags_caps: 0x00000010,
42 };
43 println!("Device 2 header:");
44 print_struct_bytes(&header.to_bytes());
45
46 let bus: u8 = 0x04;
47
48 let sensor = OcsdSensor {
49 sensor_type: OcsdSensorType::Thermal,
50 sensor_location: OcsdSensorLocation::InternalToAsic,
51 configuration: 0x0000,
52 status: OcsdSensorStatus::WithChecksum
53 | OcsdSensorStatus::Present
54 | OcsdSensorStatus::NotFailed,
55 max_continuous_threshold: Celsius::new(80).unwrap(),
56 caution_threshold: Celsius::new(90).unwrap(),
57 reading: Celsius::new(40).unwrap(),
58 update_count: count,
59 bus: Some(bus),
60 };
61
62 println!("Device 2 Sensor 0:");
63 print_struct_bytes(&sensor.to_bytes());
64
65 OcsdDevice {
66 header,
67 sensors: [sensor, Default::default(), Default::default()],
68 }
69}
70
71#[derive(Serialize, Deserialize, Debug)]
72struct AppState {
73 count: u16,
74}
75
76fn main() {
77 match OcsdContext::new(base_address::ML350_GEN9) {
78 Ok(mut context) => {
79 let mut header = context.read_header();
80 println!("Header data before write:");
81 print_struct_bytes(&header.to_bytes());
82
83 header.buffers_in_use = 3;
85
86 println!("Ready to write:");
87 print_struct_bytes(&header.to_bytes());
88
89 context.write_header(&header);
90
91 let app_state: AppState = match OpenOptions::new().read(true).open("state.json") {
92 Ok(reader) => match serde_json::from_reader(reader) {
93 Ok(app_state) => app_state,
94 Err(err) => {
95 println!("Couldn't load state: {:?}", err);
96 println!("Using default.");
97 AppState { count: 0 }
98 }
99 },
100 Err(err) => {
101 println!("Couldn't open state file: {:?}", err);
102 println!("Using default.");
103 AppState { count: 0 }
104 }
105 };
106 let count = Arc::new(AtomicU16::new(app_state.count));
107
108 let should_exit = Arc::new(AtomicBool::new(false));
109 let mut file = OpenOptions::new()
110 .create(true)
111 .truncate(true) .write(true)
113 .open("state.json")
114 .unwrap();
115
116 let should_exit_clone = should_exit.clone();
117 let count_clone = count.clone();
118 let _ = ctrlc::set_handler(move || {
119 serde_json::to_writer(
120 &mut file,
121 &AppState {
122 count: (*count_clone).load(atomic::Ordering::Relaxed),
123 },
124 )
125 .unwrap();
126 should_exit_clone.store(true, atomic::Ordering::Relaxed);
127 });
128
129 loop {
130 let device = make_device((*count).load(atomic::Ordering::Relaxed));
131 context.device_mappings[2].write(&device);
132
133 std::thread::sleep(Duration::from_millis(1000));
134 (*count).fetch_add(1, atomic::Ordering::Relaxed);
135
136 if should_exit.load(atomic::Ordering::Relaxed) {
137 break;
138 };
139 }
140 }
141 Err(_) => {
142 println!(
143 "Unable to open OCSD header context in memory. Do you have access to /dev/mem?"
144 )
145 }
146 }
147}