Skip to content

Commit

Permalink
Merge pull request #14 from kripton/DmxInputAsyncCallback
Browse files Browse the repository at this point in the history
Dmx input async callback
  • Loading branch information
jostlowe authored Dec 11, 2021
2 parents 526b73b + dd7a31d commit 10229e2
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 2 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ Use the `.read(...)` method to read the 3 channels for our RGB fixture into our

The `.read(...)` method blocks until it receives a valid DMX packet. Much like the `DmxOutput`, the zero'th channel in the DMX packet is the start code. Unless you want to mess around with other protocols such as RDM, the start code can safely be ignored.

As an alternative to the blocking `.read(...)` method, you can also start asynchronous buffer updates via the
`.read_async(...)` method. This way, the buffer is automatically updated when DMX data comes in.
Optionally, you can also pass a pointer to a callback-function that will be called everytime a new DMX
frame has been received, processed and has been written to the buffer.

```C++
void dmxDataRecevied() {
// A DMX frame has been received. Toggle some LED
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}

myDmxInput.read_async(buffer, dmxDataRecevied);
```
## Voltage Transceivers
The Pico itself cannot be directly hooked up to your DMX line, as DMX operates on RS485 logic levels,
which do not match the voltage levels of the GPIO pins on the Pico.
Expand Down
10 changes: 9 additions & 1 deletion src/DmxInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ DmxInput::return_code DmxInput::begin(uint pin, uint start_channel, uint num_cha
_start_channel = start_channel;
_num_channels = num_channels;
_buf = nullptr;
_cb = nullptr;

_dma_chan = dma_claim_unused_channel(true);

Expand Down Expand Up @@ -119,13 +120,20 @@ void dmxinput_dma_handler() {
#else
instance->_last_packet_timestamp = to_ms_since_boot(get_absolute_time());
#endif
// Trigger the callback if we have one
if (instance->_cb != nullptr) {
(*(instance->_cb))();
}
}
}
}

void DmxInput::read_async(volatile uint8_t *buffer) {
void DmxInput::read_async(volatile uint8_t *buffer, void (*inputUpdatedCallback)(void)) {

_buf = buffer;
if (inputUpdatedCallback!=nullptr) {
_cb = inputUpdatedCallback;
}

pio_sm_set_enabled(_pio, _sm, false);

Expand Down
5 changes: 4 additions & 1 deletion src/DmxInput.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class DmxInput
volatile uint _sm;
volatile uint _dma_chan;
volatile unsigned long _last_packet_timestamp=0;
void (*_cb)(void);
/*
All different return codes for the DMX class. Only the SUCCESS
Return code guarantees that the DMX output instance was properly configured
Expand Down Expand Up @@ -82,8 +83,10 @@ class DmxInput
/*
Start async read process. This should only be called once.
From then on, the buffer will always contain the latest DMX data.
If you want to be notified whenever a new DMX frame has been received,
provide a callback function that will be called without arguments.
*/
void read_async(volatile uint8_t *buffer);
void read_async(volatile uint8_t *buffer, void (*inputUpdatedCallback)(void) = nullptr);

/*
Get the timestamp (like millis()) from the moment the latest dmx packet was received.
Expand Down

0 comments on commit 10229e2

Please sign in to comment.