create_custom_atoms/
create_custom_atoms.rs

1//  _  _       _             _  _
2// | || |  ___| |_ _ __ ___ | || |
3// | || |_/ __| __| '_ ` _ \| || |_
4// |__   _\__ | |_| | | | | |__   _|
5//   |_| |___/\__|_|_|_| |_|  |_|
6//! # ehatrom — EEPROM HAT library for Raspberry Pi HATs
7//! - [Documentation (docs.rs)](https://docs.rs/ehatrom)
8//! - [GitHub](https://github.com/4stm4/ehatrom)
9//!
10use ehatrom::*;
11
12fn main() {
13    println!("📝 Creating EEPROM with custom atoms...");
14
15    // Create a list to hold our custom atoms
16    let mut custom_atoms = Vec::new();
17
18    // Create vendor info atom
19    let vendor_atom = VendorInfoAtom::new(
20        0x4143, // vendor_id "AC" (example)
21        0x0001, // product_id
22        2,      // product_ver
23        "ACME Custom HATs",
24        "SensorBoard Plus",
25        [
26            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD,
27            0xEE, 0xFF,
28        ], // UUID
29    );
30
31    // Create GPIO map for bank 0 - more complex pin assignments
32    let mut pins = [0u8; 28];
33    pins[4] = 0x01; // GPIO4 - Input
34    pins[17] = 0x02; // GPIO17 - Output
35    pins[18] = 0x02; // GPIO18 - Output
36    pins[22] = 0x01; // GPIO22 - Input
37    pins[23] = 0x01; // GPIO23 - Input
38    pins[24] = 0x02; // GPIO24 - Output
39    pins[25] = 0x02; // GPIO25 - Output
40    let gpio_atom = GpioMapAtom {
41        flags: 0x0000,
42        pins,
43    };
44
45    // Custom atom 1: Configuration string
46    let config_str = "MODE=SENSORS,INTERVAL=250,UNITS=METRIC".to_string();
47    custom_atoms.push((0x81, config_str.into_bytes())); // Using tuple format (type, data)
48
49    // Custom atom 2: Sensor calibration data (example of binary data)
50    let mut sensor_cal = Vec::new();
51    // Temperature offset and gain
52    sensor_cal.extend_from_slice(&((-2.5f32).to_be_bytes()));
53    sensor_cal.extend_from_slice(&(1.03f32.to_be_bytes()));
54    // Humidity offset and gain
55    sensor_cal.extend_from_slice(&(1.2f32.to_be_bytes()));
56    sensor_cal.extend_from_slice(&(0.98f32.to_be_bytes()));
57    // Pressure offset and gain
58    sensor_cal.extend_from_slice(&(15.0f32.to_be_bytes()));
59    sensor_cal.extend_from_slice(&(1.0f32.to_be_bytes()));
60    custom_atoms.push((0x82, sensor_cal)); // Using tuple format (type, data)
61
62    // Custom atom 3: Hardware version info as string
63    let hw_info = format!(
64        "HW_VERSION={}.{}.{},PCB_REV=C,ASSEMBLY_DATE=2024-12-20",
65        env!("CARGO_PKG_VERSION_MAJOR"),
66        env!("CARGO_PKG_VERSION_MINOR"),
67        env!("CARGO_PKG_VERSION_PATCH")
68    );
69    custom_atoms.push((0x83, hw_info.into_bytes())); // Using tuple format (type, data)
70
71    // Custom atom 4: Binary data (e.g., lookup table)
72    let mut lookup_table = Vec::new();
73    for i in 0..32 {
74        lookup_table.push((i * i) as u8); // Simple quadratic lookup table
75    }
76    custom_atoms.push((0x84, lookup_table)); // Using tuple format (type, data)
77
78    // Create EEPROM structure
79    #[cfg(feature = "alloc")]
80    let mut eeprom = Eeprom {
81        header: EepromHeader::new(),
82        vendor_info: vendor_atom,
83        gpio_map_bank0: gpio_atom,
84        dt_blob: None,
85        gpio_map_bank1: None,
86        custom_atoms,
87    };
88
89    #[cfg(not(feature = "alloc"))]
90    // Для no_std режима создаем статические данные
91    let mut eeprom = {
92        // Для no_std нам нужны статические данные, это просто заглушка
93        static CUSTOM_ATOMS: [(u8, &[u8]); 0] = [];
94        Eeprom {
95            header: EepromHeader::new(),
96            vendor_info: vendor_atom,
97            gpio_map_bank0: gpio_atom,
98            dt_blob: None,
99            gpio_map_bank1: None,
100            custom_atoms: &CUSTOM_ATOMS,
101        }
102    };
103
104    // Update header with correct counts and length
105    eeprom.update_header();
106
107    // Serialize with CRC
108    #[cfg(feature = "alloc")]
109    let serialized = eeprom.serialize_with_crc();
110
111    #[cfg(not(feature = "alloc"))]
112    // Создаем буфер и вектор для копирования данных
113    let serialized = {
114        let mut buffer = [0u8; 1024]; // Буфер достаточного размера
115        let size = eeprom
116            .serialize_with_crc_to_slice(&mut buffer)
117            .expect("Failed to serialize EEPROM");
118        // Копируем данные в новый вектор
119        buffer[..size].to_vec()
120    };
121
122    let filename = "tests/data/custom_atoms.bin";
123
124    // Create output directory if it doesn't exist
125    if std::fs::metadata("tests/data").is_err() {
126        std::fs::create_dir_all("tests/data").expect("Failed to create tests/data directory");
127    }
128
129    std::fs::write(filename, &serialized).expect("Failed to write custom atoms EEPROM file");
130
131    println!("✅ Created {} ({} bytes)", filename, serialized.len());
132    println!("📊 EEPROM contains:");
133    println!("   • Standard HAT header");
134    println!("   • Vendor info atom");
135    println!("   • GPIO map atom");
136    println!("   • 4 custom atoms:");
137    println!("     - 0x81: Configuration string");
138    println!("     - 0x82: Sensor calibration data");
139    println!("     - 0x83: Hardware version info");
140    println!("     - 0x84: Lookup table (32 bytes)");
141
142    // Verify the created file
143    if Eeprom::verify_crc(&serialized) {
144        println!("✅ CRC32 verification passed");
145    } else {
146        println!("❌ CRC32 verification failed");
147    }
148
149    println!("💡 This demonstrates how to embed custom application-specific data in HAT EEPROM");
150}