Initial DMX (Enttec OpenDMX USB) support and serial_port improvements
* Support DMX RGB lights (PAR lights, spotlights, wash lights, etc) * Configurable R/G/B channel and Brightness/Master channel * Add configurable parameters to serial_port needed to configure a port for DMX * Add DMX tab to settings
This commit is contained in:
parent
8b4b2bacbc
commit
81aaf67ff0
14 changed files with 1318 additions and 48 deletions
142
Controllers/DMXController/DMXControllerDetect.cpp
Normal file
142
Controllers/DMXController/DMXControllerDetect.cpp
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#include "Detector.h"
|
||||
#include "RGBController.h"
|
||||
#include "RGBController_DMX.h"
|
||||
#include "SettingsManager.h"
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
/******************************************************************************************\
|
||||
* *
|
||||
* DetectDMXControllers *
|
||||
* *
|
||||
* Detect devices supported by the DMX driver *
|
||||
* *
|
||||
\******************************************************************************************/
|
||||
|
||||
void DetectDMXControllers()
|
||||
{
|
||||
json dmx_settings;
|
||||
|
||||
std::vector<std::vector<DMXDevice>> device_lists;
|
||||
DMXDevice dev;
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Get DMX settings from settings manager |
|
||||
\*-------------------------------------------------*/
|
||||
dmx_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("DMXDevices");
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| If the DMX settings contains devices, process |
|
||||
\*-------------------------------------------------*/
|
||||
if(dmx_settings.contains("devices"))
|
||||
{
|
||||
for(unsigned int device_idx = 0; device_idx < dmx_settings["devices"].size(); device_idx++)
|
||||
{
|
||||
/*-------------------------------------------------*\
|
||||
| Clear DMX device data |
|
||||
\*-------------------------------------------------*/
|
||||
dev.name = "";
|
||||
dev.keepalive_time = 0;
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("name"))
|
||||
{
|
||||
dev.name = dmx_settings["devices"][device_idx]["name"];
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("port"))
|
||||
{
|
||||
dev.port = dmx_settings["devices"][device_idx]["port"];
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("keepalive_time"))
|
||||
{
|
||||
dev.keepalive_time = dmx_settings["devices"][device_idx]["keepalive_time"];
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("red_channel"))
|
||||
{
|
||||
dev.red_channel = dmx_settings["devices"][device_idx]["red_channel"];
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("green_channel"))
|
||||
{
|
||||
dev.green_channel = dmx_settings["devices"][device_idx]["green_channel"];
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("blue_channel"))
|
||||
{
|
||||
dev.blue_channel = dmx_settings["devices"][device_idx]["blue_channel"];
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("brightness_channel"))
|
||||
{
|
||||
dev.brightness_channel = dmx_settings["devices"][device_idx]["brightness_channel"];
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Determine whether to create a new list or add this device |
|
||||
| to an existing list. A device is added to an existing |
|
||||
| list if both devices share one or more universes for the |
|
||||
| same output destination |
|
||||
\*---------------------------------------------------------*/
|
||||
bool device_added_to_existing_list = false;
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Track grouping for all controllers. |
|
||||
\*---------------------------------------------------------*/
|
||||
for(unsigned int list_idx = 0; list_idx < device_lists.size(); list_idx++)
|
||||
{
|
||||
for(unsigned int device_idx = 0; device_idx < device_lists[list_idx].size(); device_idx++)
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| Check if the port used by this new device is the same as |
|
||||
| in the existing device. If so, add the new device to the |
|
||||
| existing list. |
|
||||
\*---------------------------------------------------------*/
|
||||
if(1)
|
||||
{
|
||||
device_lists[list_idx].push_back(dev);
|
||||
device_added_to_existing_list = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(device_added_to_existing_list)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| If the device did not overlap with existing devices, |
|
||||
| create a new list for it |
|
||||
\*---------------------------------------------------------*/
|
||||
if(!device_added_to_existing_list)
|
||||
{
|
||||
std::vector<DMXDevice> new_list;
|
||||
|
||||
new_list.push_back(dev);
|
||||
|
||||
device_lists.push_back(new_list);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(unsigned int list_idx = 0; list_idx < device_lists.size(); list_idx++)
|
||||
{
|
||||
RGBController_DMX* rgb_controller;
|
||||
rgb_controller = new RGBController_DMX(device_lists[list_idx]);
|
||||
ResourceManager::get()->RegisterRGBController(rgb_controller);
|
||||
}
|
||||
}
|
||||
|
||||
} /* DetectDMXControllers() */
|
||||
|
||||
REGISTER_DETECTOR("DMX", DetectDMXControllers);
|
||||
233
Controllers/DMXController/RGBController_DMX.cpp
Normal file
233
Controllers/DMXController/RGBController_DMX.cpp
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
/*-----------------------------------------*\
|
||||
| RGBController_DMX.cpp |
|
||||
| |
|
||||
| Generic RGB Interface for OpenAuraSDK |
|
||||
| DMX interface |
|
||||
| |
|
||||
| Adam Honse (CalcProgrammer1) 4/30/2023 |
|
||||
\*-----------------------------------------*/
|
||||
|
||||
#include "RGBController_DMX.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "LogManager.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name DMX Devices
|
||||
@category LEDStrip
|
||||
@type Serial
|
||||
@save :x:
|
||||
@direct :white_check_mark:
|
||||
@effects :x:
|
||||
@detectors DetectDMXControllers
|
||||
@comment
|
||||
\*-------------------------------------------------------------------*/
|
||||
|
||||
RGBController_DMX::RGBController_DMX(std::vector<DMXDevice> device_list)
|
||||
{
|
||||
devices = device_list;
|
||||
|
||||
name = "DMX Device Group";
|
||||
type = DEVICE_TYPE_LEDSTRIP;
|
||||
description = "DMX Device";
|
||||
location = "DMX: " + devices[0].port;
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| If this controller only represents a |
|
||||
| single device, use the device name for the|
|
||||
| controller name |
|
||||
\*-----------------------------------------*/
|
||||
if(devices.size() == 1)
|
||||
{
|
||||
name = devices[0].name;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Open OpenDMX port |
|
||||
\*-----------------------------------------*/
|
||||
port = new serial_port(devices[0].port.c_str(), 250000, SERIAL_PORT_PARITY_NONE, SERIAL_PORT_SIZE_8, SERIAL_PORT_STOP_BITS_2, false);
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Clear the RTS signal, which enables the |
|
||||
| OpenDMX RS-485 drive enable |
|
||||
\*-----------------------------------------*/
|
||||
port->serial_set_rts(false);
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Set up modes |
|
||||
\*-----------------------------------------*/
|
||||
mode Direct;
|
||||
Direct.name = "Direct";
|
||||
Direct.value = 0;
|
||||
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Direct.color_mode = MODE_COLORS_PER_LED;
|
||||
Direct.brightness = 255;
|
||||
Direct.brightness_min = 0;
|
||||
Direct.brightness_max = 255;
|
||||
modes.push_back(Direct);
|
||||
|
||||
keepalive_delay = 0ms;
|
||||
|
||||
SetupZones();
|
||||
|
||||
for (std::size_t device_idx = 0; device_idx < devices.size(); device_idx++)
|
||||
{
|
||||
/*-----------------------------------------*\
|
||||
| Update keepalive delay |
|
||||
\*-----------------------------------------*/
|
||||
if(devices[device_idx].keepalive_time > 0)
|
||||
{
|
||||
if(keepalive_delay.count() == 0 || keepalive_delay.count() > devices[device_idx].keepalive_time)
|
||||
{
|
||||
keepalive_delay = std::chrono::milliseconds(devices[device_idx].keepalive_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(keepalive_delay.count() > 0)
|
||||
{
|
||||
keepalive_thread_run = 1;
|
||||
keepalive_thread = new std::thread(&RGBController_DMX::KeepaliveThreadFunction, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
keepalive_thread_run = 0;
|
||||
keepalive_thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RGBController_DMX::~RGBController_DMX()
|
||||
{
|
||||
if(keepalive_thread != nullptr)
|
||||
{
|
||||
keepalive_thread_run = 0;
|
||||
keepalive_thread->join();
|
||||
delete keepalive_thread;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Delete the matrix map |
|
||||
\*---------------------------------------------------------*/
|
||||
for(unsigned int zone_index = 0; zone_index < zones.size(); zone_index++)
|
||||
{
|
||||
if(zones[zone_index].matrix_map != NULL)
|
||||
{
|
||||
if(zones[zone_index].matrix_map->map != NULL)
|
||||
{
|
||||
delete zones[zone_index].matrix_map->map;
|
||||
}
|
||||
|
||||
delete zones[zone_index].matrix_map;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RGBController_DMX::SetupZones()
|
||||
{
|
||||
/*-----------------------------------------*\
|
||||
| Add Zones |
|
||||
\*-----------------------------------------*/
|
||||
for(std::size_t zone_idx = 0; zone_idx < devices.size(); zone_idx++)
|
||||
{
|
||||
zone led_zone;
|
||||
led_zone.name = devices[zone_idx].name;
|
||||
led_zone.type = ZONE_TYPE_SINGLE;
|
||||
led_zone.leds_min = 1;
|
||||
led_zone.leds_max = 1;
|
||||
led_zone.leds_count = 1;
|
||||
led_zone.matrix_map = NULL;
|
||||
|
||||
zones.push_back(led_zone);
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Add LEDs |
|
||||
\*-----------------------------------------*/
|
||||
for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++)
|
||||
{
|
||||
for(std::size_t led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++)
|
||||
{
|
||||
led new_led;
|
||||
|
||||
new_led.name = zones[zone_idx].name + " LED ";
|
||||
new_led.name.append(std::to_string(led_idx));
|
||||
|
||||
leds.push_back(new_led);
|
||||
}
|
||||
}
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_DMX::ResizeZone(int /*zone*/, int /*new_size*/)
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| This device does not support resizing zones |
|
||||
\*---------------------------------------------------------*/
|
||||
}
|
||||
|
||||
void RGBController_DMX::DeviceUpdateLEDs()
|
||||
{
|
||||
int color_idx = 0;
|
||||
|
||||
last_update_time = std::chrono::steady_clock::now();
|
||||
|
||||
unsigned char dmx_data[513];
|
||||
|
||||
memset(dmx_data, 0, sizeof(dmx_data));
|
||||
|
||||
for(unsigned int device_idx = 0; device_idx < devices.size(); device_idx++)
|
||||
{
|
||||
if(devices[device_idx].brightness_channel > 0)
|
||||
{
|
||||
dmx_data[devices[device_idx].brightness_channel] = modes[0].brightness;
|
||||
}
|
||||
|
||||
if(devices[device_idx].red_channel > 0)
|
||||
{
|
||||
dmx_data[devices[device_idx].red_channel] = RGBGetRValue(colors[device_idx]);
|
||||
}
|
||||
|
||||
if(devices[device_idx].green_channel > 0)
|
||||
{
|
||||
dmx_data[devices[device_idx].green_channel] = RGBGetGValue(colors[device_idx]);
|
||||
}
|
||||
|
||||
if(devices[device_idx].blue_channel > 0)
|
||||
{
|
||||
dmx_data[devices[device_idx].blue_channel] = RGBGetBValue(colors[device_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
port->serial_break();
|
||||
port->serial_write((char*)&dmx_data, sizeof(dmx_data));
|
||||
}
|
||||
|
||||
void RGBController_DMX::UpdateZoneLEDs(int /*zone*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_DMX::UpdateSingleLED(int /*led*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_DMX::DeviceUpdateMode()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RGBController_DMX::KeepaliveThreadFunction()
|
||||
{
|
||||
while(keepalive_thread_run.load())
|
||||
{
|
||||
if((std::chrono::steady_clock::now() - last_update_time) > ( keepalive_delay * 0.95f ) )
|
||||
{
|
||||
UpdateLEDs();
|
||||
}
|
||||
std::this_thread::sleep_for(keepalive_delay / 2);
|
||||
}
|
||||
}
|
||||
52
Controllers/DMXController/RGBController_DMX.h
Normal file
52
Controllers/DMXController/RGBController_DMX.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*-----------------------------------------*\
|
||||
| RGBController_DMX.h |
|
||||
| |
|
||||
| Generic RGB Interface for OpenAuraSDK |
|
||||
| DMX interface |
|
||||
| |
|
||||
| Adam Honse (CalcProgrammer1) 4/30/2023 |
|
||||
\*-----------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
#include "RGBController.h"
|
||||
#include "serial_port.h"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
struct DMXDevice
|
||||
{
|
||||
std::string name;
|
||||
std::string port;
|
||||
unsigned int keepalive_time;
|
||||
unsigned int red_channel;
|
||||
unsigned int green_channel;
|
||||
unsigned int blue_channel;
|
||||
unsigned int brightness_channel;
|
||||
};
|
||||
|
||||
class RGBController_DMX : public RGBController
|
||||
{
|
||||
public:
|
||||
RGBController_DMX(std::vector<DMXDevice> device_list);
|
||||
~RGBController_DMX();
|
||||
|
||||
void SetupZones();
|
||||
|
||||
void ResizeZone(int zone, int new_size);
|
||||
|
||||
void DeviceUpdateLEDs();
|
||||
void UpdateZoneLEDs(int zone);
|
||||
void UpdateSingleLED(int led);
|
||||
|
||||
void DeviceUpdateMode();
|
||||
|
||||
void KeepaliveThreadFunction();
|
||||
|
||||
private:
|
||||
std::vector<DMXDevice> devices;
|
||||
serial_port * port;
|
||||
std::thread * keepalive_thread;
|
||||
std::atomic<bool> keepalive_thread_run;
|
||||
std::chrono::milliseconds keepalive_delay;
|
||||
std::chrono::time_point<std::chrono::steady_clock> last_update_time;
|
||||
};
|
||||
10
OpenRGB.pro
10
OpenRGB.pro
|
|
@ -108,6 +108,7 @@ INCLUDEPATH +=
|
|||
Controllers/CryorigH7QuadLumiController/ \
|
||||
Controllers/DasKeyboardController/ \
|
||||
Controllers/DebugController/ \
|
||||
Controllers/DMXController/ \
|
||||
Controllers/DuckyKeyboardController/ \
|
||||
Controllers/DygmaRaiseController/ \
|
||||
Controllers/E131Controller/ \
|
||||
|
|
@ -240,6 +241,8 @@ HEADERS +=
|
|||
qt/OpenRGBSystemInfoPage.h \
|
||||
qt/OpenRGBThemeManager.h \
|
||||
qt/OpenRGBZoneResizeDialog.h \
|
||||
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsEntry.h \
|
||||
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsPage.h \
|
||||
qt/OpenRGBE131SettingsPage/OpenRGBE131SettingsEntry.h \
|
||||
qt/OpenRGBE131SettingsPage/OpenRGBE131SettingsPage.h \
|
||||
qt/OpenRGBLIFXSettingsPage/OpenRGBLIFXSettingsEntry.h \
|
||||
|
|
@ -393,6 +396,7 @@ HEADERS +=
|
|||
Controllers/DarkProject/RGBController_DarkProjectKeyboard.h \
|
||||
Controllers/DasKeyboardController/DasKeyboardController.h \
|
||||
Controllers/DasKeyboardController/RGBController_DasKeyboard.h \
|
||||
Controllers/DMXController/RGBController_DMX.h \
|
||||
Controllers/DuckyKeyboardController/DuckyKeyboardController.h \
|
||||
Controllers/DuckyKeyboardController/RGBController_DuckyKeyboard.h \
|
||||
Controllers/DygmaRaiseController/DygmaRaiseController.h \
|
||||
|
|
@ -799,6 +803,8 @@ SOURCES +=
|
|||
qt/QTooltipedSlider.cpp \
|
||||
qt/TabLabel.cpp \
|
||||
qt/hsv.cpp \
|
||||
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsEntry.cpp \
|
||||
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsPage.cpp \
|
||||
qt/OpenRGBE131SettingsPage/OpenRGBE131SettingsEntry.cpp \
|
||||
qt/OpenRGBE131SettingsPage/OpenRGBE131SettingsPage.cpp \
|
||||
qt/OpenRGBLIFXSettingsPage/OpenRGBLIFXSettingsEntry.cpp \
|
||||
|
|
@ -981,6 +987,8 @@ SOURCES +=
|
|||
Controllers/DasKeyboardController/DasKeyboardController.cpp \
|
||||
Controllers/DasKeyboardController/DasKeyboardControllerDetect.cpp \
|
||||
Controllers/DasKeyboardController/RGBController_DasKeyboard.cpp \
|
||||
Controllers/DMXController/DMXControllerDetect.cpp \
|
||||
Controllers/DMXController/RGBController_DMX.cpp \
|
||||
Controllers/DuckyKeyboardController/DuckyKeyboardController.cpp \
|
||||
Controllers/DuckyKeyboardController/DuckyKeyboardControllerDetect.cpp \
|
||||
Controllers/DuckyKeyboardController/RGBController_DuckyKeyboard.cpp \
|
||||
|
|
@ -1426,6 +1434,8 @@ FORMS +=
|
|||
qt/OpenRGBSupportedDevicesPage.ui \
|
||||
qt/OpenRGBSystemInfoPage.ui \
|
||||
qt/OpenRGBZoneResizeDialog.ui \
|
||||
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsEntry.ui \
|
||||
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsPage.ui \
|
||||
qt/OpenRGBE131SettingsPage/OpenRGBE131SettingsEntry.ui \
|
||||
qt/OpenRGBE131SettingsPage/OpenRGBE131SettingsPage.ui \
|
||||
qt/OpenRGBElgatoKeyLightSettingsPage/OpenRGBElgatoKeyLightSettingsEntry.ui \
|
||||
|
|
|
|||
29
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsEntry.cpp
Normal file
29
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsEntry.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#include "OpenRGBDMXSettingsEntry.h"
|
||||
#include "ui_OpenRGBDMXSettingsEntry.h"
|
||||
|
||||
using namespace Ui;
|
||||
|
||||
OpenRGBDMXSettingsEntry::OpenRGBDMXSettingsEntry(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::OpenRGBDMXSettingsEntryUi)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
OpenRGBDMXSettingsEntry::~OpenRGBDMXSettingsEntry()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void OpenRGBDMXSettingsEntry::changeEvent(QEvent *event)
|
||||
{
|
||||
if(event->type() == QEvent::LanguageChange)
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Ui::OpenRGBDMXSettingsEntry::on_TypeComboBox_currentIndexChanged(int index)
|
||||
{
|
||||
|
||||
}
|
||||
25
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsEntry.h
Normal file
25
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsEntry.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef OPENRGBDMXSETTINGSENTRY_H
|
||||
#define OPENRGBDMXSETTINGSENTRY_H
|
||||
|
||||
#include "ui_OpenRGBDMXSettingsEntry.h"
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class OpenRGBDMXSettingsEntry;
|
||||
}
|
||||
|
||||
class Ui::OpenRGBDMXSettingsEntry : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OpenRGBDMXSettingsEntry(QWidget *parent = nullptr);
|
||||
~OpenRGBDMXSettingsEntry();
|
||||
Ui::OpenRGBDMXSettingsEntryUi *ui;
|
||||
|
||||
private slots:
|
||||
void changeEvent(QEvent *event);
|
||||
void on_TypeComboBox_currentIndexChanged(int index);
|
||||
};
|
||||
|
||||
#endif // OPENRGBDMXSETTINGSENTRY_H
|
||||
109
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsEntry.ui
Normal file
109
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsEntry.ui
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>OpenRGBDMXSettingsEntryUi</class>
|
||||
<widget class="QWidget" name="OpenRGBDMXSettingsEntryUi">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>531</width>
|
||||
<height>199</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>E131 settings entry</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="4" column="4">
|
||||
<widget class="QLabel" name="BrightnessLabel">
|
||||
<property name="text">
|
||||
<string>Brightness Channel:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="5">
|
||||
<widget class="QLineEdit" name="BrightnessEdit"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Blue Channel:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="5">
|
||||
<widget class="QLineEdit" name="GreenEdit"/>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLineEdit" name="RedEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="NameLabel">
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QLabel" name="GreenLabel">
|
||||
<property name="text">
|
||||
<string>Green Channel:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="RedLabel">
|
||||
<property name="text">
|
||||
<string>Red Channel:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QLineEdit" name="BlueEdit"/>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLineEdit" name="NameEdit"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="KeepaliveTimeLabel">
|
||||
<property name="text">
|
||||
<string>Keepalive Time:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<widget class="QLineEdit" name="KeepaliveTimeEdit"/>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLabel" name="PortLabel">
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="QLineEdit" name="PortEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>NameEdit</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
160
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsPage.cpp
Normal file
160
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsPage.cpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
#include "OpenRGBDMXSettingsPage.h"
|
||||
#include "ui_OpenRGBDMXSettingsPage.h"
|
||||
#include "ResourceManager.h"
|
||||
|
||||
using namespace Ui;
|
||||
|
||||
OpenRGBDMXSettingsPage::OpenRGBDMXSettingsPage(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::OpenRGBDMXSettingsPageUi)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
json dmx_settings;
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Get DMX settings from settings manager |
|
||||
\*-------------------------------------------------*/
|
||||
dmx_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("DMXDevices");
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| If the DMX settings contains devices, process |
|
||||
\*-------------------------------------------------*/
|
||||
if(dmx_settings.contains("devices"))
|
||||
{
|
||||
for(unsigned int device_idx = 0; device_idx < dmx_settings["devices"].size(); device_idx++)
|
||||
{
|
||||
OpenRGBDMXSettingsEntry* entry = new OpenRGBDMXSettingsEntry;
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("name"))
|
||||
{
|
||||
entry->ui->NameEdit->setText(QString::fromStdString(dmx_settings["devices"][device_idx]["name"]));
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("port"))
|
||||
{
|
||||
entry->ui->PortEdit->setText(QString::fromStdString(dmx_settings["devices"][device_idx]["port"]));
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("red_channel"))
|
||||
{
|
||||
entry->ui->RedEdit->setText(QString::number((int)dmx_settings["devices"][device_idx]["red_channel"]));
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("green_channel"))
|
||||
{
|
||||
entry->ui->GreenEdit->setText(QString::number((int)dmx_settings["devices"][device_idx]["green_channel"]));
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("blue_channel"))
|
||||
{
|
||||
entry->ui->BlueEdit->setText(QString::number((int)dmx_settings["devices"][device_idx]["blue_channel"]));
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("brightness_channel"))
|
||||
{
|
||||
entry->ui->BrightnessEdit->setText(QString::number((int)dmx_settings["devices"][device_idx]["brightness_channel"]));
|
||||
}
|
||||
|
||||
if(dmx_settings["devices"][device_idx].contains("keepalive_time"))
|
||||
{
|
||||
entry->ui->KeepaliveTimeEdit->setText(QString::number((int)dmx_settings["devices"][device_idx]["keepalive_time"]));
|
||||
}
|
||||
|
||||
entries.push_back(entry);
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem;
|
||||
|
||||
item->setSizeHint(entry->sizeHint());
|
||||
|
||||
ui->DMXDeviceList->addItem(item);
|
||||
ui->DMXDeviceList->setItemWidget(item, entry);
|
||||
ui->DMXDeviceList->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpenRGBDMXSettingsPage::~OpenRGBDMXSettingsPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void OpenRGBDMXSettingsPage::changeEvent(QEvent *event)
|
||||
{
|
||||
if(event->type() == QEvent::LanguageChange)
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Ui::OpenRGBDMXSettingsPage::on_AddDMXDeviceButton_clicked()
|
||||
{
|
||||
OpenRGBDMXSettingsEntry* entry = new OpenRGBDMXSettingsEntry;
|
||||
entries.push_back(entry);
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem;
|
||||
|
||||
item->setSizeHint(entry->sizeHint());
|
||||
|
||||
ui->DMXDeviceList->addItem(item);
|
||||
ui->DMXDeviceList->setItemWidget(item, entry);
|
||||
ui->DMXDeviceList->show();
|
||||
}
|
||||
|
||||
void Ui::OpenRGBDMXSettingsPage::on_RemoveDMXDeviceButton_clicked()
|
||||
{
|
||||
int cur_row = ui->DMXDeviceList->currentRow();
|
||||
|
||||
if(cur_row < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QListWidgetItem* item = ui->DMXDeviceList->takeItem(cur_row);
|
||||
|
||||
ui->DMXDeviceList->removeItemWidget(item);
|
||||
delete item;
|
||||
|
||||
delete entries[cur_row];
|
||||
entries.erase(entries.begin() + cur_row);
|
||||
}
|
||||
|
||||
void Ui::OpenRGBDMXSettingsPage::on_SaveDMXConfigurationButton_clicked()
|
||||
{
|
||||
json dmx_settings;
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Get DMX settings from settings manager |
|
||||
\*-------------------------------------------------*/
|
||||
dmx_settings = ResourceManager::get()->GetSettingsManager()->GetSettings("DMXDevices");
|
||||
|
||||
dmx_settings["devices"].clear();
|
||||
|
||||
for(unsigned int device_idx = 0; device_idx < entries.size(); device_idx++)
|
||||
{
|
||||
/*-------------------------------------------------*\
|
||||
| Required parameters |
|
||||
\*-------------------------------------------------*/
|
||||
dmx_settings["devices"][device_idx]["name"] = entries[device_idx]->ui->NameEdit->text().toStdString();
|
||||
dmx_settings["devices"][device_idx]["port"] = entries[device_idx]->ui->PortEdit->text().toStdString();
|
||||
dmx_settings["devices"][device_idx]["red_channel"] = entries[device_idx]->ui->RedEdit->text().toUInt();
|
||||
dmx_settings["devices"][device_idx]["green_channel"] = entries[device_idx]->ui->GreenEdit->text().toUInt();
|
||||
dmx_settings["devices"][device_idx]["blue_channel"] = entries[device_idx]->ui->BlueEdit->text().toUInt();
|
||||
|
||||
/*-------------------------------------------------*\
|
||||
| Optional parameters |
|
||||
\*-------------------------------------------------*/
|
||||
if(entries[device_idx]->ui->BrightnessEdit->text() != "")
|
||||
{
|
||||
dmx_settings["devices"][device_idx]["brightness_channel"] = entries[device_idx]->ui->BrightnessEdit->text().toUInt();
|
||||
}
|
||||
|
||||
if(entries[device_idx]->ui->KeepaliveTimeEdit->text() != "")
|
||||
{
|
||||
dmx_settings["devices"][device_idx]["keepalive_time"] = entries[device_idx]->ui->KeepaliveTimeEdit->text().toUInt();
|
||||
}
|
||||
}
|
||||
|
||||
ResourceManager::get()->GetSettingsManager()->SetSettings("DMXDevices", dmx_settings);
|
||||
ResourceManager::get()->GetSettingsManager()->SaveSettings();
|
||||
}
|
||||
35
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsPage.h
Normal file
35
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsPage.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef OPENRGBDMXSETTINGSPAGE_H
|
||||
#define OPENRGBDMXSETTINGSPAGE_H
|
||||
|
||||
#include "ui_OpenRGBDMXSettingsPage.h"
|
||||
#include <QWidget>
|
||||
|
||||
#include "OpenRGBDMXSettingsEntry.h"
|
||||
|
||||
namespace Ui {
|
||||
class OpenRGBDMXSettingsPage;
|
||||
}
|
||||
|
||||
class Ui::OpenRGBDMXSettingsPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit OpenRGBDMXSettingsPage(QWidget *parent = nullptr);
|
||||
~OpenRGBDMXSettingsPage();
|
||||
|
||||
private slots:
|
||||
void changeEvent(QEvent *event);
|
||||
void on_AddDMXDeviceButton_clicked();
|
||||
|
||||
void on_RemoveDMXDeviceButton_clicked();
|
||||
|
||||
void on_SaveDMXConfigurationButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::OpenRGBDMXSettingsPageUi* ui;
|
||||
std::vector<OpenRGBDMXSettingsEntry*> entries;
|
||||
|
||||
};
|
||||
|
||||
#endif // OPENRGBDMXSETTINGSPAGE_H
|
||||
49
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsPage.ui
Normal file
49
qt/OpenRGBDMXSettingsPage/OpenRGBDMXSettingsPage.ui
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>OpenRGBDMXSettingsPageUi</class>
|
||||
<widget class="QWidget" name="OpenRGBDMXSettingsPageUi">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>E131 settings page</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="AddDMXDeviceButton">
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="RemoveDMXDeviceButton">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="SaveDMXConfigurationButton">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QListWidget" name="DMXDeviceList">
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -432,6 +432,11 @@ OpenRGBDialog2::OpenRGBDialog2(QWidget *parent) : QMainWindow(parent), ui(new Op
|
|||
\*-----------------------------------------------------*/
|
||||
AddPluginsPage();
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Add the DMX settings page |
|
||||
\*-----------------------------------------------------*/
|
||||
AddDMXSettingsPage();
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Add the E1.31 settings page |
|
||||
\*-----------------------------------------------------*/
|
||||
|
|
@ -757,6 +762,34 @@ void OpenRGBDialog2::AddSettingsPage()
|
|||
connect(this, SIGNAL(ProfileListChanged()), SettingsPage, SLOT(UpdateProfiles()));
|
||||
}
|
||||
|
||||
void OpenRGBDialog2::AddDMXSettingsPage()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Create the Settings page |
|
||||
\*-----------------------------------------------------*/
|
||||
DMXSettingsPage = new OpenRGBDMXSettingsPage();
|
||||
|
||||
ui->SettingsTabBar->addTab(DMXSettingsPage, "");
|
||||
|
||||
QString SettingsLabelString;
|
||||
|
||||
if(OpenRGBThemeManager::IsDarkTheme())
|
||||
{
|
||||
SettingsLabelString = "serial_dark.png";
|
||||
}
|
||||
else
|
||||
{
|
||||
SettingsLabelString = "serial.png";
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Create the tab label |
|
||||
\*-----------------------------------------------------*/
|
||||
TabLabel* SettingsTabLabel = new TabLabel(SettingsLabelString, tr("DMX Devices"), (char *)"DMX Devices", (char *)context);
|
||||
|
||||
ui->SettingsTabBar->tabBar()->setTabButton(ui->SettingsTabBar->tabBar()->count() - 1, QTabBar::LeftSide, SettingsTabLabel);
|
||||
}
|
||||
|
||||
void OpenRGBDialog2::AddE131SettingsPage()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "OpenRGBSystemInfoPage.h"
|
||||
#include "OpenRGBSupportedDevicesPage.h"
|
||||
#include "OpenRGBSettingsPage.h"
|
||||
#include "OpenRGBDMXSettingsPage/OpenRGBDMXSettingsPage.h"
|
||||
#include "OpenRGBE131SettingsPage/OpenRGBE131SettingsPage.h"
|
||||
#include "OpenRGBElgatoKeyLightSettingsPage/OpenRGBElgatoKeyLightSettingsPage.h"
|
||||
#include "OpenRGBKasaSmartSettingsPage/OpenRGBKasaSmartSettingsPage.h"
|
||||
|
|
@ -84,6 +85,7 @@ private:
|
|||
OpenRGBSoftwareInfoPage *SoftInfoPage;
|
||||
OpenRGBSupportedDevicesPage *SupportedPage;
|
||||
OpenRGBSettingsPage *SettingsPage;
|
||||
OpenRGBDMXSettingsPage *DMXSettingsPage;
|
||||
OpenRGBE131SettingsPage *E131SettingsPage;
|
||||
OpenRGBElgatoKeyLightSettingsPage *ElgatoKeyLightSettingsPage;
|
||||
OpenRGBKasaSmartSettingsPage *KasaSmartSettingsPage;
|
||||
|
|
@ -112,6 +114,7 @@ private:
|
|||
void AddSoftwareInfoPage();
|
||||
void AddSupportedDevicesPage();
|
||||
void AddSettingsPage();
|
||||
void AddDMXSettingsPage();
|
||||
void AddE131SettingsPage();
|
||||
void AddElgatoKeyLightSettingsPage();
|
||||
void AddKasaSmartSettingsPage();
|
||||
|
|
|
|||
|
|
@ -17,9 +17,13 @@
|
|||
serial_port::serial_port()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Set a default baud rate |
|
||||
| Set default port configuration but do not open |
|
||||
\*-----------------------------------------------------*/
|
||||
baud_rate = 9600;
|
||||
baud_rate = 9600;
|
||||
parity = SERIAL_PORT_PARITY_NONE;
|
||||
size = SERIAL_PORT_SIZE_8;
|
||||
stop_bits = SERIAL_PORT_STOP_BITS_1;
|
||||
flow_control = true;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
|
|
@ -29,7 +33,44 @@ serial_port::serial_port()
|
|||
\*---------------------------------------------------------*/
|
||||
serial_port::serial_port(const char * name, unsigned int baud)
|
||||
{
|
||||
serial_open(name, baud);
|
||||
/*-----------------------------------------------------*\
|
||||
| Set default port configuration and open |
|
||||
\*-----------------------------------------------------*/
|
||||
baud_rate = baud;
|
||||
parity = SERIAL_PORT_PARITY_NONE;
|
||||
size = SERIAL_PORT_SIZE_8;
|
||||
stop_bits = SERIAL_PORT_STOP_BITS_1;
|
||||
flow_control = true;
|
||||
|
||||
serial_open(name);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_port (constructor) |
|
||||
| When created with port information, the constructor |
|
||||
| will automatically open port <name> at baud rate <baud>|
|
||||
| with the given port configuration |
|
||||
\*---------------------------------------------------------*/
|
||||
serial_port::serial_port
|
||||
(
|
||||
const char * name,
|
||||
unsigned int baud,
|
||||
serial_port_parity parity,
|
||||
serial_port_size size,
|
||||
serial_port_stop_bits stop_bits,
|
||||
bool flow_control
|
||||
)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Set default port configuration and open |
|
||||
\*-----------------------------------------------------*/
|
||||
this->baud_rate = baud;
|
||||
this->parity = parity;
|
||||
this->size = size;
|
||||
this->stop_bits = stop_bits;
|
||||
this->flow_control = flow_control;
|
||||
|
||||
serial_open(name);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
|
|
@ -58,6 +99,9 @@ bool serial_port::serial_open()
|
|||
char full_path[100];
|
||||
snprintf(full_path, sizeof(full_path), "\\\\.\\%s", port_name);
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Open the port read/write |
|
||||
\*-----------------------------------------*/
|
||||
file_descriptor = CreateFile(full_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if((int)file_descriptor < 0)
|
||||
|
|
@ -65,29 +109,106 @@ bool serial_port::serial_open()
|
|||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Get the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
SetupComm(file_descriptor, 1, 128);
|
||||
GetCommState(file_descriptor, &dcb);
|
||||
|
||||
dcb.BaudRate = baud_rate; //Set baud rate
|
||||
dcb.ByteSize = 8; //8 data bits
|
||||
dcb.Parity = NOPARITY; //Parity = none
|
||||
dcb.StopBits = ONESTOPBIT; //One stop bit
|
||||
dcb.fAbortOnError = TRUE; //Abort on error
|
||||
/*-----------------------------------------*\
|
||||
| Configure baud rate |
|
||||
\*-----------------------------------------*/
|
||||
dcb.BaudRate = baud_rate;
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure parity |
|
||||
\*-----------------------------------------*/
|
||||
switch(parity)
|
||||
{
|
||||
case SERIAL_PORT_PARITY_NONE:
|
||||
dcb.Parity = NOPARITY;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_PARITY_ODD:
|
||||
dcb.Parity = ODDPARITY;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_PARITY_EVEN:
|
||||
dcb.Parity = EVENPARITY;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure size |
|
||||
\*-----------------------------------------*/
|
||||
switch(size)
|
||||
{
|
||||
case SERIAL_PORT_SIZE_8:
|
||||
dcb.ByteSize = 8;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_7:
|
||||
dcb.ByteSize = 7;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_6:
|
||||
dcb.ByteSize = 6;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_5:
|
||||
dcb.ByteSize = 5;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure stop bits |
|
||||
\*-----------------------------------------*/
|
||||
if(stop_bits == SERIAL_PORT_STOP_BITS_2)
|
||||
{
|
||||
dcb.StopBits = TWOSTOPBITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure flow control |
|
||||
\*-----------------------------------------*/
|
||||
if(flow_control)
|
||||
{
|
||||
dcb.fRtsControl = RTS_CONTROL_ENABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure additional parameters |
|
||||
\*-----------------------------------------*/
|
||||
dcb.fAbortOnError = FALSE; //Abort on error
|
||||
dcb.fOutX = FALSE; //XON/XOFF off for transmit
|
||||
dcb.fInX = FALSE; //XON/XOFF off for receive
|
||||
dcb.fOutxCtsFlow = FALSE; //Turn off CTS flow control
|
||||
dcb.fRtsControl = RTS_CONTROL_DISABLE; //Options DISABLE, ENABLE, HANDSHAKE
|
||||
dcb.fOutxDsrFlow = FALSE; //Turn off DSR flow control
|
||||
dcb.fDtrControl = DTR_CONTROL_DISABLE; //Disable DTR control
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Set the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
SetCommState(file_descriptor, &dcb);
|
||||
|
||||
COMMTIMEOUTS timeouts = {0};
|
||||
timeouts.ReadIntervalTimeout = 50;
|
||||
timeouts.ReadTotalTimeoutConstant=50;
|
||||
timeouts.ReadTotalTimeoutMultiplier=10;
|
||||
timeouts.WriteTotalTimeoutConstant=50;
|
||||
timeouts.WriteTotalTimeoutMultiplier=10;
|
||||
/*-----------------------------------------*\
|
||||
| Set the port timeouts |
|
||||
\*-----------------------------------------*/
|
||||
COMMTIMEOUTS timeouts = {0};
|
||||
timeouts.ReadIntervalTimeout = 50;
|
||||
timeouts.ReadTotalTimeoutConstant = 50;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 10;
|
||||
timeouts.WriteTotalTimeoutConstant = 50;
|
||||
timeouts.WriteTotalTimeoutMultiplier = 10;
|
||||
|
||||
SetCommTimeouts(file_descriptor, &timeouts);
|
||||
#endif
|
||||
|
||||
|
|
@ -95,6 +216,9 @@ bool serial_port::serial_open()
|
|||
| Linux-specific code path for serial port opening |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __linux__
|
||||
/*-----------------------------------------*\
|
||||
| Open the port read/write with no delay |
|
||||
\*-----------------------------------------*/
|
||||
file_descriptor = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
|
||||
if(file_descriptor < 0)
|
||||
|
|
@ -102,19 +226,105 @@ bool serial_port::serial_open()
|
|||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Get the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
struct termios2 options;
|
||||
ioctl(file_descriptor, TCGETS2, &options);
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure baud rate |
|
||||
\*-----------------------------------------*/
|
||||
options.c_cflag &= ~CBAUD;
|
||||
options.c_cflag |= BOTHER;
|
||||
options.c_cflag |= CBAUDEX;
|
||||
|
||||
options.c_ispeed = baud_rate;
|
||||
options.c_ospeed = baud_rate;
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure parity |
|
||||
\*-----------------------------------------*/
|
||||
switch(parity)
|
||||
{
|
||||
case SERIAL_PORT_PARITY_NONE:
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_PARITY_ODD:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag |= PARODD;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_PARITY_EVEN:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure size |
|
||||
\*-----------------------------------------*/
|
||||
options.c_cflag &= ~CSIZE;
|
||||
|
||||
switch(size)
|
||||
{
|
||||
case SERIAL_PORT_SIZE_8:
|
||||
options.c_cflag |= CS8;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_7:
|
||||
options.c_cflag |= CS7;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_6:
|
||||
options.c_cflag |= CS6;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_5:
|
||||
options.c_cflag |= CS5;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure stop bits |
|
||||
\*-----------------------------------------*/
|
||||
if(stop_bits == SERIAL_PORT_STOP_BITS_2)
|
||||
{
|
||||
options.c_cflag |= CSTOPB;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure flow control |
|
||||
\*-----------------------------------------*/
|
||||
if(flow_control)
|
||||
{
|
||||
options.c_cflag |= CRTSCTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.c_cflag &= ~CRTSCTS;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure additional parameters |
|
||||
\*-----------------------------------------*/
|
||||
options.c_lflag &= ~ICANON;
|
||||
options.c_lflag &= ~ECHO; // Disable echo
|
||||
options.c_lflag &= ~ECHOE; // Disable erasure
|
||||
options.c_lflag &= ~ECHONL; // Disable new-line echo
|
||||
options.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
|
||||
|
||||
options.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
|
||||
options.c_ispeed = baud_rate;
|
||||
options.c_ospeed = baud_rate;
|
||||
options.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Set the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
ioctl(file_descriptor, TCSETS2, &options);
|
||||
#endif
|
||||
|
||||
|
|
@ -122,6 +332,9 @@ bool serial_port::serial_open()
|
|||
| MacOS-specific code path for serial port opening |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __APPLE__
|
||||
/*-----------------------------------------*\
|
||||
| Open the port read/write with no delay |
|
||||
\*-----------------------------------------*/
|
||||
file_descriptor = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
|
||||
if(file_descriptor < 0)
|
||||
|
|
@ -129,53 +342,107 @@ bool serial_port::serial_open()
|
|||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Get the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
struct termios options;
|
||||
tcgetattr(file_descriptor, &options);
|
||||
switch(baud_rate)
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure parity |
|
||||
\*-----------------------------------------*/
|
||||
switch(parity)
|
||||
{
|
||||
case 9600:
|
||||
cfsetispeed(&options, B9600);
|
||||
cfsetospeed(&options, B9600);
|
||||
case SERIAL_PORT_PARITY_NONE:
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
break;
|
||||
case 19200:
|
||||
cfsetispeed(&options, B19200);
|
||||
cfsetospeed(&options, B19200);
|
||||
|
||||
case SERIAL_PORT_PARITY_ODD:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag |= PARODD;
|
||||
break;
|
||||
case 115200:
|
||||
cfsetispeed(&options, B115200);
|
||||
cfsetospeed(&options, B115200);
|
||||
break;
|
||||
case 38400:
|
||||
cfsetispeed(&options, B38400);
|
||||
cfsetospeed(&options, B38400);
|
||||
break;
|
||||
case 57600:
|
||||
cfsetispeed(&options, B57600);
|
||||
cfsetospeed(&options, B57600);
|
||||
break;
|
||||
default:
|
||||
cfsetispeed(&options, B9600);
|
||||
cfsetospeed(&options, B9600);
|
||||
|
||||
case SERIAL_PORT_PARITY_EVEN:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Configure other settings |
|
||||
\*-----------------------------------------------------*/
|
||||
/*-----------------------------------------*\
|
||||
| Configure size |
|
||||
\*-----------------------------------------*/
|
||||
options.c_cflag &= ~CSIZE;
|
||||
|
||||
switch(size)
|
||||
{
|
||||
case SERIAL_PORT_SIZE_8:
|
||||
options.c_cflag |= CS8;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_7:
|
||||
options.c_cflag |= CS7;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_6:
|
||||
options.c_cflag |= CS6;
|
||||
break;
|
||||
|
||||
case SERIAL_PORT_SIZE_5:
|
||||
options.c_cflag |= CS5;
|
||||
break;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure stop bits |
|
||||
\*-----------------------------------------*/
|
||||
if(stop_bits == SERIAL_PORT_STOP_BITS_2)
|
||||
{
|
||||
options.c_cflag |= CSTOPB;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure flow control |
|
||||
\*-----------------------------------------*/
|
||||
if(flow_control)
|
||||
{
|
||||
options.c_cflag |= CRTSCTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.c_cflag &= ~CRTSCTS;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure additional parameters |
|
||||
\*-----------------------------------------*/
|
||||
options.c_lflag &= ~(ICANON | ISIG | ECHO);
|
||||
|
||||
options.c_iflag &= ~(INLCR | ICRNL);
|
||||
options.c_iflag |= IGNPAR | IGNBRK;
|
||||
|
||||
options.c_oflag &= ~(OPOST | ONLCR | OCRNL);
|
||||
options.c_cflag &= ~(PARENB | PARODD | CSTOPB | CSIZE | CRTSCTS);
|
||||
options.c_cflag |= CLOCAL | CREAD | CS8;
|
||||
options.c_lflag &= ~(ICANON | ISIG | ECHO);
|
||||
|
||||
options.c_cc[VTIME] = 1;
|
||||
options.c_cc[VMIN] = 0;
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Set the port configuration options |
|
||||
\*-----------------------------------------*/
|
||||
if(tcsetattr(file_descriptor, TCSANOW, &options) < 0)
|
||||
{
|
||||
close(file_descriptor);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------*\
|
||||
| Configure baud rate |
|
||||
\*-----------------------------------------*/
|
||||
ioctl(file_descriptor, IOSSIOSPEED, &baud_rate);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
|
|
@ -357,3 +624,85 @@ void serial_port::serial_flush_tx()
|
|||
tcflush(file_descriptor, TCOFLUSH);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| serial_break |
|
||||
\*---------------------------------------------------------*/
|
||||
void serial_port::serial_break()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Windows-specific code path for serial break |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
SetCommBreak(file_descriptor);
|
||||
Sleep(1);
|
||||
ClearCommBreak(file_descriptor);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Linux-specific code path for serial break |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __linux__
|
||||
//Send break for at least 1 ms
|
||||
ioctl(file_descriptor, TIOCSBRK);
|
||||
usleep(1000);
|
||||
ioctl(file_descriptor, TIOCCBRK);
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| MacOS-specific code path for serial break |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __APPLE__
|
||||
//Send break for at least 1 ms
|
||||
ioctl(file_descriptor, TIOCSBRK);
|
||||
usleep(1000);
|
||||
ioctl(file_descriptor, TIOCCBRK);
|
||||
#endif
|
||||
}
|
||||
|
||||
void serial_port::serial_set_rts(bool rts)
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Windows-specific code path for serial set RTS |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
if(rts)
|
||||
{
|
||||
EscapeCommFunction(file_descriptor, SETRTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
EscapeCommFunction(file_descriptor, CLRRTS);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Linux-specific code path for serial set RTS |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __linux__
|
||||
const int RTSFLAG = TIOCM_RTS;
|
||||
if(rts)
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIS, &RTSFLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIC, &RTSFLAG);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| MacOS-specific code path for serial set RTS |
|
||||
\*-----------------------------------------------------*/
|
||||
#ifdef __APPLE__
|
||||
const int RTSFLAG = TIOCM_RTS;
|
||||
if(rts)
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIS, &RTSFLAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
ioctl(file_descriptor, TIOCMBIC, &RTSFLAG);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +58,37 @@
|
|||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <IOKit/serial/ioss.h>
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Serial Port Enums |
|
||||
\*-------------------------------------------------------------------------*/
|
||||
typedef unsigned int serial_port_parity;
|
||||
enum
|
||||
{
|
||||
SERIAL_PORT_PARITY_NONE = 0, /* No parity */
|
||||
SERIAL_PORT_PARITY_ODD = 1, /* Odd parity */
|
||||
SERIAL_PORT_PARITY_EVEN = 2, /* Even parity */
|
||||
};
|
||||
|
||||
typedef unsigned int serial_port_size;
|
||||
enum
|
||||
{
|
||||
SERIAL_PORT_SIZE_8 = 0, /* 8 bits per byte */
|
||||
SERIAL_PORT_SIZE_7 = 1, /* 7 bits per byte */
|
||||
SERIAL_PORT_SIZE_6 = 2, /* 6 bits per byte */
|
||||
SERIAL_PORT_SIZE_5 = 3, /* 5 bits per byte */
|
||||
};
|
||||
|
||||
typedef unsigned int serial_port_stop_bits;
|
||||
enum
|
||||
{
|
||||
SERIAL_PORT_STOP_BITS_1 = 0, /* 1 stop bit */
|
||||
SERIAL_PORT_STOP_BITS_2 = 1, /* 2 stop bits */
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
| Serial Port Class |
|
||||
| The reason for this class is that serial ports are treated differently |
|
||||
|
|
@ -72,6 +100,12 @@ class serial_port
|
|||
public:
|
||||
serial_port();
|
||||
serial_port(const char * name, unsigned int baud);
|
||||
serial_port(const char * name,
|
||||
unsigned int baud,
|
||||
serial_port_parity parity,
|
||||
serial_port_size size,
|
||||
serial_port_stop_bits stop_bits,
|
||||
bool flow_control);
|
||||
|
||||
~serial_port();
|
||||
|
||||
|
|
@ -90,12 +124,19 @@ public:
|
|||
|
||||
void serial_flush_rx();
|
||||
void serial_flush_tx();
|
||||
void serial_break();
|
||||
|
||||
void serial_set_rts(bool rts);
|
||||
|
||||
int serial_available();
|
||||
|
||||
private:
|
||||
char port_name[1024];
|
||||
unsigned int baud_rate;
|
||||
char port_name[1024];
|
||||
unsigned int baud_rate;
|
||||
serial_port_parity parity;
|
||||
serial_port_size size;
|
||||
serial_port_stop_bits stop_bits;
|
||||
bool flow_control;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE file_descriptor;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue