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
/* callback.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! Reasonably generic way of dealing with callbacks from interrupt handlers.
//!

// Imports ===================================================================
use core::any::Any;

// Declarations ==============================================================
/**
 * Represents a callback function from an interrupt service routine.
 */
#[derive(Copy,Clone,Debug)]
pub enum IsrCallback<F,R>
{
  /// No Operation - dummy callback that evaluates to a fixed constant return
  /// value.
  Nop(R),
  /// A function/closure callback.  This will be called when the interrupt
  /// service routine needs it; the function signature is context dependent,
  /// however the last parameter will always be an `Option<&'static dyn Any>`
  /// user-data field, which will be given a `None` value.
  /// The first parameter must be an isolation token
  /// ([`avr_oxide::concurrency::Isolated`])
  Function(F),
  /// A function/closure callback.  This will be called when the interrupt
  /// service routine needs it; the function signature is context dependent,
  /// however the last parameter will always be an `Option<&'static dyn Any>`
  /// user-data field, into which the given data will be passed as Some()
  /// value.
  /// The first parameter must be an isolation token
  /// ([`avr_oxide::concurrency::Isolated`])
  WithData(F, *const dyn Any)
}

// Code ======================================================================
#[doc(hidden)]
#[macro_export]
macro_rules! isr_cb_invoke {
  ($isotoken:expr, $cb:expr, $($params:expr),*) => {
    {
      let cb : avr_oxide::hal::generic::callback::IsrCallback<_,_> = $cb;

      match cb {
        avr_oxide::hal::generic::callback::IsrCallback::Nop(r) => r,
        avr_oxide::hal::generic::callback::IsrCallback::Function(f) => (f)($isotoken, $($params),*, Option::None),
        avr_oxide::hal::generic::callback::IsrCallback::WithData(f,d) => (f)($isotoken, $($params),*, Option::Some(d))
      }
    }
  }
}

impl<F,R> IsrCallback<F,R> {
  /**
   * Return true iff this callback is a no-op function.  We can use this to
   * drive optimisations like disabling the interrupt routine entirely.
   */
  pub fn is_nop(&self) -> bool {
    match self {
      IsrCallback::Nop(_) => true,
      IsrCallback::Function(_) => false,
      IsrCallback::WithData(_, _) => false
    }
  }
}


// Tests =====================================================================