Files
LedBars/RpiLedBars/src/artnet/ArtnetnodeWifi.cpp
2021-07-24 00:09:43 +01:00

316 lines
6.7 KiB
C++

/*
Copyright (c) Charles Yarnold charlesyarnold@gmail.com 2015
Copyright (c) 2016-2020 Stephan Ruloff
https://github.com/rstephan/ArtnetnodeWifi
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, under version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ArtnetnodeWifi.h>
const char ArtnetnodeWifi::artnetId[] = ARTNET_ID;
ArtnetnodeWifi::ArtnetnodeWifi()
{
// Initalise DMXOutput array
for (int i = 0; i < DMX_MAX_OUTPUTS; i++) {
DMXOutputs[i][0] = 0xFF;
DMXOutputs[i][1] = 0xFF;
DMXOutputs[i][2] = 0;
}
// Start DMX tick clock
msSinceDMXSend = 0;
// Init DMX buffers
for (int i = 0; i < DMX_MAX_OUTPUTS; i++) {
memset(DMXBuffer[i], 0, sizeof(DMXBuffer[i]));
}
sequence = 1;
physical = 0;
outgoingUniverse = 0;
dmxDataLength = 0;
}
/**
@retval 0 Ok
*/
uint8_t ArtnetnodeWifi::begin(String hostname)
{
byte mac[6];
Udp.begin(ARTNET_PORT);
localIP = WiFi.localIP();
localMask = WiFi.subnetMask();
localBroadcast = IPAddress((uint32_t)localIP | ~(uint32_t)localMask);
WiFi.macAddress(mac);
PollReplyPacket.setMac(mac);
PollReplyPacket.setIP(localIP);
PollReplyPacket.canDHCP(true);
PollReplyPacket.isDHCP(true);
host = hostname;
return 0;
}
void ArtnetnodeWifi::setShortName(const char name[])
{
PollReplyPacket.setShortName(name);
}
void ArtnetnodeWifi::setLongName(const char name[])
{
PollReplyPacket.setLongName(name);
}
void ArtnetnodeWifi::setName(const char name[])
{
PollReplyPacket.setShortName(name);
PollReplyPacket.setLongName(name);
}
void ArtnetnodeWifi::setNumPorts(uint8_t num)
{
PollReplyPacket.setNumPorts(num);
}
void ArtnetnodeWifi::setStartingUniverse(uint16_t startingUniverse)
{
PollReplyPacket.setStartingUniverse(startingUniverse);
}
uint16_t ArtnetnodeWifi::read()
{
uint8_t startcode;
packetSize = Udp.parsePacket();
if (packetSize <= ARTNET_MAX_BUFFER && packetSize > 0) {
Udp.read(artnetPacket, ARTNET_MAX_BUFFER);
// Check that packetID is "Art-Net" else ignore
if (memcmp(artnetPacket, artnetId, sizeof(artnetId)) != 0) {
return 0;
}
opcode = artnetPacket[8] | artnetPacket[9] << 8;
switch (opcode) {
case OpDmx:
return handleDMX(0);
case OpPoll:
return handlePollRequest();
case OpNzs:
startcode = artnetPacket[13];
if (startcode != 0 && startcode != DMX_RDM_STARTCODE) {
return handleDMX(startcode);
}
}
return opcode;
}
return 0;
}
uint16_t ArtnetnodeWifi::makePacket(void)
{
uint16_t len;
uint16_t version;
memcpy(artnetPacket, artnetId, sizeof(artnetId));
opcode = OpDmx;
artnetPacket[8] = opcode;
artnetPacket[9] = opcode >> 8;
version = 14;
artnetPacket[10] = version >> 8;
artnetPacket[11] = version;
artnetPacket[12] = sequence;
sequence++;
if (!sequence) {
sequence = 1;
}
artnetPacket[13] = physical;
artnetPacket[14] = outgoingUniverse;
artnetPacket[15] = outgoingUniverse >> 8;
len = dmxDataLength + (dmxDataLength % 2); // make an even number
artnetPacket[16] = len >> 8;
artnetPacket[17] = len;
return len;
}
int ArtnetnodeWifi::write(void)
{
uint16_t len;
len = makePacket();
Udp.beginPacket(host.c_str(), ARTNET_PORT);
Udp.write(artnetPacket, ARTNET_DMX_START_LOC + len);
return Udp.endPacket();
}
int ArtnetnodeWifi::write(IPAddress ip)
{
uint16_t len;
len = makePacket();
Udp.beginPacket(ip, ARTNET_PORT);
Udp.write(artnetPacket, ARTNET_DMX_START_LOC + len);
return Udp.endPacket();
}
void ArtnetnodeWifi::setByte(uint16_t pos, uint8_t value)
{
if (pos > 512) {
return;
}
artnetPacket[ARTNET_DMX_START_LOC + pos] = value;
}
bool ArtnetnodeWifi::isBroadcast()
{
if (Udp.remoteIP() == localBroadcast){
return true;
} else {
return false;
}
}
uint16_t ArtnetnodeWifi::handleDMX(uint8_t nzs)
{
if (isBroadcast()) {
return 0;
} else {
// Get universe
uint16_t universe = artnetPacket[14] | artnetPacket[15] << 8;
// Get DMX frame length
uint16_t dmxDataLength = artnetPacket[17] | artnetPacket[16] << 8;
// Sequence
uint8_t sequence = artnetPacket[12];
if (artDmxCallback) {
(*artDmxCallback)(universe, dmxDataLength, sequence, artnetPacket + ARTNET_DMX_START_LOC);
}
for(int a = 0; a < DMX_MAX_OUTPUTS; a++){
if(DMXOutputs[a][1] == universe){
for (int i = 0 ; i < DMX_MAX_BUFFER ; i++){
if(i < dmxDataLength){
DMXBuffer[a][i] = artnetPacket[i+ARTNET_DMX_START_LOC];
}
else{
DMXBuffer[a][i] = 0;
}
}
}
}
if (nzs) {
return OpNzs;
} else {
return OpDmx;
}
}
}
uint16_t ArtnetnodeWifi::handlePollRequest()
{
if (1 || isBroadcast()) {
Udp.beginPacket(localBroadcast, ARTNET_PORT);
Udp.write(PollReplyPacket.printPacket(), sizeof(PollReplyPacket.packet));
Udp.endPacket();
return OpPoll;
} else{
return 0;
}
}
void ArtnetnodeWifi::enableDMX()
{
DMXOutputStatus = true;
}
void ArtnetnodeWifi::disableDMX()
{
DMXOutputStatus = false;
}
void ArtnetnodeWifi::enableDMXOutput(uint8_t outputID)
{
DMXOutputs[outputID][2] = 1;
int numEnabled = 0;
for(int i = 0; i < DMX_MAX_OUTPUTS; i++){
if(DMXOutputs[i][2]==1){
if(numEnabled<4){
numEnabled++;
}
}
}
PollReplyPacket.setNumPorts(numEnabled);
PollReplyPacket.setOutputEnabled(outputID);
}
void ArtnetnodeWifi::disableDMXOutput(uint8_t outputID)
{
DMXOutputs[outputID][2] = 0;
int numEnabled = 0;
for(int i = 0; i < DMX_MAX_OUTPUTS; i++){
if(DMXOutputs[i][2]==1){
if(numEnabled<4){
numEnabled++;
}
}
}
PollReplyPacket.setNumPorts(numEnabled);
PollReplyPacket.setOutputDisabled(outputID);
}
uint8_t ArtnetnodeWifi::setDMXOutput(uint8_t outputID, uint8_t uartNum, uint16_t attachedUniverse)
{
// Validate input
if(outputID < DMX_MAX_OUTPUTS && uartNum != 0xFF && attachedUniverse != 0xFF){
DMXOutputs[outputID][0] = uartNum;
DMXOutputs[outputID][1] = attachedUniverse;
DMXOutputs[outputID][2] = 0;
PollReplyPacket.setSwOut(outputID, attachedUniverse);
return 1;
} else {
return 0;
}
}
void ArtnetnodeWifi::tickDMX(uint32_t time)
{
msSinceDMXSend += time;
if(msSinceDMXSend > DMX_MS_BETWEEN_TICKS){
sendDMX();
msSinceDMXSend = 0;
}
}