|
| 1 | +// |
| 2 | +// This file provides a example on how to work with slice in progmem (sort of) |
| 3 | +// on an Arduino Uno. |
| 4 | +// |
| 5 | + |
| 6 | + |
| 7 | +// Define no_std only for AVR |
| 8 | +#![cfg_attr(target_arch = "avr", no_std)] |
| 9 | +#![cfg_attr(target_arch = "avr", no_main)] |
| 10 | + |
| 11 | + |
| 12 | +use avr_progmem::progmem; // The macro |
| 13 | +use avr_progmem::wrapper::ProgMem; |
| 14 | +use cfg_if::cfg_if; |
| 15 | +#[cfg(target_arch = "avr")] |
| 16 | +use panic_halt as _; // halting panic implementation for AVR |
| 17 | + |
| 18 | +// First, there are no slices in progmem. All data must be statically size, |
| 19 | +// such as an array: |
| 20 | +progmem! { |
| 21 | + // Just one array of size 3 |
| 22 | + static progmem<const ARRAY_A_LEN: usize> ARRAY_A: [u8; ARRAY_A_LEN] = [1,2,3]; |
| 23 | + |
| 24 | + // Another array of size 5 |
| 25 | + static progmem<const ARRAY_B_LEN: usize> ARRAY_B: [u8; ARRAY_B_LEN] = [1,2,3,4,5]; |
| 26 | + |
| 27 | + // Yet another array |
| 28 | + static progmem<const ARRAY_C_LEN: usize> ARRAY_C: [u8; ARRAY_C_LEN] = [42]; |
| 29 | +} |
| 30 | + |
| 31 | +// Include a fancy printer supporting Arduino Uno's USB-Serial output as well |
| 32 | +// as stdout on non-AVR targets. |
| 33 | +mod printer; |
| 34 | +use printer::Printer; |
| 35 | + |
| 36 | +#[cfg_attr(target_arch = "avr", arduino_hal::entry)] |
| 37 | +fn main() -> ! { |
| 38 | + // Setup the output |
| 39 | + let mut printer = setup(); |
| 40 | + |
| 41 | + // |
| 42 | + // Working with slices. |
| 43 | + // |
| 44 | + // So, we actually only have statically sized arrays in progmem. However, |
| 45 | + // sometimes slices are nicer to work with, for instance if you want to put |
| 46 | + // them into a list or something, e.g. to iterate over them. |
| 47 | + // |
| 48 | + // There are basically to way to accomplish this, first just load those |
| 49 | + // arrays into RAM and coerce the standard Rust arrays into standard Rust |
| 50 | + // slices as usual. The drawback is the potential high RAM usage. |
| 51 | + // |
| 52 | + // In order to have the benefits of slices while the data is still in |
| 53 | + // progmem, we can also just coerce the ProgMems of arrays into ProgMems of |
| 54 | + // slices: |
| 55 | + |
| 56 | + // Once we have slice wrappers, we can store them together e.g. in a array |
| 57 | + let list_of_slices: [ProgMem<[u8]>; 3] = { |
| 58 | + cfg_if! { |
| 59 | + if #[cfg(feature = "unsize")] { |
| 60 | + // Option 1: just coerce them to a slice wrapper |
| 61 | + // but this requires the crate feature "unsize" |
| 62 | + |
| 63 | + [ |
| 64 | + ARRAY_A, |
| 65 | + ARRAY_B, |
| 66 | + ARRAY_C, |
| 67 | + ] |
| 68 | + } else { |
| 69 | + // Option 2: convert them explicitly via the "as_slice" method |
| 70 | + |
| 71 | + [ |
| 72 | + ARRAY_A.as_slice(), |
| 73 | + ARRAY_B.as_slice(), |
| 74 | + ARRAY_C.as_slice(), |
| 75 | + ] |
| 76 | + } |
| 77 | + } |
| 78 | + }; |
| 79 | + |
| 80 | + // And for instance iterate through that list. |
| 81 | + for (i, slice) in list_of_slices.iter().enumerate() { |
| 82 | + // Here `slice` is a `ProgMem<[u8]>`, which has (among others) a `len` and a |
| 83 | + // `load_at` method. |
| 84 | + |
| 85 | + ufmt::uwriteln!( |
| 86 | + &mut printer, |
| 87 | + "Element #{}, size: {}, first element: {}\r", |
| 88 | + i, |
| 89 | + slice.len(), |
| 90 | + slice.load_at(0) |
| 91 | + ) |
| 92 | + .unwrap(); |
| 93 | + |
| 94 | + // We can also use a progmem-iterator that gives a ProgMem wrapper for |
| 95 | + // each element of that slice (without yet loading any of them). |
| 96 | + for elem_wrapper in slice.wrapper_iter() { |
| 97 | + // Fun fact, if that element happened to be another array, we would |
| 98 | + // also iterate its elements without loading it yet. |
| 99 | + // That allows to iterate multi-dimensional arrays and only ever |
| 100 | + // loading a single element into RAM. |
| 101 | + |
| 102 | + // Only load a single element at a time |
| 103 | + let e = elem_wrapper.load(); |
| 104 | + ufmt::uwrite!(&mut printer, "{}, ", e).unwrap(); |
| 105 | + } |
| 106 | + printer.println(""); |
| 107 | + } |
| 108 | + |
| 109 | + // "end" the program |
| 110 | + finish(printer) |
| 111 | +} |
| 112 | + |
| 113 | +// |
| 114 | +// Following are just some auxiliary functions to setup and finish up the Arduino |
| 115 | +// |
| 116 | + |
| 117 | + |
| 118 | +// Setup the serial UART as output at 9600 baud and print a "Hello from Arduino" |
| 119 | +fn setup() -> Printer { |
| 120 | + let mut printer = { |
| 121 | + #[cfg(target_arch = "avr")] |
| 122 | + { |
| 123 | + // Initialize the USB-Serial output on the Arduino Uno |
| 124 | + |
| 125 | + let dp = arduino_hal::Peripherals::take().unwrap(); |
| 126 | + let pins = arduino_hal::pins!(dp); |
| 127 | + let serial = arduino_hal::default_serial!(dp, pins, 9600); |
| 128 | + |
| 129 | + Printer(serial) |
| 130 | + } |
| 131 | + #[cfg(not(target_arch = "avr"))] |
| 132 | + { |
| 133 | + // Just use stdout for non-AVR targets |
| 134 | + Printer |
| 135 | + } |
| 136 | + }; |
| 137 | + |
| 138 | + // Print some introduction text |
| 139 | + printer.println("Hello from Arduino!"); |
| 140 | + printer.println(""); |
| 141 | + printer.println("--------------------------"); |
| 142 | + printer.println(""); |
| 143 | + |
| 144 | + // return the printer |
| 145 | + printer |
| 146 | +} |
| 147 | + |
| 148 | +// Print a "DONE" and exit (or go into an infinite loop). |
| 149 | +fn finish(mut printer: Printer) -> ! { |
| 150 | + // Print some final lines |
| 151 | + printer.println(""); |
| 152 | + printer.println("--------------------------"); |
| 153 | + printer.println(""); |
| 154 | + printer.println("DONE"); |
| 155 | + |
| 156 | + // It is very convenient to just exit on non-AVR platforms, otherwise users |
| 157 | + // might get the impression that the program hangs, whereas it already |
| 158 | + // succeeded. |
| 159 | + #[cfg(not(target_arch = "avr"))] |
| 160 | + std::process::exit(0); |
| 161 | + |
| 162 | + // Otherwise, that is on AVR, just go into an infinite loop, because on AVR |
| 163 | + // we just can't exit! |
| 164 | + loop { |
| 165 | + // Done, just do nothing |
| 166 | + } |
| 167 | +} |
0 commit comments