Skip to content

Commit

Permalink
Remove static mut variable declaration for Rust 2024
Browse files Browse the repository at this point in the history
  • Loading branch information
emeric-martineau committed May 9, 2024
1 parent 0a87af1 commit d8a94ad
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 71 deletions.
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub enum RbdDimmerErrorKind {
TimerEvery,
/// No dimmer found with ID
DimmerNotFound,
/// Not init
DimmerManagerNotInit,
}

/// Uart error with type and message
Expand Down
183 changes: 112 additions & 71 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
//! The `zc` sub-module works only for 50Hz voltage.
//! 50Hz = 100 half sinusoidal per seconde => 100%
use core::fmt;
use std::cell::RefCell;
use esp_idf_hal::gpio::{AnyInputPin, AnyOutputPin, Input, Output, PinDriver};
use esp_idf_hal::task::block_on;
use esp_idf_svc::timer::{EspISRTimerService, EspTimer};
use esp_idf_sys::EspError;
use std::cmp::Ordering;
use std::sync::atomic::{AtomicU8, Ordering as aOrdering};
use std::time::Duration;

use crate::error::*;
Expand Down Expand Up @@ -60,24 +62,35 @@ pub mod zc;
const HZ_50_DURATION: u8 = 100;
// 60Hz => half sinusoidal / 100 = 0.083 ms
const HZ_60_DURATION: u8 = 83;
// List of manager devices
static mut DIMMER_DEVICES: Vec<DimmerDevice> = vec![];

// The device manager
static mut DEVICES_DIMMER_MANAGER: Option<DevicesDimmerManager> = None;
// Maximal tick value. Cannot work 100% because of the zero crossing detection timer on the same core.
static mut TICK_MAX: u8 = 95;
static TICK_MAX: AtomicU8 = AtomicU8::new(95);
// Tick of device timer counter. TICK=0 means zero crossing detected.
// If TICK=TICK_MAX, nothing happen.
static mut TICK: u8 = 0;
static TICK: AtomicU8 = AtomicU8::new(0);
// Step of tick
static mut TICK_STEP: u8 = 1;
static TICK_STEP: AtomicU8 = AtomicU8::new(1);

/// Output pin (dimmer).
pub type OutputPin = PinDriver<'static, AnyOutputPin, Output>;
/// Input pin (zero crossing).
pub type InputPin = PinDriver<'static, AnyInputPin, Input>;

struct GlobalDimmerManager {
// List of manager devices
devices: RefCell<Vec<DimmerDevice>>,
// The device manager
manager: RefCell<Option<DevicesDimmerManager>>,
}

unsafe impl Sync for GlobalDimmerManager {

}

static GLOBAL_DIMMER_INSTANCE: GlobalDimmerManager = GlobalDimmerManager {
devices: RefCell::new(vec![]),
manager: RefCell::new(None),
};

/// This enum represent the frequency electricity.
#[derive(Debug, Clone, PartialEq)]
pub enum Frequency {
Expand All @@ -87,7 +100,7 @@ pub enum Frequency {
F60HZ,
}

// Similarly, implement `Display` for `Point2D`.
/// Similarly, implement `Display` for `Frequency`.
impl fmt::Display for Frequency {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Expand Down Expand Up @@ -150,6 +163,10 @@ impl DimmerDevice {
}
}

unsafe impl Sync for DimmerDevice {

}

/// Config of device manager
pub struct DevicesDimmerManagerConfig {
/// Pin for read zero crossing
Expand Down Expand Up @@ -213,47 +230,30 @@ pub struct DevicesDimmerManager {
}

impl DevicesDimmerManager {
/// At first time, init the manager singleton. Else, return singleton already created.
/// The list of device is singleton.
/// Max power is 95%.
pub fn init(config: DevicesDimmerManagerConfig) -> Result<&'static mut Self, RbdDimmerError> {
Self::init_advanced(config)
}

/// At first time, init the manager singleton. Else, return singleton already created.
/// The list of device is singleton.
/// step_size is allow to contol if power management is do 0 to 100 by step_size.
/// That allow also to be create more time for ISR timer (in 50Hz always 0.1ms * step size ).
pub fn init_advanced(
/// At first time, init the manager singleton.
pub fn init(
config: DevicesDimmerManagerConfig,
) -> Result<&'static mut Self, RbdDimmerError> {
unsafe {
TICK_MAX = config.tick_max;
TICK = TICK_MAX;

match DEVICES_DIMMER_MANAGER.as_mut() {
None => match Self::initialize(config) {
Ok(d) => Ok(d),
Err(e) => Err(RbdDimmerError::new(
RbdDimmerErrorKind::Other,
format!("Fail to initialize timer. Error code: {}", e),
)),
},
Some(d) => Ok(d),
}
) -> Result<(), RbdDimmerError> {
TICK_MAX.store(config.tick_max, aOrdering::Relaxed);
TICK.store(config.tick_max, aOrdering::Relaxed);

match Self::initialize(config) {
Ok(d) => Ok(d),
Err(e) => Err(RbdDimmerError::new(
RbdDimmerErrorKind::Other,
format!("Fail to initialize timer. Error code: {}", e),
)),
}
}

/// This function wait zero crossing. Zero crossing is low to high impulsion.
#[inline(always)]
pub fn wait_zero_crossing(&mut self) -> Result<(), RbdDimmerError> {
fn wait_zero_crossing(&mut self) -> Result<(), RbdDimmerError> {
let result = block_on(self.zero_crossing_pin.wait_for_falling_edge());

match result {
Ok(_) => {
unsafe {
TICK = 0;
}
TICK.store(0, aOrdering::Relaxed);
Ok(())
}
Err(_) => Err(RbdDimmerError::other(String::from(
Expand All @@ -263,10 +263,8 @@ impl DevicesDimmerManager {
}

/// Stop timer
pub fn stop(&mut self) -> Result<bool, RbdDimmerError> {
unsafe {
TICK = TICK_MAX;
}
fn stop(&self) -> Result<bool, RbdDimmerError> {
TICK.store(TICK_MAX.load(aOrdering::Relaxed), aOrdering::Relaxed);

match self.esp_timer.cancel() {
Ok(status) => Ok(status),
Expand All @@ -277,29 +275,47 @@ impl DevicesDimmerManager {
}
}

fn initialize(config: DevicesDimmerManagerConfig) -> Result<&'static mut Self, EspError> {
fn initialize(config: DevicesDimmerManagerConfig) -> Result<(), EspError> {
unsafe {
// Copy all devices
for d in config.devices {
DIMMER_DEVICES.push(d);
}
{
let mut devices = GLOBAL_DIMMER_INSTANCE.devices.borrow_mut();

for d in config.devices {
devices.push(d);
}
} // Borrom mut is release here

TICK_STEP = config.step_size;
TICK_STEP.store(config.step_size, aOrdering::Relaxed);

let callback = || {
match TICK.cmp(&TICK_MAX) {
let tick_max = TICK_MAX.load(aOrdering::Relaxed);
let tick = TICK.load(aOrdering::Relaxed);
match tick.cmp(&tick_max) {
Ordering::Less => {
for d in DIMMER_DEVICES.iter_mut() {
// TODO check error or not?
let _ = d.tick(TICK);
match GLOBAL_DIMMER_INSTANCE.devices.try_borrow_mut() {
Ok(mut devices) => {
for d in devices.iter_mut() {
// TODO check error or not?
let _ = d.tick(TICK.load(aOrdering::Relaxed));
}
},
Err(_) => {},
}

TICK += TICK_STEP;
TICK.store(
tick + TICK_STEP.load(aOrdering::Relaxed),
aOrdering::Relaxed,
);
}
Ordering::Greater => {}
Ordering::Equal => {
for d in DIMMER_DEVICES.iter_mut() {
d.reset();
match GLOBAL_DIMMER_INSTANCE.devices.try_borrow_mut() {
Ok(mut devices) => {
for d in devices.iter_mut() {
d.reset();
}
},
Err(_) => {},
}
}
};
Expand All @@ -319,35 +335,60 @@ impl DevicesDimmerManager {
))?;

// Create New device manager
DEVICES_DIMMER_MANAGER = Some(Self {
let mut manager = GLOBAL_DIMMER_INSTANCE.manager.borrow_mut();

*manager = Some(Self {
zero_crossing_pin: config.zero_crossing_pin,
esp_timer,
});

Ok(DEVICES_DIMMER_MANAGER.as_mut().unwrap())
Ok(())
}
}
}

/// Set power of a device. The list of device is singleton.
pub fn set_power(id: u8, power: u8) -> Result<(), RbdDimmerError> {
unsafe {
match DIMMER_DEVICES.iter_mut().find(|d| d.id == id) {
None => Err(RbdDimmerError::from(RbdDimmerErrorKind::DimmerNotFound)),
Some(device) => {
device.set_power(power);
Ok(())
match GLOBAL_DIMMER_INSTANCE.devices.try_borrow_mut() {
Ok(mut devices) => {
match devices.iter_mut().find(|d| d.id == id) {
Some(device) => {
device.set_power(power);
Ok(())
},
None => Err(RbdDimmerError::from(RbdDimmerErrorKind::DimmerNotFound)),
}
}
},
Err(_) => Ok(()),
}
}

/// Stop manager.
pub fn stop() -> Result<bool, RbdDimmerError> {
unsafe {
match DEVICES_DIMMER_MANAGER.as_mut() {
Some(d) => d.stop(),
None => Ok(true)
}
match GLOBAL_DIMMER_INSTANCE.manager.try_borrow_mut() {
Ok(mut manager) => {
match manager.as_mut() {
Some(d) => d.stop(),
None => Err(RbdDimmerError::from(RbdDimmerErrorKind::DimmerManagerNotInit)),
}
},
Err(_) => Ok(false),
}
}

pub fn wait_zero_crossing() -> Result<bool, RbdDimmerError> {
match GLOBAL_DIMMER_INSTANCE.manager.try_borrow_mut() {
Ok(mut manager) => {
match manager.as_mut() {
Some(d) => {
match d.wait_zero_crossing() {
Ok(()) => Ok(true),
Err(e) => Err(e),
}
},
None => Err(RbdDimmerError::from(RbdDimmerErrorKind::DimmerManagerNotInit)),
}
},
Err(_) => Ok(false),
}
}

0 comments on commit d8a94ad

Please sign in to comment.