1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
// _ _ _ _ _
// | || | ___| |_ _ __ ___ | || |
// | || |_/ __| __| '_ ` _ \| || |_
// |__ _\__ | |_| | | | | |__ _|
// |_| |___/\__|_|_|_| |_| |_|
//! # ehatrom — EEPROM HAT library for Raspberry Pi HATs
//! - [Documentation (docs.rs)](https://docs.rs/ehatrom)
//! - [GitHub](https://github.com/4stm4/ehatrom)
//!
fn main() {
// Import I2C functions only on Linux
#[cfg(not(all(target_os = "linux", feature = "linux")))]
use ehatrom::Eeprom;
#[cfg(all(target_os = "linux", feature = "linux"))]
use ehatrom::{Eeprom, read_from_eeprom_i2c, write_to_eeprom_i2c};
use std::env;
use std::process;
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!("Usage: ehatrom <read|write|show|detect> [options]");
eprintln!("Commands:");
eprintln!(
" read [i2c-dev] <output.bin> Read HAT EEPROM via I2C and save to file"
);
eprintln!(
" write [i2c-dev] <input.bin> Write HAT EEPROM from file to I2C device"
);
eprintln!(" show <input.bin> Show parsed EEPROM info from file");
eprintln!(
" detect [i2c-dev] Auto-detect HAT EEPROM on specific device"
);
eprintln!(" detect --all Scan all I2C devices for HAT EEPROM");
eprintln!("Notes:");
eprintln!(" HAT EEPROM always uses address 0x50 (automatic)");
eprintln!(" Default I2C device is /dev/i2c-0 (HAT standard)");
eprintln!(" Default buffer size is 32KB, customize with EHATROM_BUFFER_SIZE env variable");
eprintln!("Examples:");
eprintln!(" sudo ehatrom read hat_data.bin # Read from /dev/i2c-0 to file");
eprintln!(" sudo ehatrom write hat_data.bin # Write from file to /dev/i2c-0");
eprintln!(" sudo ehatrom read /dev/i2c-1 hat.bin # Read from specific I2C device");
eprintln!(" EHATROM_BUFFER_SIZE=1048576 sudo ehatrom read big.bin # Read 1MB EEPROM");
eprintln!(" sudo ehatrom detect # Scan /dev/i2c-0 (HAT standard)");
eprintln!(" sudo ehatrom detect --all # Scan all I2C devices");
eprintln!(" sudo ehatrom detect /dev/i2c-1 # Scan specific device");
process::exit(1);
}
match args[1].as_str() {
"read" => {
// ehatrom read [i2c-dev] <output.bin>
if args.len() < 3 || args.len() > 4 {
eprintln!("Usage: ehatrom read [i2c-dev] <output.bin>");
eprintln!(" Default I2C device: /dev/i2c-0");
eprintln!(" HAT EEPROM address: 0x50 (automatic)");
process::exit(1);
}
#[cfg(all(target_os = "linux", feature = "linux"))]
{
let (dev, output_file) = if args.len() == 3 {
// ehatrom read <output.bin>
("/dev/i2c-0", &args[2])
} else {
// ehatrom read <i2c-dev> <output.bin>
(args[2].as_str(), &args[3])
};
let addr = 0x50u16; // HAT EEPROM fixed address
// Support reading large EEPROMs - default buffer is 32 KB
// You can override the size with the EHATROM_BUFFER_SIZE environment variable
let buf_size = match env::var("EHATROM_BUFFER_SIZE") {
Ok(size_str) => match size_str.parse::<usize>() {
Ok(size) => {
if size < 1024 {
println!("Warning: Buffer size too small, using minimum 1KB");
1024
} else {
println!("Using custom buffer size: {} bytes", size);
size
}
}
Err(_) => {
println!("Warning: Failed to parse EHATROM_BUFFER_SIZE, using 32KB");
32 * 1024
}
},
Err(_) => 32 * 1024, // 32 KB by default
};
let buf = vec![0u8; buf_size];
let mut buf = buf; // for compatibility with function signature
match read_from_eeprom_i2c(&mut buf, dev, addr, 0) {
Ok(()) => {
if let Err(e) = std::fs::write(output_file, &buf) {
eprintln!("Failed to write output: {e}");
process::exit(1);
}
println!(
"HAT EEPROM read from {} (0x50) and saved to {} ({} bytes buffer used)",
dev, output_file, buf_size
);
println!(
"Note: Set EHATROM_BUFFER_SIZE env variable if you need a different buffer size"
);
}
Err(e) => {
eprintln!("Read error: {e}");
process::exit(1);
}
}
}
#[cfg(not(feature = "linux"))]
{
eprintln!("I2C read requires --features=linux");
eprintln!("Please rebuild with: cargo build --features linux");
process::exit(1);
}
}
"write" => {
// ehatrom write [i2c-dev] <input.bin>
if args.len() < 3 || args.len() > 4 {
eprintln!("Usage: ehatrom write [i2c-dev] <input.bin>");
eprintln!(" Default I2C device: /dev/i2c-0");
eprintln!(" HAT EEPROM address: 0x50 (automatic)");
process::exit(1);
}
#[cfg(all(target_os = "linux", feature = "linux"))]
{
let (dev, input_file) = if args.len() == 3 {
// ehatrom write <input.bin>
("/dev/i2c-0", &args[2])
} else {
// ehatrom write <i2c-dev> <input.bin>
(args[2].as_str(), &args[3])
};
let addr = 0x50u16; // HAT EEPROM fixed address
let data = match std::fs::read(input_file) {
Ok(d) => d,
Err(e) => {
eprintln!("Failed to read input: {e}");
process::exit(1);
}
};
match write_to_eeprom_i2c(&data, dev, addr) {
Ok(()) => {
println!("HAT EEPROM written from {} to {} (0x50)", input_file, dev);
}
Err(e) => {
eprintln!("Write error: {e}");
process::exit(1);
}
}
}
#[cfg(not(feature = "linux"))]
{
eprintln!("I2C write requires --features=linux");
eprintln!("Please rebuild with: cargo build --features linux");
process::exit(1);
}
}
"show" => {
// ehatrom show <input.bin>
if args.len() != 3 {
eprintln!("Usage: ehatrom show <input.bin>");
process::exit(1);
}
let data = match std::fs::read(&args[2]) {
Ok(d) => d,
Err(e) => {
eprintln!("Failed to read input: {e}");
process::exit(1);
}
};
#[cfg(feature = "alloc")]
match Eeprom::from_bytes(&data) {
Ok(eeprom) => {
println!("EEPROM info:\n{eeprom:#?}");
}
Err(e) => {
eprintln!("Parse error: {e}");
process::exit(1);
}
}
#[cfg(not(feature = "alloc"))]
{
eprintln!("Parse command requires 'alloc' feature");
process::exit(1);
}
}
"detect" => {
// ehatrom detect [i2c-dev] or ehatrom detect --all
#[cfg(feature = "linux")]
{
#[cfg(target_os = "linux")]
{
use ehatrom::{detect_all_i2c_devices, detect_and_show_eeprom_info};
if args.len() >= 3 && args[2] == "--all" {
// Scan all I2C devices
match detect_all_i2c_devices() {
Ok(()) => {}
Err(e) => {
eprintln!("Detection error: {e}");
process::exit(1);
}
}
} else {
// Scan specific device or default
let dev = if args.len() >= 3 {
&args[2]
} else {
"/dev/i2c-0" // HAT EEPROM is typically on i2c-0
};
// Support reading large EEPROMs - default buffer is 32 KB
// You can override the size with the EHATROM_BUFFER_SIZE environment variable
let read_len = match env::var("EHATROM_BUFFER_SIZE") {
Ok(size_str) => match size_str.parse::<usize>() {
Ok(size) => {
if size < 1024 {
eprintln!(
"Warning: Buffer size too small, using minimum 1KB"
);
1024
} else {
println!("Using custom buffer size: {} bytes", size);
size
}
}
Err(_) => {
eprintln!(
"Warning: Failed to parse EHATROM_BUFFER_SIZE, using 32KB"
);
32 * 1024
}
},
Err(_) => 32 * 1024, // 32 KB by default
};
match detect_and_show_eeprom_info(dev, read_len) {
Ok(()) => {}
Err(e) => {
eprintln!("Detection error: {e}");
process::exit(1);
}
}
}
}
#[cfg(not(target_os = "linux"))]
{
println!("Linux feature enabled, but running on non-Linux platform.");
println!("I2C detection requires actual Linux /dev/i2c-* devices.");
println!(
"This demonstrates that the library compiles with Linux feature on any platform."
);
if args.len() >= 3 && args[2] == "--all" {
println!("Would scan all I2C devices on Linux");
} else {
let dev = if args.len() >= 3 {
&args[2]
} else {
"/dev/i2c-0"
};
println!("Would scan device: {}", dev);
println!("Would check addresses: [0x50]");
}
}
}
#[cfg(not(feature = "linux"))]
{
eprintln!("EEPROM detection requires --features=linux");
eprintln!("Please rebuild with: cargo build --features linux");
process::exit(1);
}
}
_ => {
eprintln!("Unknown command: {}", args[1]);
eprintln!("Usage: ehatrom <read|write|show|detect> [options]");
process::exit(1);
}
}
}