http://mbed.org/users/okini3939/notebook/art-net/
Dependents: ArtNode ArtNode DMXStation ArtNodeLED ... more
DmxArtNet.cpp@2:0753f1ed1dec, 2019-09-13 (annotated)
- Committer:
- okini3939
- Date:
- Fri Sep 13 06:16:58 2019 +0000
- Revision:
- 2:0753f1ed1dec
- Parent:
- 1:c59dc374fc64
- Child:
- 3:89aa639c946a
fix multi universe
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
okini3939 | 0:629617d401de | 1 | /* |
okini3939 | 0:629617d401de | 2 | * Control Art-Net from freepascal & delphi |
okini3939 | 0:629617d401de | 3 | * (c) Rowan Maclachlan (hippy) rowanmac@optusnet.com.au [15d/01m/06y] |
okini3939 | 0:629617d401de | 4 | * |
okini3939 | 0:629617d401de | 5 | * Free for personal not-for-profit use only, please contact me if you are |
okini3939 | 0:629617d401de | 6 | * using it in a commercial product, as i would like a copy :) |
okini3939 | 0:629617d401de | 7 | * |
okini3939 | 0:629617d401de | 8 | * http://members.westnet.com.au/rowanmac/ |
okini3939 | 0:629617d401de | 9 | * |
okini3939 | 2:0753f1ed1dec | 10 | * for mbed ported by Suga 2011, 2017 |
okini3939 | 0:629617d401de | 11 | */ |
okini3939 | 0:629617d401de | 12 | |
okini3939 | 0:629617d401de | 13 | /** @file |
okini3939 | 0:629617d401de | 14 | */ |
okini3939 | 0:629617d401de | 15 | |
okini3939 | 0:629617d401de | 16 | #include "mbed.h" |
okini3939 | 2:0753f1ed1dec | 17 | #include "EthernetInterface.h" |
okini3939 | 0:629617d401de | 18 | #include "DmxArtNet.h" |
okini3939 | 0:629617d401de | 19 | #include <stdio.h> |
okini3939 | 0:629617d401de | 20 | #include <string.h> |
okini3939 | 0:629617d401de | 21 | |
okini3939 | 2:0753f1ed1dec | 22 | //#define DEBUG |
okini3939 | 2:0753f1ed1dec | 23 | #ifdef DEBUG |
okini3939 | 2:0753f1ed1dec | 24 | #define DBG(...) printf("" __VA_ARGS__) |
okini3939 | 2:0753f1ed1dec | 25 | #else |
okini3939 | 2:0753f1ed1dec | 26 | #define DBG(...) |
okini3939 | 2:0753f1ed1dec | 27 | #endif |
okini3939 | 2:0753f1ed1dec | 28 | |
okini3939 | 2:0753f1ed1dec | 29 | /* |
okini3939 | 0:629617d401de | 30 | // host to network short |
okini3939 | 0:629617d401de | 31 | #define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) ) |
okini3939 | 0:629617d401de | 32 | #define ntohs( x ) htons(x) |
okini3939 | 0:629617d401de | 33 | // host to network long |
okini3939 | 0:629617d401de | 34 | #define htonl( x ) ( (( (x) << 24 ) & 0xFF000000) \ |
okini3939 | 0:629617d401de | 35 | | (( (x) << 8 ) & 0x00FF0000) \ |
okini3939 | 0:629617d401de | 36 | | (( (x) >> 8 ) & 0x0000FF00) \ |
okini3939 | 0:629617d401de | 37 | | (( (x) >> 24 ) & 0x000000FF) ) |
okini3939 | 0:629617d401de | 38 | #define ntohl( x ) htonl(x) |
okini3939 | 2:0753f1ed1dec | 39 | */ |
okini3939 | 0:629617d401de | 40 | |
okini3939 | 0:629617d401de | 41 | extern "C" void mbed_mac_address(char *s); |
okini3939 | 0:629617d401de | 42 | |
okini3939 | 0:629617d401de | 43 | |
okini3939 | 2:0753f1ed1dec | 44 | DmxArtNet::DmxArtNet () { |
okini3939 | 2:0753f1ed1dec | 45 | BindIpAddress[0] = 0; |
okini3939 | 2:0753f1ed1dec | 46 | BCastAddress[0] = 0; |
okini3939 | 2:0753f1ed1dec | 47 | Init_ArtDMX(); |
okini3939 | 2:0753f1ed1dec | 48 | InitArtPollReplyDefaults(); |
okini3939 | 2:0753f1ed1dec | 49 | } |
okini3939 | 2:0753f1ed1dec | 50 | |
okini3939 | 0:629617d401de | 51 | // function to make a word (16bit) from two bytes (2 x 8bit) |
okini3939 | 0:629617d401de | 52 | int DmxArtNet::makeword16 (int lsb, int msb) { |
okini3939 | 0:629617d401de | 53 | return (msb << 8) + lsb; |
okini3939 | 0:629617d401de | 54 | } |
okini3939 | 0:629617d401de | 55 | |
okini3939 | 0:629617d401de | 56 | // report a socket error, halt program |
okini3939 | 0:629617d401de | 57 | void DmxArtNet::SocketErrorOccured (char *proc) { |
okini3939 | 0:629617d401de | 58 | LError = 1; |
okini3939 | 0:629617d401de | 59 | snprintf(LErrorString, sizeof(LErrorString), "socket> error occured in '%s'\r\n", proc); |
okini3939 | 0:629617d401de | 60 | DBG("%s", LErrorString); |
okini3939 | 0:629617d401de | 61 | } |
okini3939 | 0:629617d401de | 62 | |
okini3939 | 0:629617d401de | 63 | // clear error |
okini3939 | 0:629617d401de | 64 | void DmxArtNet::ClearError () { |
okini3939 | 0:629617d401de | 65 | LError = 0; |
okini3939 | 0:629617d401de | 66 | } |
okini3939 | 0:629617d401de | 67 | |
okini3939 | 0:629617d401de | 68 | int DmxArtNet::Init () { |
okini3939 | 0:629617d401de | 69 | int i; |
okini3939 | 2:0753f1ed1dec | 70 | int err; |
okini3939 | 0:629617d401de | 71 | |
okini3939 | 2:0753f1ed1dec | 72 | rxlen = 0; |
okini3939 | 2:0753f1ed1dec | 73 | cb_ArtParser = NULL; |
okini3939 | 0:629617d401de | 74 | LError = 0; // no error yet :) |
okini3939 | 2:0753f1ed1dec | 75 | LastRecievedUniverse = 0; |
okini3939 | 2:0753f1ed1dec | 76 | |
okini3939 | 2:0753f1ed1dec | 77 | // Init_ArtDMX(); // initialize ArtDmx structure |
okini3939 | 0:629617d401de | 78 | |
okini3939 | 2:0753f1ed1dec | 79 | if (BindIpAddress[0] == 0) { |
okini3939 | 2:0753f1ed1dec | 80 | char mac[6]; |
okini3939 | 2:0753f1ed1dec | 81 | mbed_mac_address(mac); |
okini3939 | 2:0753f1ed1dec | 82 | sprintf(BindIpAddress, "%d.%d.%d.%d", 2, mac[3], mac[4], mac[5]); |
okini3939 | 2:0753f1ed1dec | 83 | strcpy(SubNetMask, "255.0.0.0"); |
okini3939 | 0:629617d401de | 84 | } |
okini3939 | 2:0753f1ed1dec | 85 | if (BCastAddress[0] == 0) { |
okini3939 | 2:0753f1ed1dec | 86 | bcast(BCastAddress, BindIpAddress, SubNetMask); |
okini3939 | 2:0753f1ed1dec | 87 | } |
okini3939 | 2:0753f1ed1dec | 88 | RemoteSin.set_address(BCastAddress, ArtUDPPort); |
okini3939 | 2:0753f1ed1dec | 89 | |
okini3939 | 2:0753f1ed1dec | 90 | err = _art.bind(ArtUDPPort); |
okini3939 | 0:629617d401de | 91 | if (err) { |
okini3939 | 0:629617d401de | 92 | SocketErrorOccured("Bind error"); |
okini3939 | 0:629617d401de | 93 | return -1; |
okini3939 | 0:629617d401de | 94 | } |
okini3939 | 2:0753f1ed1dec | 95 | // _art.set_broadcasting(true); |
okini3939 | 0:629617d401de | 96 | |
okini3939 | 2:0753f1ed1dec | 97 | int ip[4]; |
okini3939 | 2:0753f1ed1dec | 98 | sscanf(BindIpAddress, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]); |
okini3939 | 2:0753f1ed1dec | 99 | for (i = 0; i < 4; i ++) { |
okini3939 | 2:0753f1ed1dec | 100 | localaddr.IP[i] = ip[i]; |
okini3939 | 2:0753f1ed1dec | 101 | } |
okini3939 | 2:0753f1ed1dec | 102 | localaddr.Port = ArtUDPPort; |
okini3939 | 2:0753f1ed1dec | 103 | ArtPollReply.Addr = localaddr; |
okini3939 | 0:629617d401de | 104 | |
okini3939 | 2:0753f1ed1dec | 105 | for (i = 0; i < ArtMaxUniv; i ++) { |
okini3939 | 2:0753f1ed1dec | 106 | // DmxIn[i] = new unsigned char[DMX_SIZE]; |
okini3939 | 2:0753f1ed1dec | 107 | DmxIn[i] = (unsigned char*)malloc(DMX_SIZE); |
okini3939 | 2:0753f1ed1dec | 108 | memset(DmxIn[i], 0, DMX_SIZE); |
okini3939 | 2:0753f1ed1dec | 109 | } |
okini3939 | 2:0753f1ed1dec | 110 | |
okini3939 | 2:0753f1ed1dec | 111 | thread = new Thread(&DmxArtNet::task_UDPSocket, (void*)this, osPriorityNormal, 1024*4); |
okini3939 | 0:629617d401de | 112 | |
okini3939 | 0:629617d401de | 113 | return 0; |
okini3939 | 0:629617d401de | 114 | } |
okini3939 | 0:629617d401de | 115 | |
okini3939 | 2:0753f1ed1dec | 116 | void DmxArtNet::task_UDPSocket (void const *arg) { |
okini3939 | 2:0753f1ed1dec | 117 | DmxArtNet *inst = (DmxArtNet*)arg; |
okini3939 | 2:0753f1ed1dec | 118 | |
okini3939 | 2:0753f1ed1dec | 119 | inst->on_UDPSocketEvent(); |
okini3939 | 2:0753f1ed1dec | 120 | } |
okini3939 | 2:0753f1ed1dec | 121 | |
okini3939 | 2:0753f1ed1dec | 122 | void DmxArtNet::on_UDPSocketEvent () { |
okini3939 | 2:0753f1ed1dec | 123 | int n; |
okini3939 | 2:0753f1ed1dec | 124 | |
okini3939 | 2:0753f1ed1dec | 125 | for (;;) { |
okini3939 | 2:0753f1ed1dec | 126 | Work(); |
okini3939 | 2:0753f1ed1dec | 127 | |
okini3939 | 2:0753f1ed1dec | 128 | n = _art.receiveFrom(RemoteSin, (char*)buf, sizeof(buf)); |
okini3939 | 2:0753f1ed1dec | 129 | if (n < 0) break; |
okini3939 | 2:0753f1ed1dec | 130 | if (n == 0) continue; |
okini3939 | 2:0753f1ed1dec | 131 | rxlen = n; |
okini3939 | 0:629617d401de | 132 | } |
okini3939 | 0:629617d401de | 133 | } |
okini3939 | 0:629617d401de | 134 | |
okini3939 | 0:629617d401de | 135 | int DmxArtNet::Work() { |
okini3939 | 2:0753f1ed1dec | 136 | int i, n; |
okini3939 | 2:0753f1ed1dec | 137 | struct ArtPacketHeader *ArtHead = (ArtPacketHeader*)buf; |
okini3939 | 0:629617d401de | 138 | |
okini3939 | 0:629617d401de | 139 | if (rxlen >= sizeof(ArtPacketHeader)) { |
okini3939 | 0:629617d401de | 140 | // retreive the packet header |
okini3939 | 0:629617d401de | 141 | |
okini3939 | 0:629617d401de | 142 | // if looback disabled |
okini3939 | 2:0753f1ed1dec | 143 | if (strcmp(RemoteSin.get_address(), BindIpAddress) == NULL) { |
okini3939 | 0:629617d401de | 144 | DBG("ArtNet> loopback detected\r\n"); |
okini3939 | 0:629617d401de | 145 | |
okini3939 | 0:629617d401de | 146 | rxlen = 0; |
okini3939 | 0:629617d401de | 147 | return 0; // don't read packets |
okini3939 | 0:629617d401de | 148 | // which we sent! |
okini3939 | 0:629617d401de | 149 | } |
okini3939 | 0:629617d401de | 150 | |
okini3939 | 2:0753f1ed1dec | 151 | // confirm is vaild art-net packet |
okini3939 | 2:0753f1ed1dec | 152 | if (strncmp(ArtHead->ID, ArtHeaderID, 8) != 0) { |
okini3939 | 2:0753f1ed1dec | 153 | rxlen = 0; |
okini3939 | 2:0753f1ed1dec | 154 | return 0; |
okini3939 | 2:0753f1ed1dec | 155 | } |
okini3939 | 2:0753f1ed1dec | 156 | |
okini3939 | 2:0753f1ed1dec | 157 | DBG("ArtNet> RX: %d OpCode: %04x\r\n", rxlen, ArtHead->OpCode); |
okini3939 | 0:629617d401de | 158 | |
okini3939 | 2:0753f1ed1dec | 159 | switch (ArtHead->OpCode) { // determine packet type |
okini3939 | 0:629617d401de | 160 | |
okini3939 | 2:0753f1ed1dec | 161 | case OP_Output: // 0x5000 An ArtDMX Packet, containts dmx universe |
okini3939 | 2:0753f1ed1dec | 162 | if (rxlen >= sizeof(struct ArtDMX_Packet) - (DMX_SIZE - 2)) { |
okini3939 | 2:0753f1ed1dec | 163 | struct ArtDMX_Packet *artdmx = (struct ArtDMX_Packet*)buf; |
okini3939 | 2:0753f1ed1dec | 164 | |
okini3939 | 2:0753f1ed1dec | 165 | // check data length |
okini3939 | 2:0753f1ed1dec | 166 | if (ntohs(artdmx->Length) > DMX_SIZE || (artdmx->Universes & 0x7ff0) != (NetSwitch & 0x7ff0)) { |
okini3939 | 2:0753f1ed1dec | 167 | break; |
okini3939 | 2:0753f1ed1dec | 168 | } |
okini3939 | 0:629617d401de | 169 | |
okini3939 | 2:0753f1ed1dec | 170 | for (i = 0; i < ArtMaxUniv; i ++) { |
okini3939 | 2:0753f1ed1dec | 171 | if ( (ArtMaxUniv <= 4 && ArtPollReply.Swout[i] == (artdmx->Universes & 0x0f)) || |
okini3939 | 2:0753f1ed1dec | 172 | (ArtMaxUniv > 4 && ArtPorts.Swout[i] == (artdmx->Universes & 0x0f)) ) { |
okini3939 | 2:0753f1ed1dec | 173 | LastRecievedUniverse |= (1<<i); |
okini3939 | 2:0753f1ed1dec | 174 | // get the dmx data |
okini3939 | 2:0753f1ed1dec | 175 | memcpy(DmxIn[i], artdmx->Data, ntohs(artdmx->Length)); |
okini3939 | 2:0753f1ed1dec | 176 | DBG(" <Art-Dmx> Univ: %d Length: %d Ch1: %d\r\n", artdmx->Universes, ntohs(artdmx->Length), DmxIn[i][0]); |
okini3939 | 2:0753f1ed1dec | 177 | DBG(" from %s\r\n", RemoteSin.get_address()); |
okini3939 | 2:0753f1ed1dec | 178 | rxlen = 0; |
okini3939 | 2:0753f1ed1dec | 179 | return 1; // something happened! |
okini3939 | 2:0753f1ed1dec | 180 | } |
okini3939 | 2:0753f1ed1dec | 181 | } |
okini3939 | 2:0753f1ed1dec | 182 | } |
okini3939 | 2:0753f1ed1dec | 183 | break; // OP_Output |
okini3939 | 2:0753f1ed1dec | 184 | |
okini3939 | 2:0753f1ed1dec | 185 | case OP_Poll: // 0x2000 |
okini3939 | 2:0753f1ed1dec | 186 | if (rxlen == sizeof(struct ArtPoll_Packet)) { |
okini3939 | 2:0753f1ed1dec | 187 | struct ArtPoll_Packet *artpoll = (struct ArtPoll_Packet*)buf; |
okini3939 | 0:629617d401de | 188 | |
okini3939 | 2:0753f1ed1dec | 189 | if (!(artpoll->TalkToMe & 1)) { |
okini3939 | 2:0753f1ed1dec | 190 | RemoteSin.set_address(BCastAddress, ArtUDPPort); |
okini3939 | 2:0753f1ed1dec | 191 | } |
okini3939 | 2:0753f1ed1dec | 192 | DBG(" <Art-Poll> Ver: %d TalkToMe: %d\r\n", ArtPoll.Version, ArtPoll.TalkToMe); |
okini3939 | 2:0753f1ed1dec | 193 | SendArtPollReply(); // send a reply to the ArtPoll |
okini3939 | 2:0753f1ed1dec | 194 | } |
okini3939 | 2:0753f1ed1dec | 195 | break; // OP_Poll |
okini3939 | 0:629617d401de | 196 | |
okini3939 | 2:0753f1ed1dec | 197 | case OP_PollReply: // 0x2100 |
okini3939 | 2:0753f1ed1dec | 198 | { |
okini3939 | 2:0753f1ed1dec | 199 | struct ArtPollReply_Packet *pollreply = (struct ArtPollReply_Packet*)buf; |
okini3939 | 2:0753f1ed1dec | 200 | |
okini3939 | 2:0753f1ed1dec | 201 | DBG(" <Art-PollReply> Startus: %02x Name: %s\r\n", pollreply->Status, pollreply->ShortName); |
okini3939 | 2:0753f1ed1dec | 202 | } |
okini3939 | 2:0753f1ed1dec | 203 | break; // OP_PollReply |
okini3939 | 2:0753f1ed1dec | 204 | |
okini3939 | 2:0753f1ed1dec | 205 | case OP_Address: // 0x6000 |
okini3939 | 2:0753f1ed1dec | 206 | if (rxlen == sizeof(struct ArtAddress_Packet)) { |
okini3939 | 2:0753f1ed1dec | 207 | struct ArtAddress_Packet *address = (struct ArtAddress_Packet *)buf; |
okini3939 | 0:629617d401de | 208 | |
okini3939 | 2:0753f1ed1dec | 209 | if ((address->NetSwitch & 0x80) && (address->SubSwitch & 0x80)) { |
okini3939 | 2:0753f1ed1dec | 210 | NetSwitch = ((address->NetSwitch & 0x7f) << 8) | ((address->SubSwitch & 0x0f) << 4); |
okini3939 | 2:0753f1ed1dec | 211 | ArtPollReply.NetSwitch = (NetSwitch >> 8) & 0x7f; |
okini3939 | 2:0753f1ed1dec | 212 | ArtPollReply.SubSwitch = (NetSwitch >> 4) & 0x0f; |
okini3939 | 2:0753f1ed1dec | 213 | } |
okini3939 | 2:0753f1ed1dec | 214 | if (address->ShortName[0]) { |
okini3939 | 2:0753f1ed1dec | 215 | strncpy(ArtPollReply.ShortName, address->ShortName, 18); |
okini3939 | 2:0753f1ed1dec | 216 | } |
okini3939 | 2:0753f1ed1dec | 217 | if (address->LongName[0]) { |
okini3939 | 2:0753f1ed1dec | 218 | strncpy(ArtPollReply.LongName, address->LongName, 64); |
okini3939 | 2:0753f1ed1dec | 219 | } |
okini3939 | 2:0753f1ed1dec | 220 | if (address->BindIndex) { |
okini3939 | 2:0753f1ed1dec | 221 | n = (address->BindIndex - 1) * 4; |
okini3939 | 2:0753f1ed1dec | 222 | } else { |
okini3939 | 2:0753f1ed1dec | 223 | n = 0; |
okini3939 | 2:0753f1ed1dec | 224 | } |
okini3939 | 2:0753f1ed1dec | 225 | for (i = 0; i < 4; i ++) { |
okini3939 | 2:0753f1ed1dec | 226 | if (address->Swin[i] != 0x7f) { |
okini3939 | 2:0753f1ed1dec | 227 | ArtPollReply.Swin[i] = address->Swin[i] & 0x0f; |
okini3939 | 2:0753f1ed1dec | 228 | ArtPorts.Swin[n + i] = address->Swin[i] & 0x0f; |
okini3939 | 2:0753f1ed1dec | 229 | if (address->Swin[i] & 0x80) { |
okini3939 | 2:0753f1ed1dec | 230 | ArtPollReply.PortType[i] |= 0x40; |
okini3939 | 2:0753f1ed1dec | 231 | ArtPorts.PortType[n + i] |= 0x40; |
okini3939 | 2:0753f1ed1dec | 232 | } else { |
okini3939 | 2:0753f1ed1dec | 233 | ArtPollReply.PortType[i] &= ~0x40; |
okini3939 | 2:0753f1ed1dec | 234 | ArtPorts.PortType[n + i] &= ~0x40; |
okini3939 | 2:0753f1ed1dec | 235 | } |
okini3939 | 2:0753f1ed1dec | 236 | } |
okini3939 | 2:0753f1ed1dec | 237 | if (address->Swout[i] != 0x7f) { |
okini3939 | 2:0753f1ed1dec | 238 | ArtPollReply.Swout[i] = address->Swout[i] & 0x0f; |
okini3939 | 2:0753f1ed1dec | 239 | ArtPorts.Swout[n + i] = address->Swout[i] & 0x0f; |
okini3939 | 2:0753f1ed1dec | 240 | if (address->Swout[i] & 0x80) { |
okini3939 | 2:0753f1ed1dec | 241 | ArtPollReply.PortType[i] |= 0x80; |
okini3939 | 2:0753f1ed1dec | 242 | ArtPorts.PortType[n + i] |= 0x80; |
okini3939 | 2:0753f1ed1dec | 243 | } else { |
okini3939 | 2:0753f1ed1dec | 244 | ArtPollReply.PortType[i] &= ~0x80; |
okini3939 | 2:0753f1ed1dec | 245 | ArtPorts.PortType[n + i] &= ~0x80; |
okini3939 | 2:0753f1ed1dec | 246 | } |
okini3939 | 2:0753f1ed1dec | 247 | } |
okini3939 | 2:0753f1ed1dec | 248 | } |
okini3939 | 2:0753f1ed1dec | 249 | |
okini3939 | 2:0753f1ed1dec | 250 | if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); |
okini3939 | 2:0753f1ed1dec | 251 | SendArtPollReply(); // send a reply to the ArtPoll |
okini3939 | 2:0753f1ed1dec | 252 | DBG(" <Art-Address> NetSwitch: %02x Command: %02x\r\n", NetSwitch, address->Command); |
okini3939 | 2:0753f1ed1dec | 253 | } |
okini3939 | 2:0753f1ed1dec | 254 | break; |
okini3939 | 0:629617d401de | 255 | |
okini3939 | 2:0753f1ed1dec | 256 | case OP_IpProg: // 0xf800 |
okini3939 | 2:0753f1ed1dec | 257 | if (rxlen == sizeof(struct ArtIpProg_Packet)) { |
okini3939 | 2:0753f1ed1dec | 258 | struct ArtIpProg_Packet *ipprog = (struct ArtIpProg_Packet *)buf; |
okini3939 | 2:0753f1ed1dec | 259 | |
okini3939 | 2:0753f1ed1dec | 260 | if (ipprog->Command & (1<<7)) { |
okini3939 | 2:0753f1ed1dec | 261 | if (ipprog->Command & (1<<6)) { // dhcp |
okini3939 | 2:0753f1ed1dec | 262 | BindIpAddress[0] = 0; |
okini3939 | 2:0753f1ed1dec | 263 | } |
okini3939 | 2:0753f1ed1dec | 264 | if (ipprog->Command & (1<<2)) { // ip addrress |
okini3939 | 2:0753f1ed1dec | 265 | sprintf(BindIpAddress, "%d.%d.%d.%d", ipprog->ProgIp[0], ipprog->ProgIp[1], ipprog->ProgIp[2], ipprog->ProgIp[3]); |
okini3939 | 2:0753f1ed1dec | 266 | // sprintf(DGateWay, "%d.%d.%d.%d", ipprog->Padding[0], ipprog->Padding[1], ipprog->Padding[2], ipprog->Padding[3]); |
okini3939 | 2:0753f1ed1dec | 267 | } |
okini3939 | 2:0753f1ed1dec | 268 | if (ipprog->Command & (1<<1)) { // subnet mask |
okini3939 | 2:0753f1ed1dec | 269 | sprintf(SubNetMask, "%d.%d.%d.%d", ipprog->ProgSm[0], ipprog->ProgSm[1], ipprog->ProgSm[2], ipprog->ProgSm[3]); |
okini3939 | 2:0753f1ed1dec | 270 | } |
okini3939 | 2:0753f1ed1dec | 271 | bcast(BCastAddress, BindIpAddress, SubNetMask); |
okini3939 | 2:0753f1ed1dec | 272 | } |
okini3939 | 2:0753f1ed1dec | 273 | |
okini3939 | 2:0753f1ed1dec | 274 | // if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); |
okini3939 | 2:0753f1ed1dec | 275 | SendArtIpProgReply(); |
okini3939 | 2:0753f1ed1dec | 276 | DBG(" <Art-IpProg> NetSwitch: %02x Command: %02x\r\n", NetSwitch, ipprog->Command); |
okini3939 | 2:0753f1ed1dec | 277 | } |
okini3939 | 2:0753f1ed1dec | 278 | if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); |
okini3939 | 2:0753f1ed1dec | 279 | break; |
okini3939 | 0:629617d401de | 280 | |
okini3939 | 2:0753f1ed1dec | 281 | case OP_OpTodRequest: // 0x8000 |
okini3939 | 2:0753f1ed1dec | 282 | if (rxlen == sizeof(struct ArtTodRequest_Packet)) { |
okini3939 | 2:0753f1ed1dec | 283 | struct ArtTodRequest_Packet *todreq = (struct ArtTodRequest_Packet *)buf; |
okini3939 | 2:0753f1ed1dec | 284 | if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); |
okini3939 | 2:0753f1ed1dec | 285 | for (i = 0; i < todreq->AddCount; i ++) { |
okini3939 | 2:0753f1ed1dec | 286 | SendArtTodData(todreq->Address[i]); |
okini3939 | 2:0753f1ed1dec | 287 | } |
okini3939 | 2:0753f1ed1dec | 288 | } |
okini3939 | 2:0753f1ed1dec | 289 | break; |
okini3939 | 2:0753f1ed1dec | 290 | |
okini3939 | 2:0753f1ed1dec | 291 | case OP_OpTodControl: // 0x8200 |
okini3939 | 2:0753f1ed1dec | 292 | if (rxlen == sizeof(struct ArtTodControl_Packet)) { |
okini3939 | 2:0753f1ed1dec | 293 | struct ArtTodControl_Packet *tod = (struct ArtTodControl_Packet *)buf; |
okini3939 | 2:0753f1ed1dec | 294 | if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); |
okini3939 | 2:0753f1ed1dec | 295 | if (tod->Command == 0x01) { |
okini3939 | 2:0753f1ed1dec | 296 | SendArtTodData(tod->Address); |
okini3939 | 2:0753f1ed1dec | 297 | } |
okini3939 | 2:0753f1ed1dec | 298 | } |
okini3939 | 2:0753f1ed1dec | 299 | break; |
okini3939 | 2:0753f1ed1dec | 300 | |
okini3939 | 2:0753f1ed1dec | 301 | case OP_OpRdm: // 0x8300 |
okini3939 | 2:0753f1ed1dec | 302 | case OP_OpRdmSub: // 0x8400 |
okini3939 | 2:0753f1ed1dec | 303 | default: |
okini3939 | 2:0753f1ed1dec | 304 | if (cb_ArtParser) cb_ArtParser(ArtHead, rxlen); |
okini3939 | 2:0753f1ed1dec | 305 | DBG(" <Unknown> OpCode: %04x\r\n", ArtHead->OpCode); |
okini3939 | 2:0753f1ed1dec | 306 | break; |
okini3939 | 0:629617d401de | 307 | } // case packet type |
okini3939 | 0:629617d401de | 308 | } |
okini3939 | 0:629617d401de | 309 | |
okini3939 | 0:629617d401de | 310 | rxlen = 0; |
okini3939 | 0:629617d401de | 311 | return 0; |
okini3939 | 0:629617d401de | 312 | } |
okini3939 | 0:629617d401de | 313 | |
okini3939 | 0:629617d401de | 314 | // socket shutdown |
okini3939 | 0:629617d401de | 315 | void DmxArtNet::Done () { |
okini3939 | 0:629617d401de | 316 | _art.close(); |
okini3939 | 0:629617d401de | 317 | } |
okini3939 | 0:629617d401de | 318 | |
okini3939 | 0:629617d401de | 319 | // init ArtDMX packet |
okini3939 | 0:629617d401de | 320 | void DmxArtNet::Init_ArtDMX () { |
okini3939 | 0:629617d401de | 321 | // header stuff |
okini3939 | 2:0753f1ed1dec | 322 | memset(&ArtDMX, 0, sizeof(ArtDMX)); |
okini3939 | 0:629617d401de | 323 | memcpy(ArtDMX.ID, ArtHeaderID, 8); |
okini3939 | 0:629617d401de | 324 | ArtDMX.OpCode = OP_Output; |
okini3939 | 0:629617d401de | 325 | ArtDMX.Version = ArtVersion; |
okini3939 | 0:629617d401de | 326 | // dmx stuff |
okini3939 | 0:629617d401de | 327 | ArtDMX.Universes = 0; // this is the destination for the dmx |
okini3939 | 0:629617d401de | 328 | ArtDMX.Sequence = 0; |
okini3939 | 2:0753f1ed1dec | 329 | ArtDMX.Length = htons(DMX_SIZE); |
okini3939 | 0:629617d401de | 330 | } |
okini3939 | 0:629617d401de | 331 | |
okini3939 | 0:629617d401de | 332 | // send ArtDmx Packet |
okini3939 | 0:629617d401de | 333 | int DmxArtNet::Send_ArtDmx(int univ, int physical, char *data, int length) { |
okini3939 | 2:0753f1ed1dec | 334 | Endpoint Remote; |
okini3939 | 0:629617d401de | 335 | |
okini3939 | 0:629617d401de | 336 | // build a artdmx packet |
okini3939 | 0:629617d401de | 337 | memcpy(ArtDMX.Data, data, length); |
okini3939 | 2:0753f1ed1dec | 338 | ArtDMX.Universes = (NetSwitch & 0x7ff0) | univ; |
okini3939 | 0:629617d401de | 339 | ArtDMX.Length = htons(length); |
okini3939 | 0:629617d401de | 340 | ArtDMX.Physical = physical; |
okini3939 | 0:629617d401de | 341 | ArtDMX.Sequence ++; |
okini3939 | 0:629617d401de | 342 | |
okini3939 | 0:629617d401de | 343 | // set place to send |
okini3939 | 2:0753f1ed1dec | 344 | Remote.set_address(BCastAddress, ArtUDPPort); |
okini3939 | 0:629617d401de | 345 | |
okini3939 | 0:629617d401de | 346 | // send it off |
okini3939 | 2:0753f1ed1dec | 347 | _art.sendTo(Remote, (char*)&ArtDMX, sizeof(ArtDMX)); |
okini3939 | 0:629617d401de | 348 | |
okini3939 | 0:629617d401de | 349 | return 0; |
okini3939 | 0:629617d401de | 350 | } |
okini3939 | 0:629617d401de | 351 | |
okini3939 | 0:629617d401de | 352 | |
okini3939 | 0:629617d401de | 353 | void DmxArtNet::InitArtPollReplyDefaults () { |
okini3939 | 2:0753f1ed1dec | 354 | memset(&ArtPollReply, 0, sizeof(ArtPollReply)); |
okini3939 | 2:0753f1ed1dec | 355 | memset(&ArtPorts, 0, sizeof(ArtPorts)); |
okini3939 | 0:629617d401de | 356 | memcpy(ArtPollReply.ID, ArtHeaderID, 8); |
okini3939 | 0:629617d401de | 357 | ArtPollReply.OpCode = OP_PollReply; // reply packet |
okini3939 | 0:629617d401de | 358 | ArtPollReply.Version = ArtVersion; |
okini3939 | 0:629617d401de | 359 | |
okini3939 | 2:0753f1ed1dec | 360 | ArtPollReply.NetSwitch = (NetSwitch >> 8) & 0x7f; |
okini3939 | 2:0753f1ed1dec | 361 | ArtPollReply.SubSwitch = (NetSwitch >> 4) & 0x0f; |
okini3939 | 2:0753f1ed1dec | 362 | ArtPollReply.OEM = htons(OemId); |
okini3939 | 2:0753f1ed1dec | 363 | ArtPollReply.Status = (3<<6)|(2<<4); // Normal mode, Universe programmed by network |
okini3939 | 2:0753f1ed1dec | 364 | |
okini3939 | 2:0753f1ed1dec | 365 | ArtPollReply.Addr = localaddr; |
okini3939 | 0:629617d401de | 366 | strncpy(ArtPollReply.ShortName, STR_ShortName, 18); |
okini3939 | 0:629617d401de | 367 | strncpy(ArtPollReply.LongName, STR_LongName, 64); |
okini3939 | 0:629617d401de | 368 | strncpy(ArtPollReply.NodeReport, "OK", 64); |
okini3939 | 0:629617d401de | 369 | ArtPollReply.Style = StyleNode; |
okini3939 | 0:629617d401de | 370 | |
okini3939 | 0:629617d401de | 371 | mbed_mac_address((char*)&ArtPollReply.Mac); |
okini3939 | 0:629617d401de | 372 | |
okini3939 | 2:0753f1ed1dec | 373 | ArtPollReply.PortType[0] = 0; |
okini3939 | 2:0753f1ed1dec | 374 | ArtPollReply.PortType[1] = 0; |
okini3939 | 2:0753f1ed1dec | 375 | ArtPollReply.PortType[2] = 0; |
okini3939 | 2:0753f1ed1dec | 376 | ArtPollReply.PortType[3] = 0; |
okini3939 | 0:629617d401de | 377 | } |
okini3939 | 0:629617d401de | 378 | |
okini3939 | 0:629617d401de | 379 | // send ArtPoll Reply |
okini3939 | 0:629617d401de | 380 | int DmxArtNet::SendArtPollReply () { |
okini3939 | 2:0753f1ed1dec | 381 | int i, j, n; |
okini3939 | 0:629617d401de | 382 | |
okini3939 | 0:629617d401de | 383 | // send the packet |
okini3939 | 2:0753f1ed1dec | 384 | // DBG("SendArtPollReply> %s:%d\r\n", RemoteSin.get_address(), RemoteSin.get_port()); |
okini3939 | 2:0753f1ed1dec | 385 | if (ArtMaxUniv <= 4) { |
okini3939 | 2:0753f1ed1dec | 386 | _art.sendTo(RemoteSin, (char*)&ArtPollReply, sizeof(ArtPollReply)); |
okini3939 | 2:0753f1ed1dec | 387 | } else { |
okini3939 | 2:0753f1ed1dec | 388 | for (i = 0; i < (ArtMaxUniv + 3) / 4; i ++) { |
okini3939 | 2:0753f1ed1dec | 389 | n = i * 4; |
okini3939 | 2:0753f1ed1dec | 390 | ArtPollReply.BindIndex = 1 + i; |
okini3939 | 2:0753f1ed1dec | 391 | ArtPollReply.NumPorts = ArtMaxUniv - n < 4 ? ArtMaxUniv - n : 4; |
okini3939 | 2:0753f1ed1dec | 392 | for (j = 0; j < ArtPollReply.NumPorts; j ++) { |
okini3939 | 2:0753f1ed1dec | 393 | ArtPollReply.PortType[j] = ArtPorts.PortType[n + j]; |
okini3939 | 2:0753f1ed1dec | 394 | ArtPollReply.GoodInput[j] = ArtPorts.GoodInput[n + j]; |
okini3939 | 2:0753f1ed1dec | 395 | ArtPollReply.GoodOutput[j] = ArtPorts.GoodOutput[n + j]; |
okini3939 | 2:0753f1ed1dec | 396 | ArtPollReply.Swin[j] = ArtPorts.Swin[n + j]; |
okini3939 | 2:0753f1ed1dec | 397 | ArtPollReply.Swout[j] = ArtPorts.Swout[n + j]; |
okini3939 | 2:0753f1ed1dec | 398 | } |
okini3939 | 2:0753f1ed1dec | 399 | for (; j < 4; j ++) { |
okini3939 | 2:0753f1ed1dec | 400 | ArtPollReply.PortType[j] = 0; |
okini3939 | 2:0753f1ed1dec | 401 | ArtPollReply.GoodInput[j] = 0; |
okini3939 | 2:0753f1ed1dec | 402 | ArtPollReply.GoodOutput[j] = 0; |
okini3939 | 2:0753f1ed1dec | 403 | ArtPollReply.Swin[j] = 0; |
okini3939 | 2:0753f1ed1dec | 404 | ArtPollReply.Swout[j] = 0; |
okini3939 | 2:0753f1ed1dec | 405 | } |
okini3939 | 2:0753f1ed1dec | 406 | _art.sendTo(RemoteSin, (char*)&ArtPollReply, sizeof(ArtPollReply)); |
okini3939 | 2:0753f1ed1dec | 407 | } |
okini3939 | 2:0753f1ed1dec | 408 | } |
okini3939 | 2:0753f1ed1dec | 409 | return 0; |
okini3939 | 2:0753f1ed1dec | 410 | } |
okini3939 | 2:0753f1ed1dec | 411 | |
okini3939 | 2:0753f1ed1dec | 412 | // send ArtIpProg Reply |
okini3939 | 2:0753f1ed1dec | 413 | int DmxArtNet::SendArtIpProgReply () { |
okini3939 | 2:0753f1ed1dec | 414 | ArtIpProgReply_Packet ArtIpProgReply; |
okini3939 | 2:0753f1ed1dec | 415 | int ip[4]; |
okini3939 | 2:0753f1ed1dec | 416 | |
okini3939 | 2:0753f1ed1dec | 417 | memset(&ArtIpProgReply, 0, sizeof(ArtIpProgReply)); |
okini3939 | 2:0753f1ed1dec | 418 | memcpy(ArtIpProgReply.ID, ArtHeaderID, 8); |
okini3939 | 2:0753f1ed1dec | 419 | ArtIpProgReply.OpCode = OP_IpProgReply; |
okini3939 | 2:0753f1ed1dec | 420 | ArtIpProgReply.Version = ArtVersion; |
okini3939 | 2:0753f1ed1dec | 421 | |
okini3939 | 2:0753f1ed1dec | 422 | sscanf(BindIpAddress, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]); |
okini3939 | 2:0753f1ed1dec | 423 | ArtIpProgReply.ProgIp[0] = ip[0]; |
okini3939 | 2:0753f1ed1dec | 424 | ArtIpProgReply.ProgIp[1] = ip[1]; |
okini3939 | 2:0753f1ed1dec | 425 | ArtIpProgReply.ProgIp[2] = ip[2]; |
okini3939 | 2:0753f1ed1dec | 426 | ArtIpProgReply.ProgIp[3] = ip[3]; |
okini3939 | 2:0753f1ed1dec | 427 | sscanf(SubNetMask, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]); |
okini3939 | 2:0753f1ed1dec | 428 | ArtIpProgReply.ProgSm[0] = ip[0]; |
okini3939 | 2:0753f1ed1dec | 429 | ArtIpProgReply.ProgSm[1] = ip[1]; |
okini3939 | 2:0753f1ed1dec | 430 | ArtIpProgReply.ProgSm[2] = ip[2]; |
okini3939 | 2:0753f1ed1dec | 431 | ArtIpProgReply.ProgSm[3] = ip[3]; |
okini3939 | 2:0753f1ed1dec | 432 | ArtIpProgReply.ProgPortH = ArtUDPPort >> 8; |
okini3939 | 2:0753f1ed1dec | 433 | ArtIpProgReply.ProgPort = ArtUDPPort & 0xff; |
okini3939 | 2:0753f1ed1dec | 434 | |
okini3939 | 2:0753f1ed1dec | 435 | if (BindIpAddress[0] == '0') { |
okini3939 | 2:0753f1ed1dec | 436 | ArtIpProgReply.Status = 0x40; // dhcp |
okini3939 | 2:0753f1ed1dec | 437 | } |
okini3939 | 2:0753f1ed1dec | 438 | |
okini3939 | 2:0753f1ed1dec | 439 | _art.sendTo(RemoteSin, (char*)&ArtIpProgReply, sizeof(ArtIpProgReply)); |
okini3939 | 0:629617d401de | 440 | |
okini3939 | 0:629617d401de | 441 | return 0; |
okini3939 | 0:629617d401de | 442 | } |
okini3939 | 2:0753f1ed1dec | 443 | |
okini3939 | 2:0753f1ed1dec | 444 | // send SendArtTod |
okini3939 | 2:0753f1ed1dec | 445 | int DmxArtNet::SendArtTodData (int n) { |
okini3939 | 2:0753f1ed1dec | 446 | ArtTodData_Packet ArtTodData; |
okini3939 | 2:0753f1ed1dec | 447 | |
okini3939 | 2:0753f1ed1dec | 448 | memset(&ArtTodData, 0, sizeof(ArtTodData)); |
okini3939 | 2:0753f1ed1dec | 449 | memcpy(ArtTodData.ID, ArtHeaderID, 8); |
okini3939 | 2:0753f1ed1dec | 450 | ArtTodData.OpCode = OP_OpTodData; |
okini3939 | 2:0753f1ed1dec | 451 | ArtTodData.Version = ArtVersion; |
okini3939 | 2:0753f1ed1dec | 452 | |
okini3939 | 2:0753f1ed1dec | 453 | ArtTodData.RdmVersion = 1; |
okini3939 | 2:0753f1ed1dec | 454 | ArtTodData.Port = n + 1; |
okini3939 | 2:0753f1ed1dec | 455 | |
okini3939 | 2:0753f1ed1dec | 456 | ArtTodData.UidTotalH = 0; |
okini3939 | 2:0753f1ed1dec | 457 | ArtTodData.UidTotalL = 1; |
okini3939 | 2:0753f1ed1dec | 458 | ArtTodData.BlockCount = 0; |
okini3939 | 2:0753f1ed1dec | 459 | ArtTodData.UidCount = 2; |
okini3939 | 2:0753f1ed1dec | 460 | ArtTodData.ToD[0] = 0x11; |
okini3939 | 2:0753f1ed1dec | 461 | ArtTodData.ToD[1] = 0x22; |
okini3939 | 2:0753f1ed1dec | 462 | |
okini3939 | 2:0753f1ed1dec | 463 | _art.sendTo(RemoteSin, (char*)&ArtTodData, sizeof(ArtTodData)); |
okini3939 | 2:0753f1ed1dec | 464 | |
okini3939 | 2:0753f1ed1dec | 465 | return 0; |
okini3939 | 2:0753f1ed1dec | 466 | } |
okini3939 | 2:0753f1ed1dec | 467 | |
okini3939 | 2:0753f1ed1dec | 468 | void DmxArtNet::bcast(char *dest, char *ipaddr, char *netmask) { |
okini3939 | 2:0753f1ed1dec | 469 | unsigned char ip[4]; |
okini3939 | 2:0753f1ed1dec | 470 | int a[4], n[4]; |
okini3939 | 2:0753f1ed1dec | 471 | |
okini3939 | 2:0753f1ed1dec | 472 | sscanf(ipaddr, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]); |
okini3939 | 2:0753f1ed1dec | 473 | sscanf(netmask, "%d.%d.%d.%d", &n[0], &n[1], &n[2], &n[3]); |
okini3939 | 2:0753f1ed1dec | 474 | ip[0] = (a[0] & n[0]) | ~n[0]; |
okini3939 | 2:0753f1ed1dec | 475 | ip[1] = (a[1] & n[1]) | ~n[1]; |
okini3939 | 2:0753f1ed1dec | 476 | ip[2] = (a[2] & n[2]) | ~n[2]; |
okini3939 | 2:0753f1ed1dec | 477 | ip[3] = (a[3] & n[3]) | ~n[3]; |
okini3939 | 2:0753f1ed1dec | 478 | sprintf(dest, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); |
okini3939 | 2:0753f1ed1dec | 479 | } |
okini3939 | 2:0753f1ed1dec | 480 | |
okini3939 | 2:0753f1ed1dec | 481 | void DmxArtNet::attach (void (*handler)(struct ArtPacketHeader *, int)) { |
okini3939 | 2:0753f1ed1dec | 482 | cb_ArtParser = handler; |
okini3939 | 2:0753f1ed1dec | 483 | } |