From 50b14ac4bfdf564ae5857b050a88406bc464c02d Mon Sep 17 00:00:00 2001 From: Austin McElroy Date: Thu, 26 Oct 2023 13:20:50 -0500 Subject: [PATCH] Added index of addresses The issue came up on the Max17261, where the addressing is non-contiguous. In v0.4.0, accessing the registers by address caused a buffer overflow because the address was larger than the indexable register map. The solution is an array of addresses. --- examples/max17261.rs | 2 +- src/lib.rs | 53 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/examples/max17261.rs b/examples/max17261.rs index 3897f5c..ef22ea1 100644 --- a/examples/max17261.rs +++ b/examples/max17261.rs @@ -43,7 +43,7 @@ pub fn main() { peripheral!( Max17261, - 0x0A, + 0x36, 112, [ // 0x00 to 0x10 diff --git a/src/lib.rs b/src/lib.rs index 4fedb8d..a12a367 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,9 +25,9 @@ pub enum Errors { #[macro_export] macro_rules! register_backer { ($reg_name:ident, $reg_type:ty) => { - type RegisterType = $reg_type; + pub type RegisterType = $reg_type; - type RegisterBacker = $reg_name; + pub type RegisterBacker = $reg_name; #[derive(Copy, Clone)] pub struct $reg_name { @@ -142,7 +142,7 @@ macro_rules! register_backer { macro_rules! peripheral { //($enum_name:ident, $enum_type:ty, [$(($name:ident, $value:literal)),+]) => { - ($peripheral_name:ident, $i2c_addr:literal, $count:literal, [$(($register:ident, $addr:literal, $index:literal)),+]) => { + ($peripheral_name:ident, $address_type:ty, $i2c_addr:literal, $count:literal, [$(($register:ident, $addr:literal, $index:literal)),+]) => { #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum RegisterAddress { $( @@ -159,24 +159,63 @@ macro_rules! peripheral { pub struct $peripheral_name { registers: [RegisterBacker; $count], + address_index: [$address_type; $count], i2c_addr: u16, } impl $peripheral_name { pub fn new() -> Self { + let mut address_index: [$address_type; $count] = [0; $count]; + + $( + address_index[$index as usize] = $addr as $address_type; + )+ + $peripheral_name { registers: [RegisterBacker { contents: 0 }; $count], + address_index, i2c_addr: $i2c_addr, } } - pub fn direct_update(&mut self, address: usize, val: RegisterType) -> &mut Self { - self.registers[address].update(val); + pub fn find_index_by_address(&self, address: usize) -> Option { + for i in 0..$count { + if self.address_index[i] == address as $address_type { + return Some(i); + } + } + + None + } + + pub fn direct_update_by_address(&mut self, address: usize, val: RegisterType) -> &mut Self { + let index = self.find_index_by_address(address); + match index { + Some(i) => { + self.registers[i].update(val); + }, + None => { + panic!("Address not found"); + } + } self } - pub fn direct_read(&self, address: usize) -> RegisterType { - self.registers[address].contents() + pub fn direct_read_by_address(&self, address: usize) -> RegisterType { + let index = self.find_index_by_address(address); + match index { + Some(i) => { + return self.registers[i].contents(); + }, + None => { + panic!("Address not found"); + } + } + } + + pub fn direct_update_by_index(&mut self, index: usize, val: RegisterType) -> &mut Self { + self.registers[index].update(val); + self } pub fn get_i2c_address(&self) -> u16 {