Skip to content

Commit

Permalink
merge development branch
Browse files Browse the repository at this point in the history
  • Loading branch information
someweisguy committed Jul 17, 2021
2 parents d1ef73d + 5e9056f commit 14e3ec9
Show file tree
Hide file tree
Showing 16 changed files with 802 additions and 192 deletions.
Empty file added .development
Empty file.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
idf_component_register(SRCS "src/esp_dmx.c" INCLUDE_DIRS "include/")
idf_component_register(SRCS "src/esp_dmx.c" INCLUDE_DIRS "src/" "src/dmx")
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ DMX is a unidirectional communication protocol used primarily in the entertainme

Each DMX packet begins with a high-to-low transition called the break, followed by a low-to-high transition called the mark after break, followed by an eight-bit byte. This first byte is called the start code. The start-of-packet break, mark after break, and start code is called the reset sequence. After the reset sequence, a packet of up to 512 data bytes may be sent.

DMX imposes very strict timing requirements to allow for backwards compatibility with older lighting equipment. Frame rates may range from 1fps to up to approximately 830fps. A typical DMX controller transmits packets at approximately 44fps. DMX receivers and transmitters have different timing requirements which must be adhered to carefully to ensure commands are processed.
DMX imposes very strict timing requirements to allow for backwards compatibility with older lighting equipment. Frame rates may range from 1fps to up to approximately 830fps. A typical DMX controller transmits packets between approximately 25fps to 44fps. DMX receivers and transmitters have different timing requirements which must be adhered to carefully to ensure commands are processed.

Today, DMX often struggles to keep up with the demands of the latest hardware. Its low data rate and small packet size sees it losing market popularity over more capable protocols. However its simplicity and robustness often makes it the first choice for small scale projects.

Expand All @@ -93,14 +93,14 @@ The DMX driver’s functions identify each of the UART controllers using `dmx_po

Call the function `dmx_param_config()` and pass it a `dmx_config_t` structure. It contains all the parameters needed to configure the DMX packet settings. In most situations, custom packet configuration isn't necessary. The macro `DMX_DEFAULT_CONFIG` is provided to simplify this process.

```c
```cpp
const dmx_config_t dmx_config = DMX_DEFAULT_CONFIG;
dmx_param_config(DMX_NUM_2, &dmx_config);
```
If using a custom DMX configuration is desired, the `dmx_config_t` parameters can be set manually.
```c
```cpp
const dmx_config_t dmx_config = {
.baud_rate = 250000, // typical baud rate
.break_num = 45, // 180us
Expand All @@ -125,7 +125,7 @@ Each of the above functions has a `_get_` counterpart to check the currently set
### Setting Communication Pins
Configure the physical GPIO pins to which the DMX port will be connected. To do this, call the function `dmx_set_pin()` and specify which GPIO should be connected to the TX, RX, and RTS signals. If you want to keep a currently allocated pin to a specific signal, pass the macro DMX_PIN_NO_CHANGE. This macro should also be used if a pin isn't used.
Configure the physical GPIO pins to which the DMX port will be connected. To do this, call the function `dmx_set_pin()` and specify which GPIO should be connected to the TX, RX, and RTS signals. If you want to keep a currently allocated pin to a specific signal, pass the macro `DMX_PIN_NO_CHANGE`. This macro should also be used if a pin isn't used.
```cpp
// set TX: IO16 (port 2 default), RX: IO17 (port 2 default), RTS: IO21
Expand Down Expand Up @@ -240,7 +240,7 @@ if (xQueueReceive(queue, &event, DMX_RX_PACKET_TOUT_TICK) == pdTRUE) {

### Writing

Writing to the DMX bus does not require the use of an event queue. To write to the DMX bus, `dmx_write_packet()` can be called. This writes data to the DMX driver but it does not transmit a packet onto the bus. In order to transmit the data that was written, `dmx_tx_packet()` can be called. When a packet is sent out onto the bus, its size will be the same as the buffer size that was passed to `dmx_driver_install().`
Writing to the DMX bus does not require the use of an event queue. To write to the DMX bus, `dmx_write_packet()` can be called. This writes data to the DMX driver but it does not transmit a packet onto the bus. In order to transmit the data that was written, `dmx_tx_packet()` can be called. When a packet is sent out onto the bus, its size will be the same as the buffer size that was passed to `dmx_driver_install()`.

```cpp
uint8_t data[DMX_MAX_PACKET_SIZE] = { 0, 1, 2, 3 };
Expand Down Expand Up @@ -355,6 +355,7 @@ ANSI-ESTA E1.11 DMX512-A specifies that DMX devices be electrically isolated fro

## To Do

- Port the library to the Arduino IDE!
- Reset-Sequence-First Mode. Allow for reset sequences to be sent first rather than using the UART hardware break circuitry.
- Enable use of ESP32 Hardware Timer for Reset Sequence.
- Remote Device Management. Enable RDM compatibility for DMX transceivers.
- Art-Net. Enable Art-Net compatibility using ESP-IDF Ethernet Driver.
4 changes: 2 additions & 2 deletions examples/read_example/read_example.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*
* Read synchronously from the DMX bus. If the packet is a standard DMX packet,
* and there are no errors in the packet, logs a hex dump every 1 second of the
* first 16 and the last 16 bytes of data from the data packet. When the data
* times out, uninstalls the driver and the program terminates.
* first 16 bytes of data from the data packet. When the data times out,
* uninstalls the driver and the program terminates.
*/

#include "esp_dmx.h"
Expand Down
4 changes: 4 additions & 0 deletions examples/rx_stress_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
idf_component_register(
SRCS "rx_stress_test.c"
INCLUDE_DIRS ""
)
156 changes: 156 additions & 0 deletions examples/rx_stress_test/rx_stress_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#include <stdio.h>

#include "esp_dmx.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"

#include "driver/gpio.h"
#include "esp_wifi.h"
#include <string.h>
#include "nvs_flash.h"

#define TX_PIN 17
#define RX_PIN 16
#define EN_PIN 21

#define LED_PIN 13

#define EXAMPLE_SSID "MySSID"
#define EXAMPLE_PASS "MyPassword"

static const char *TAG = "main";

uint8_t data[DMX_MAX_PACKET_SIZE] = {};

static void wifi_handler(void *handler_args, esp_event_base_t base,
int event_id, void *event_data) {
if (base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
ESP_LOGI(TAG, "wifi started");
esp_wifi_connect();
} else if (base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
ESP_LOGI(TAG, "wifi disconnected");
esp_wifi_connect();
} else if (base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ESP_LOGI(TAG, "wifi connected");
}
}

void dmx_rx_task(void *arg) {
const dmx_port_t dmx_num = *(dmx_port_t *)arg;

// install the DMX driver
QueueHandle_t queue;
dmx_set_pin(dmx_num, TX_PIN, RX_PIN, EN_PIN);
const dmx_config_t dmx_config = DMX_DEFAULT_CONFIG;
dmx_param_config(dmx_num, &dmx_config);
dmx_driver_install(dmx_num, DMX_MAX_PACKET_SIZE, 1, &queue, 1);

dmx_set_mode(dmx_num, DMX_MODE_RX); // not required - in rx mode by default

// install the default gpio isr
gpio_install_isr_service(ESP_INTR_FLAG_EDGE | ESP_INTR_FLAG_IRAM);
dmx_rx_timing_enable(dmx_num, RX_PIN);

// light up the built-in LED when DMX connected
gpio_reset_pin(LED_PIN);
gpio_set_pull_mode(LED_PIN, GPIO_PULLUP_DISABLE);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(LED_PIN, 0);

uint32_t packet_counter = 0;
bool timeout = true;
while (!xTaskNotifyWait(0, 0, 0, 0)) {
dmx_event_t packet;
if (xQueueReceive(queue, &packet, DMX_RX_PACKET_TOUT_TICK)) {
if (packet.status == DMX_OK) {
if (timeout) {
ESP_LOGI(TAG, "dmx connected");
timeout = false;
packet_counter = 0;
gpio_set_level(LED_PIN, 1); // LED on
}
++packet_counter;
dmx_read_packet(dmx_num, data, packet.size);
ESP_LOGI(TAG,
"Frame: %i, Start Code: %02X, Size: %i, Slot 1: %03i, Break: %ius, "
"MAB: %ius Packet: %.2fms",
packet_counter, packet.start_code, packet.size, data[1],
packet.timing.brk, packet.timing.mab, packet.duration / 1000.0);
} else {
char *err_name;
switch (packet.status) {
case DMX_ERR_BUFFER_SIZE:
err_name = "DMX_ERR_BUFFER_SIZE";
break;
case DMX_ERR_IMPROPER_SLOT:
err_name = "DMX_ERR_IMPROPER_SLOT";
break;
case DMX_ERR_PACKET_SIZE:
err_name = "DMX_ERR_PACKET_SIZE";
break;
case DMX_ERR_DATA_OVERFLOW:
err_name = "DMX_ERR_DATA_OVERFLOW";
break;
default:
err_name = "UNKNOWN_ERR";
}
ESP_LOGE(TAG, "dmx error %s", err_name);
}
} else if (timeout == false) {
ESP_LOGW(TAG, "lost dmx signal");
timeout = true;
gpio_set_level(LED_PIN, 0); // LED off
}
// do other stuff here...
}

// if task is notified, the loop is exited and the driver deleted
dmx_driver_delete(dmx_num);

vTaskDelete(NULL);
}

void app_main(void) {
nvs_flash_init();

// initialize esp network STA interface
esp_netif_init();
esp_event_loop_create_default();
esp_netif_create_default_wifi_sta();

// init wifi driver with default configuration
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&wifi_init_config);

// register wifi event handlers
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_handler, NULL);
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_handler, NULL);

// configure the wifi connection and start the driver
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_SSID,
.password = EXAMPLE_PASS,
}
};
esp_wifi_set_mode(WIFI_MODE_STA);
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config);
esp_wifi_start();

// create the DMX task
ESP_LOGI(TAG, "Creating DMX task...");
TaskHandle_t dmx_task_handle;
static dmx_port_t dmx_num = 2;
xTaskCreate(dmx_rx_task, "dmx_task", 3072, &dmx_num, 10, &dmx_task_handle);


// uncomment the code below to stop the task after 10 seconds

//vTaskDelay(10000 / portTICK_PERIOD_MS);
//xTaskNotify(dmx_task_handle, 0, eNoAction);
//dmx_task_handle = NULL;
//ESP_LOGI(TAG, "Stopped DMX!");

}
99 changes: 0 additions & 99 deletions include/dmx/hal.h

This file was deleted.

Loading

0 comments on commit 14e3ec9

Please sign in to comment.