RSeries astromech firmware
PWMDecoder.h
Go to the documentation of this file.
1 #if !defined(ESP32)
2 #error Only supports ESP32
3 #endif
4 
5 #ifndef PWMDecoder_h_
6 #define PWMDecoder_h_
7 
8 #include "ReelTwo.h"
9 #include "core/SetupEvent.h"
10 #include "core/AnimatedEvent.h"
11 #include "driver/rmt.h"
12 #include "esp32-hal.h"
13 
14 #ifndef RMT_RX_MODE
15 #define RMT_RX_MODE false
16 #endif
17 
19 {
20 public:
21  PWMDecoder(void (*changeNotify)(int pin, uint16_t pwm), int pin1, int pin2 = -1, int pin3 = -1, int pin4 = -1) :
22  fChangeNotify(changeNotify)
23  {
24  fChannel[0].fGPIO = uint8_t(pin1);
25  fChannel[1].fGPIO = uint8_t(pin2);
26  fChannel[2].fGPIO = uint8_t(pin3);
27  fChannel[3].fGPIO = uint8_t(pin4);
28  fNumChannels = 4;
29  if (pin4 == -1)
30  fNumChannels = 3;
31  if (pin3 == -1)
32  fNumChannels = 2;
33  if (pin2 == -1)
34  fNumChannels = 1;
35  }
36 
37  PWMDecoder(int pin1, int pin2 = -1, int pin3 = -1, int pin4 = -1) :
38  PWMDecoder(nullptr, pin1, pin2, pin3, pin4)
39  {
40  }
41 
42  inline uint16_t channel(unsigned i = 0) const
43  {
44  return fChannel[i].fRawPulse;
45  }
46 
47  inline uint16_t getValue(unsigned i = 0) const
48  {
49  return fChannel[i].fRawPulse;
50  }
51 
52  inline bool hasChanged(unsigned i = 0)
53  {
54  return abs(int32_t(fChannel[i].fPulse) - int32_t(fChannel[i].fRawPulse)) > 20;
55  }
56 
57  inline unsigned numChannels() const
58  {
59  return fNumChannels;
60  }
61 
62  unsigned long getAge(unsigned i = 0)
63  {
64  return millis() - fChannel[i].fLastActive;
65  }
66 
67  bool isActive(unsigned i = 0)
68  {
69  return millis() > 500 && (fChannel[i].fPulse != 0 && getAge(i) < 500);
70  }
71 
72  bool becameActive(unsigned i = 0)
73  {
74  return (fChannel[i].fAliveStateChange && fChannel[i].fAlive);
75  }
76 
77  bool becameInactive(unsigned i = 0)
78  {
79  return (fChannel[i].fAliveStateChange && !fChannel[i].fAlive);
80  }
81 
82  virtual void animate() override
83  {
84  for (unsigned i = 0; i < fNumChannels; i++)
85  {
86  #ifndef RMT_RX_MODE
87  checkActive(i);
88  #endif
89  if (hasChanged(i))
90  {
91  fChannel[i].fPulse = fChannel[i].fRawPulse;
92  if (fChangeNotify != nullptr)
93  fChangeNotify(fChannel[i].fGPIO, fChannel[i].fPulse);
94  }
95  fChannel[i].fAliveStateChange = false;
96  if (isActive(i))
97  {
98  if (!fChannel[i].fAlive)
99  {
100  DEBUG_PRINT("PWM Start Pin: "); DEBUG_PRINTLN(fChannel[i].fGPIO);
101  fChannel[i].fAlive = true;
102  fChannel[i].fAliveStateChange = true;
103  }
104  }
105  else if (fChannel[i].fAlive)
106  {
107  DEBUG_PRINT("PWM End Pin: "); DEBUG_PRINTLN(fChannel[i].fGPIO);
108  fChannel[i].fAlive = false;
109  fChannel[i].fAliveStateChange = true;
110  }
111  }
112  }
113 
114 #ifdef RMT_RX_MODE
115  bool fStarted = false;
116  void begin()
117  {
118  if (fStarted)
119  return;
120  for (unsigned i = 0; i < fNumChannels; i++)
121  {
122  if ((fChannel[i].fReceiver = rmtInit(fChannel[i].fGPIO, RMT_RX_MODE, RMT_MEM_64)) != NULL)
123  {
124  rmtSetTick(fChannel[i].fReceiver, 1000);
125  rmtSetFilter(fChannel[i].fReceiver, true, 100);
126  rmtSetRxThreshold(fChannel[i].fReceiver, 5000);
127  rmtRead(fChannel[i].fReceiver, receive_data, &fChannel[i]);
128  }
129  else
130  {
131  DEBUG_PRINT("FAILED TO INIT RMT on ");
132  DEBUG_PRINTLN(fChannel[i].fGPIO);
133  }
134  }
135  fStarted = true;
136  }
137 
138  void end()
139  {
140  if (!fStarted)
141  return;
142  for (unsigned i = 0; i < fNumChannels; i++)
143  {
144  if (fChannel[i].fReceiver != nullptr)
145  {
146  rmtEnd(fChannel[i].fReceiver);
147  rmtDeinit(fChannel[i].fReceiver);
148  fChannel[i].fReceiver = nullptr;
149  }
150  }
151  fStarted = false;
152  }
153 #else
154  void begin();
155  void end();
156 #endif
157 
158 private:
159  uint8_t fNumChannels = 1;
160  static constexpr unsigned fMaxChannels = 8;
161  struct Channel
162  {
163  uint8_t fGPIO;
164  uint16_t fPulse;
165  volatile uint16_t fRawPulse;
166  bool fAlive;
167  bool fAliveStateChange;
168  uint32_t fLastActive;
169  rmt_obj_t* fReceiver;
170  } fChannel[fMaxChannels] = {};
171  void (*fChangeNotify)(int pin, uint16_t pwm) = nullptr;
172 
173 #ifdef RMT_RX_MODE
174  static void receive_data(uint32_t* data, size_t len, void* arg)
175  {
176  Channel* channel = (Channel*)arg;
177  rmt_data_t* it = (rmt_data_t*)data;
178  if (len >= 1)
179  {
180  channel->fRawPulse = it[0].duration0;
181  channel->fLastActive = millis();
182  }
183  }
184 #else
185  rmt_isr_handle_t fISRHandle = nullptr;
186  static void IRAM_ATTR rmt_isr_handler(void* arg);
187  void checkActive(unsigned i);
188 #endif
189 };
190 
191 #define ServoDecoder PWMDecoder
192 
193 #endif
RMT_RX_MODE
#define RMT_RX_MODE
Definition: PWMDecoder.h:15
PWMDecoder::becameActive
bool becameActive(unsigned i=0)
Definition: PWMDecoder.h:72
DEBUG_PRINT
#define DEBUG_PRINT(s)
Definition: ReelTwo.h:189
ReelTwo.h
SetupEvent.h
AnimatedEvent
Base class for all animated devices. AnimatedEvent::animate() is called for each device once through ...
Definition: AnimatedEvent.h:18
AnimatedEvent.h
PWMDecoder::getValue
uint16_t getValue(unsigned i=0) const
Definition: PWMDecoder.h:47
DEBUG_PRINTLN
#define DEBUG_PRINTLN(s)
Definition: ReelTwo.h:188
PWMDecoder::becameInactive
bool becameInactive(unsigned i=0)
Definition: PWMDecoder.h:77
IRAM_ATTR
#define IRAM_ATTR
Definition: ReelTwo.h:155
PWMDecoder::PWMDecoder
PWMDecoder(void(*changeNotify)(int pin, uint16_t pwm), int pin1, int pin2=-1, int pin3=-1, int pin4=-1)
Definition: PWMDecoder.h:21
PWMDecoder::getAge
unsigned long getAge(unsigned i=0)
Definition: PWMDecoder.h:62
PWMDecoder
Definition: PWMDecoder.h:18
PWMDecoder::channel
uint16_t channel(unsigned i=0) const
Definition: PWMDecoder.h:42
PWMDecoder::isActive
bool isActive(unsigned i=0)
Definition: PWMDecoder.h:67
PWMDecoder::end
void end()
Definition: PWMDecoder.h:138
PWMDecoder::numChannels
unsigned numChannels() const
Definition: PWMDecoder.h:57
PWMDecoder::animate
virtual void animate() override
Subclasses must implement this function to run through a single frame of animation/activity.
Definition: PWMDecoder.h:82
PWMDecoder::PWMDecoder
PWMDecoder(int pin1, int pin2=-1, int pin3=-1, int pin4=-1)
Definition: PWMDecoder.h:37
PWMDecoder::fStarted
bool fStarted
Definition: PWMDecoder.h:115
PWMDecoder::hasChanged
bool hasChanged(unsigned i=0)
Definition: PWMDecoder.h:52
PWMDecoder::begin
void begin()
Definition: PWMDecoder.h:116