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
#![no_std]
#![no_main]

#![allow(special_module_name)]

//! # Welcome to the neopixel example code!
//! - By: Jonathan Zurita
//! - Date: 11/18/2024
//! 
//! ## What is the function of this example?
//! This file shows the capabilities of the 
//! neopixel library. From individually addressing
//! one neopixel to addressing all of them, it truly
//! is a versatile library.
//! 
//! - If you are interested in looking into neopixel
//! library source code, look into the lib module to find 
//! `neopixel`
//! 

mod lib;
use lib::neopixel;


use esp_backtrace as _;

use esp_hal::{
    analog::adc::{Adc, AdcConfig, Attenuation}, 
    gpio::{Io, Level, Output}, 
    prelude::*, 
    timer::timg::TimerGroup,
};

use esp_hal::{
    delay::Delay,
    dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf},
    spi::master,
};

use esp_println::println;


/// main entry point for this example
#[entry]
fn main() -> ! {

    //////////////////////// INIT PERIPHERAL AND IO MAPS //////////////////////////////////////////////////////
    

    let peripherals = esp_hal::init(esp_hal::Config::default());
    let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
    let str = esp_hal::reset::get_reset_reason();
    println!("Reset Reason [Debug Purposes] => {:?}", str);

    // Initialize the Delay peripheral
    let mut delay = Delay::new();    


    //////////////////////////  INIT WDT   ////////////////////////////////////////////////////////////////////////////
  
    // initialize TIM0 group and watchdog timer  
    let timg0 = TimerGroup::new(peripherals.TIMG0);
    let mut wdt = timg0.wdt;
    
    // timeout set at 5 seconds and enable WDT
    wdt.set_timeout(5_000.millis());
    wdt.enable();
    // reset wdt timer (starts back at 5 second value)
    wdt.feed();


    //////////////////////// INIT SPI BUS AND PASS INTO FUNCTION //////////////////////////////////////////////////////
    
    // initialize the neopixel buffer with all LOGIC_0's in the buffer
    let mut arr: [u8 ; neopixel::ARR_SIZE] = neopixel::neopixel_init_buffer();

    let sclk = io.pins.gpio18;
    let miso = io.pins.gpio19;
    let mosi = io.pins.gpio23;
    let cs = io.pins.gpio5;

    let (rx_buf, rx_desc, tx_buf, tx_desc) = esp_hal::dma_buffers!(neopixel::ARR_SIZE);

    let dma = Dma::new(peripherals.DMA);
    let dma_channel = dma.spi2channel;
    
    // creates a SpiDma Instance
    let spi = master::Spi::new(peripherals.SPI2, 4000.kHz(), esp_hal::spi::SpiMode::Mode0)
        .with_sck(sclk)
        .with_mosi(mosi)
        .with_miso(miso)
        .with_cs(cs)
        .with_dma(
            dma_channel.configure(false, DmaPriority::Priority0)
        );

    // now create a SpiDmaBus instance given the SpiDma
    let dma_rx_buf = DmaRxBuf::new(rx_desc, rx_buf).unwrap();
    let dma_tx_buf = DmaTxBuf::new(tx_desc, tx_buf).unwrap();
    let mut spi_dma = spi.with_buffers(dma_rx_buf, dma_tx_buf);

    // sets the RGB value for a desired NeoPixel LED (indexes from 0)!!
    //neopixel_set_data(0x00000F, 7, &mut arr);

    // call the SPI dma transfer functions
    // also include the pass watchdog timer test
    neopixel::spi_dma_send(&mut spi_dma, &mut arr, &mut wdt);
    neopixel::spi_dma_send_breathing(&mut spi_dma, &mut arr, &mut delay, &mut wdt);

    // init BLUE LED GPIO pin
    let mut _led = Output::new(io.pins.gpio2, Level::Low);


    //////////////////////// INIT ADC AND PASS INTO FUNCTION!! //////////////////////////////////////////////////////
    
    // you can also initialize generic GPIO pins
    let analog_pin = io.pins.gpio36;

    // ADC configuration using the GPIO32 generic init 
    let mut adc1_config = AdcConfig::new(); // start ADC1 config process
    let mut adc1_pin = adc1_config.enable_pin(analog_pin, Attenuation::Attenuation11dB); // init GPIO32 to be ADC1 input pin
    let mut adc1 = Adc::new(peripherals.ADC1, adc1_config); // init the ADC1 module for use

    // test function passing in ADC parameters as mutable pointers
    //let mut adc1_val = test_function2(&mut adc1, &mut adc1_pin);


    //////////////////////// START OF INFINITE LOOP!! ///////////////////////////////////////////////////////////////
    
    loop {
        
       // test_function(&mut led);
        println!("test string");
        //adc1_val = test_function2(&mut adc1, &mut adc1_pin);

        // read ADC1_Channel0 value
        let adc1_val = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap();
        println!("{}", adc1_val);
        delay.delay_millis(250 as u32);
        
        // set ADC1_Channel0 hex value into an RGB color for neoPixel!
        neopixel::neopixel_set_entire_data(adc1_val as u32 , &mut arr);
        neopixel::spi_dma_send(&mut spi_dma, &mut arr, &mut wdt);

        // Error testing if you want to (wrong RGB value or wrong neoPixel position)
        // neopixel::neopixel_set_data(0xFFFFFFFF, (neopixels::NUM_LEDS + 1), &mut arr).unwrap();
    
    }

    //////////////////////// END OF MAIN LOOP ///////////////////////////////////////////////////////////////
    
}


// IMPROVING ROBUSTNESS
//
// If system goes into unrecoverable state:
// esp_hal::reset::software_reset_cpu();
// esp_hal::reset::software_reset();