1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
|
/*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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 Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* kinet.cpp
* Scratch pad for Kinet work
* Copyright (C) 2010 Simon Newton
*/
#include <ola/Callback.h>
#include <ola/Logging.h>
#include <ola/network/NetworkUtils.h>
#include <ola/network/SelectServer.h>
#include <ola/network/Socket.h>
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
using ola::network::SelectServer;
using ola::network::UDPSocket;
using ola::network::LittleEndianToHost;
/*
* The KiNet protocol appears to be little-endian. We write the constants as
* they appear to a human and convert back and forth.
*/
// All packets seem to start with this number
const uint32_t KINET_MAGIC = 0x4adc0104;
// We haven't seen a non V1 protocol in the wild yet.
const uint16_t KINET_VERSION = 0x0001;
// No idea what this is, but we should send a poll reply when we see it
const uint32_t KINET_DISCOVERY_COMMAND = 0x8988870a;
// KiNet packet types
typedef enum {
KINET_POLL = 0x0001,
KINET_POLL_REPLY = 0x0002,
KINET_SET_IP = 0x0003,
KINET_SET_UNIVERSE = 0x0005,
KINET_SET_NAME = 0x0006,
// KINET_?? = 0x000a;
KINET_DMX = 0x0101,
// KINET_PORTOUT = 0x0108; // portout
// KINET_PORTOUT_SYNC = 0x0109; // portout_sync
// KINET_?? = 0x0201; // seems to be a discovery packet
// KINET_?? = 0x0203; // get dmx address?
} kinet_packet_type;
/**
* The KiNet header
*/
struct kinet_header {
uint32_t magic;
uint16_t version;
uint16_t type; // see kinet_packet_type above
uint32_t padding; // always set to 0, seq #,
// most of the time it's 0,
// not implemented in most supplies
} __attribute__((packed));
// A KiNet poll message
struct kinet_poll {
uint32_t command; // ??, Seems to always be KINET_DISCOVERY_COMMAND
} __attribute__((packed));
// A KiNet poll reply message
struct kinet_poll_reply {
uint32_t src_ip;
uint8_t hw_address[6]; // mac address
uint8_t data[2]; // This contains non-0 data
uint32_t serial; // The node serial #
uint32_t zero;
uint8_t node_name[60];
uint8_t node_label[31];
uint16_t zero2;
} __attribute__((packed));
// A KiNet Set IP Command.
// TODO(simon): Check what ip,mac dst this packet is sent to.
struct kinet_set_ip {
uint32_t something; // ef be ad de
uint8_t hw_address[6]; // The MAC address to match
uint16_t something2; // 05 67
uint32_t new_ip;
} __attribute__((packed));
// A KiNet Set Universe Command
struct kinet_set_universe {
uint32_t something; // ef be ad de
uint8_t universe;
uint8_t zero[3];
} __attribute__((packed));
// A KiNet Set Name Command
struct kinet_set_name {
uint32_t something; // ef be ad de
uint8_t new_name[31]; // Null terminated.
} __attribute__((packed));
// A KiNet Get Address command
struct kinet_get_address {
uint32_t serial;
uint32_t something; // 41 00 12 00
} __attribute__((packed));
// A KiNet DMX packet
struct kinet_dmx {
uint8_t port; // should be set to 0 for v1
uint8_t flags; // set to 0
uint16_t timerVal; // set to 0
uint32_t universe;
uint8_t paylod[513]; // payload inc start code
} __attribute__((packed));
struct kinet_port_out_flags {
uint16_t flags;
// little endian
// first bit is undefined 0:1;
// second bit is for 16 bit data, set to 0 :1;
// third is shall hold for sync packet :: 1;
};
struct kinet_port_out_sync {
uint32_t padding;
}
// A KiNet DMX port out packet
struct kinet_port_out {
uint32_t universe;
uint8_t port; // 1- 16
uint8_t pad; // set to 0
portoutflags flags;
uint16_t length; // little endian
uint16_t startCode; // 0x0fff for chomASIC products, 0x0000 otherwise
uint8_t payload[512];
} __attribute__((packed));
// The full kinet packet
struct kinet_packet {
struct kinet_header header;
union {
struct kinet_poll poll;
struct kinet_poll_reply poll_reply;
} data;
};
uint8_t peer0_0[] = {
0x04, 0x01, 0xdc, 0x4a, // magic number
0x01, 0x00, // version #
0x02, 0x00, // packet type (poll reply)
0x00, 0x00, 0x00, 0x00, // sequence
0x0a, 0x00, 0x00, 0x01, // 192.168.1.207
0x00, 0x0a, 0xc5, 0xff, 0xae, 0x01, // mac address
0x01, 0x00,
0xff, 0xff, 0x00, 0x2d, // serial #
0x00, 0x00, 0x00, 0x00, // padding
// What follows is ascii text, with fields separated by new lines. Each field
// is in the form /[MD#R]:.*/
// It's unclear is this is a variable length field or not.
0x4d, 0x3a, // M:
0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x4b, 0x69, 0x6e, 0x65, 0x74, 0x69, 0x63,
0x73, 0x20, 0x49, 0x6e, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x65,
0x64, // Color Kinetics cs Incorporated
0x0a, // \n
0x44, 0x3a, // D:
0x50, 0x44, 0x53, 0x2d, 0x65, // PDS-e
0x0a, // \n
0x23, 0x3a, // #:
0x53, 0x46, 0x54, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x36, 0x36, 0x2d, 0x30, 0x30,
0x0a, // SFT-000066-00
0x52, 0x3a, // R:
0x30, 0x30, // 00
0x0a, // \n
0x00,
// offset 92
0x64, 0x73, 0x2d, 0x64, 0x61, 0x6e, 0x63, 0x65, 0x2d, 0x72, 0x65, 0x61, 0x72,
0x00, // device name?
0x00, 0x95, 0x8c, 0xc7, 0xb6, 0x00,
0x00,
0xff, 0x00, 0x00,
0xff, 0x00, 0x00,
0xff, 0x00, 0x00,
0xff, 0x00, 0x00 };
SelectServer ss;
UDPSocket udp_socket;
/**
* Check if a packet is valid KiNet
*/
bool IsKiNet(const kinet_packet *packet, unsigned int size) {
return (size > sizeof(struct kinet_header) &&
KINET_MAGIC == LittleEndianToHost(packet->header.magic) &&
KINET_VERSION == LittleEndianToHost(packet->header.version));
}
/**
* Handle a KiNet poll packet
*/
void HandlePoll(const struct sockaddr_in &source,
const kinet_packet &packet,
unsigned int size) {
ssize_t r = udp_socket.SendTo(peer0_0, sizeof(peer0_0), source);
OLA_INFO << "sent " << r << " bytes";
}
/**
* Handle a KiNet DMX packet
*/
void HandleDmx(const struct sockaddr_in &source,
const kinet_packet &packet,
unsigned int size) {
}
void SocketReady() {
kinet_packet packet;
ssize_t data_read = sizeof(packet);
struct sockaddr_in source;
socklen_t src_size = sizeof(source);
udp_socket.RecvFrom(reinterpret_cast<uint8_t*>(&packet),
&data_read,
source,
src_size);
if (IsKiNet(&packet, data_read)) {
uint16_t command = LittleEndianToHost(packet.header.type);
switch (command) {
case KINET_POLL:
HandlePoll(source, packet, data_read);
break;
case KINET_DMX:
HandleDmx(source, packet, data_read);
break;
default:
OLA_WARN << "Unknown packet 0x" << std::hex << command;
}
} else {
OLA_WARN << "Not a KiNet packet";
}
}
/*
* Main
*/
int main(int argc, char *argv[]) {
ola::InitLogging(ola::OLA_LOG_INFO, ola::OLA_LOG_STDERR);
udp_socket.SetOnData(ola::NewCallback(&SocketReady));
if (!udp_socket.Init()) {
OLA_WARN << "Failed to init";
return 1;
}
if (!udp_socket.Bind(6038)) {
OLA_WARN << "Failed to bind";
return 1;
}
if (!udp_socket.EnableBroadcast()) {
OLA_WARN << "Failed to enabl bcast";
return 1;
}
ss.AddSocket(&udp_socket);
ss.Run();
return 0;
}
|