505 lines
13 KiB
C
505 lines
13 KiB
C
/*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* private.h
|
|
* Private definitions, data structures, macros and functions for libartnet
|
|
* Copyright (C) 2004-2007 Simon Newton
|
|
*/
|
|
|
|
#if HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#ifndef WIN32
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
|
|
#include "artnet.h"
|
|
#include "artnet/packets.h"
|
|
#include "misc.h"
|
|
#include "tod.h"
|
|
|
|
#ifndef ARTNET_PRIVATE_H
|
|
#define ARTNET_PRIVATE_H
|
|
|
|
// these are defined in artnet.c
|
|
extern int ARTNET_PORT;
|
|
extern char ARTNET_STRING[];
|
|
extern int ARTNET_STRING_SIZE;
|
|
extern uint8_t ARTNET_VERSION;
|
|
extern uint8_t OEM_HI;
|
|
extern uint8_t OEM_LO;
|
|
extern char ESTA_HI;
|
|
extern char ESTA_LO;
|
|
extern uint8_t TTM_BEHAVIOUR_MASK;
|
|
extern uint8_t TTM_REPLY_MASK;
|
|
extern uint8_t PROGRAM_NO_CHANGE;
|
|
extern uint8_t PROGRAM_DEFAULTS;
|
|
extern uint8_t PROGRAM_CHANGE_MASK;
|
|
extern uint8_t HIGH_NIBBLE;
|
|
extern uint8_t LOW_NIBBLE;
|
|
extern uint8_t STATUS_PROG_AUTH_MASK;
|
|
extern uint8_t PORT_STATUS_LPT_MODE;
|
|
extern uint8_t PORT_STATUS_SHORT;
|
|
extern uint8_t PORT_STATUS_ERROR;
|
|
extern uint8_t PORT_STATUS_DISABLED_MASK;
|
|
extern uint8_t ORT_STATUS_MERGE;
|
|
extern uint8_t PORT_STATUS_DMX_TEXT;
|
|
extern uint8_t PORT_STATUS_DMX_SIP;
|
|
extern uint8_t PORT_STATUS_DMX_TEST;
|
|
extern uint8_t PORT_STATUS_ACT_MASK;
|
|
extern uint8_t PORT_DISABLE_MASK;
|
|
extern uint8_t TOD_RESPONSE_FULL;
|
|
extern uint8_t TOD_RESPONSE_NAK;
|
|
extern uint8_t MIN_PACKET_SIZE;
|
|
extern uint8_t MERGE_TIMEOUT_SECONDS;
|
|
extern uint8_t FIRMWARE_TIMEOUT_SECONDS;
|
|
extern uint8_t RECV_NO_DATA;
|
|
|
|
#ifndef TRUE
|
|
extern int TRUE;
|
|
extern int FALSE;
|
|
#endif
|
|
|
|
extern uint16_t LOW_BYTE;
|
|
extern uint16_t HIGH_BYTE;
|
|
|
|
// non artnet specific
|
|
#define SA struct sockaddr
|
|
#define SI struct in_addr
|
|
|
|
#ifndef min
|
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
|
#endif
|
|
|
|
#ifndef max
|
|
#define max(a, b) ((a) > (b) ? (a) : (b))
|
|
#endif
|
|
|
|
#ifndef INVALID_SOCKET
|
|
#define INVALID_SOCKET -1
|
|
#endif
|
|
|
|
// byte ordering macros
|
|
#define bswap_16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
|
|
|
|
// htols : convert short from host to little endian order
|
|
#ifdef WIN32
|
|
# define htols(x) (x)
|
|
#else
|
|
# ifdef HAVE_ENDIAN_H
|
|
# if BYTE_ORDER == __BIG_ENDIAN
|
|
# define htols(x) bswap_16 (x)
|
|
# else
|
|
# define htols(x) (x)
|
|
# endif
|
|
# else
|
|
# if BYTE_ORDER == BIG_ENDIAN
|
|
# define htols(x) bswap_16 (x)
|
|
# else
|
|
# define htols(x) (x)
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
// convert from shorts to bytes and back again
|
|
#define short_get_high_byte(x) ((HIGH_BYTE & x) >> 8)
|
|
#define short_get_low_byte(x) (LOW_BYTE & x)
|
|
|
|
#define bytes_to_short(h,l) ( ((h << 8) & 0xff00) | (l & 0x00FF) );
|
|
|
|
/*
|
|
* These are enums for fields in packets
|
|
* Ordered by packets they appear in. Some of these appear in the public header file
|
|
* artnet.h if they have to be used by the user.
|
|
*
|
|
* They are all in the form artnet_xxx_code in case they have to be made public some day
|
|
*
|
|
*/
|
|
|
|
// ArtPollReply
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// the node report codes
|
|
typedef enum {
|
|
ARTNET_RCDEBUG,
|
|
ARTNET_RCPOWEROK,
|
|
ARTNET_RCPOWERFAIL,
|
|
ARTNET_RCSOCKETWR1,
|
|
ARTNET_RCPARSEFAIL,
|
|
ARTNET_RCUDPFAIL,
|
|
ARTNET_RCSHNAMEOK,
|
|
ARTNET_RCLONAMEOK,
|
|
ARTNET_RCDMXERROR,
|
|
ARTNET_RCDMXUDPFULL,
|
|
ARTNET_RCDMXRXFULL,
|
|
ARTNET_RCSWITCHERR,
|
|
ARTNET_RCCONFIGERR,
|
|
ARTNET_RCDMXSHORT,
|
|
ARTNET_RCFIRMWAREFAIL,
|
|
ARTNET_RCUSERFAIL
|
|
} artnet_node_report_code;
|
|
|
|
// these define the types of node that can exist
|
|
// note it's different from artnet_node_type
|
|
typedef enum {
|
|
STNODE = 0x00,
|
|
STSERVER = 0x01,
|
|
STMEDIA = 0x02,
|
|
STROUTE = 0x03,
|
|
STBACKUP = 0x04,
|
|
STCONFIG = 0x05
|
|
} artnet_node_style_code;
|
|
|
|
// artnet_port_data in artnet.h
|
|
|
|
// ArtAddress
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// artnet_port_command_code in artnet.h
|
|
|
|
// ArtFirmwareMaster
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// defines contents of the firmware packet
|
|
typedef enum {
|
|
ARTNET_FIRMWARE_FIRMFIRST = 0x00,
|
|
ARTNET_FIRMWARE_FIRMCONT = 0x01,
|
|
ARTNET_FIRMWARE_FIRMLAST = 0x02,
|
|
ARTNET_FIRMWARE_UBEAFIRST = 0x03,
|
|
ARTNET_FIRMWARE_UBEACONT = 0x04,
|
|
ARTNET_FIRMWARE_UBEALAST = 0x05,
|
|
} artnet_firmware_type_code;
|
|
|
|
// ArtFirmwareReply
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// artnet_firmware_status_code in artnet.h
|
|
|
|
|
|
|
|
// End packet enums
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
/*
|
|
* Data structures to manage callbacks
|
|
*/
|
|
|
|
// packet callbacks have a function and some user data
|
|
typedef struct {
|
|
int (*fh)(artnet_node n, void *p, void *data);
|
|
void *data;
|
|
} callback_t;
|
|
|
|
/*
|
|
* the dmx callback is triggered when a dmx packet arrives
|
|
*/
|
|
typedef struct {
|
|
int (*fh)(artnet_node n, int portid, void *data);
|
|
void *data;
|
|
} dmx_callback_t;
|
|
|
|
/*
|
|
* firmware callback is triggered when a firmware recieve has been completed sucessfully
|
|
*/
|
|
typedef struct {
|
|
int (*fh)(artnet_node n, int ubea, uint16_t *data, int length, void *d);
|
|
void *data;
|
|
} firmware_callback_t;
|
|
|
|
/*
|
|
* called when a node is remote programmed
|
|
*/
|
|
typedef struct {
|
|
int (*fh)(artnet_node n, void *d);
|
|
void *data;
|
|
} program_callback_t;
|
|
|
|
/*
|
|
* called when a node receives rdm data
|
|
*/
|
|
typedef struct {
|
|
int (*fh)(artnet_node n, int address, uint8_t *rdm, int length, void *d);
|
|
void *data;
|
|
} rdm_callback_t;
|
|
|
|
|
|
// struct to store callbacks
|
|
typedef struct {
|
|
callback_t recv;
|
|
callback_t send;
|
|
callback_t poll;
|
|
callback_t reply;
|
|
callback_t dmx;
|
|
callback_t address;
|
|
callback_t input;
|
|
callback_t todrequest;
|
|
callback_t toddata;
|
|
callback_t todcontrol;
|
|
callback_t rdm;
|
|
callback_t ipprog;
|
|
callback_t firmware;
|
|
callback_t firmware_reply;
|
|
dmx_callback_t dmx_c;
|
|
firmware_callback_t firmware_c;
|
|
program_callback_t program_c;
|
|
rdm_callback_t rdm_c;
|
|
dmx_callback_t rdm_init_c;
|
|
dmx_callback_t rdm_tod_c;
|
|
} node_callbacks_t;
|
|
|
|
|
|
// End callback structures
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Begin port structures
|
|
*/
|
|
|
|
|
|
|
|
// first a generic port
|
|
typedef struct {
|
|
uint8_t addr; // the port address
|
|
uint8_t default_addr; // the address set by the hardware
|
|
uint8_t net_ctl; // if the port address is under network control
|
|
uint8_t status; // status of the port
|
|
uint8_t enabled; // true if the port has had it's address set, this is internal only,
|
|
// it's not used by the ArtNet protocol, otherwise the node keeps
|
|
// picking up packets for the 0x00 port
|
|
tod_t tod;
|
|
} g_port_t;
|
|
|
|
/**
|
|
* struct to represent an input port
|
|
* input ports need to keep track of sequence numbers
|
|
* (this doesn't seem to be used though)
|
|
*/
|
|
typedef struct {
|
|
g_port_t port;
|
|
uint8_t seq;
|
|
} input_port_t;
|
|
|
|
|
|
/**
|
|
* For output ports we need to track if they merge in HTP or LTP modes
|
|
*/
|
|
typedef enum {
|
|
ARTNET_MERGE_HTP,
|
|
ARTNET_MERGE_LTP
|
|
} merge_t;
|
|
|
|
/**
|
|
* struct to represent an output port
|
|
*
|
|
* output ports can merge data from two sources in either HTP
|
|
* (highest takes precedence) or LPT (lowest takes precedence) mode
|
|
*
|
|
* we need to store:
|
|
* o The data from each source
|
|
* o The ip of the source
|
|
* o The time the data was recv'ed
|
|
* o the tod table, length and max length
|
|
*/
|
|
typedef struct {
|
|
g_port_t port;
|
|
int length; // the length of the data THAT HAS CHANGED since the last dmx packet
|
|
uint8_t enabled; // true if the port has had it's address set, this is internal only,
|
|
// it's not used by the ArtNet protocol, otherwise the node keeps
|
|
// picking up packets for the 0x00 port
|
|
uint8_t data[ARTNET_DMX_LENGTH]; // output data
|
|
merge_t merge_mode; // for merging
|
|
uint8_t dataA[ARTNET_DMX_LENGTH];
|
|
uint8_t dataB[ARTNET_DMX_LENGTH];
|
|
time_t timeA;
|
|
time_t timeB;
|
|
SI ipA;
|
|
SI ipB;
|
|
} output_port_t;
|
|
|
|
// use defines to hide the inner structures
|
|
#define port_addr port.addr
|
|
#define port_default_addr port.default_addr
|
|
#define port_net_ctl port.net_ctl
|
|
#define port_status port.status
|
|
#define port_enabled port.enabled
|
|
#define port_tod port.tod
|
|
|
|
// End port structures
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
/*
|
|
* We use a linked list to keep track of nodes on the network
|
|
* Here be the structures
|
|
*/
|
|
|
|
/* firstly we have the potential to do a firmware transfer to any node,
|
|
* this struct keeps the information such as how much data has been transfered
|
|
* and the address of the peer. It's also used for receiving firmware
|
|
*/
|
|
typedef struct {
|
|
uint16_t *data;
|
|
int bytes_current;
|
|
int bytes_total;
|
|
struct in_addr peer;
|
|
int ubea;
|
|
time_t last_time;
|
|
int expected_block;
|
|
int (*callback)(artnet_node n, artnet_firmware_status_code code, void *d);
|
|
void *user_data;
|
|
} firmware_transfer_t;
|
|
|
|
/*
|
|
* The node entry in the LL. It contains the public entry, as well as some stuff
|
|
* we don't want public like firmware
|
|
*/
|
|
typedef struct node_entry_private_s {
|
|
artnet_node_entry_t pub;
|
|
struct node_entry_private_s *next;
|
|
firmware_transfer_t firmware;
|
|
SI ip; // don't rely on the ip address that the node
|
|
// sends, they could be faking it. This is the ip that
|
|
// the pollreply was sent from
|
|
} node_entry_private_t;
|
|
|
|
/**
|
|
* The node list stores a pointer to the first, last and current
|
|
* entries.
|
|
*/
|
|
typedef struct {
|
|
node_entry_private_t *first;
|
|
node_entry_private_t *current;
|
|
node_entry_private_t *last;
|
|
int length;
|
|
} node_list_t;
|
|
|
|
|
|
// End node list structures
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// the status of the node
|
|
typedef enum {
|
|
ARTNET_OFF,
|
|
ARTNET_STANDBY,
|
|
ARTNET_ON
|
|
} node_status_t;
|
|
|
|
|
|
// struct to hold the state of the node
|
|
typedef struct {
|
|
artnet_node_type node_type;
|
|
node_status_t mode;
|
|
SI reply_addr;
|
|
SI ip_addr;
|
|
SI bcast_addr;
|
|
uint8_t hw_addr[ARTNET_MAC_SIZE];
|
|
uint8_t default_subnet;
|
|
uint8_t subnet_net_ctl;
|
|
int send_apr_on_change;
|
|
int ar_count;
|
|
int verbose;
|
|
char short_name[ARTNET_SHORT_NAME_LENGTH];
|
|
char long_name[ARTNET_LONG_NAME_LENGTH];
|
|
char report[ARTNET_REPORT_LENGTH];
|
|
uint8_t subnet;
|
|
uint8_t oem_hi;
|
|
uint8_t oem_lo;
|
|
uint8_t esta_hi;
|
|
uint8_t esta_lo;
|
|
int bcast_limit; // the number of nodes after which we change to bcast
|
|
artnet_node_report_code report_code;
|
|
} node_state_t;
|
|
|
|
|
|
typedef struct {
|
|
struct artnet_node_s *peer; // peer if we've joined a group
|
|
int master;
|
|
} node_peering_t;
|
|
|
|
|
|
/**
|
|
* The main node structure
|
|
*/
|
|
typedef struct artnet_node_s{
|
|
int sd; // the two sockets
|
|
node_state_t state; // the state struct
|
|
node_callbacks_t callbacks; // the callbacks struct
|
|
struct ports_s {
|
|
uint8_t types[ARTNET_MAX_PORTS]; // type of port
|
|
input_port_t in[ARTNET_MAX_PORTS]; // input ports
|
|
output_port_t out[ARTNET_MAX_PORTS]; // output ports
|
|
} ports;
|
|
artnet_reply_t ar_temp; // buffered artpoll reply packet
|
|
node_list_t node_list; // node list
|
|
firmware_transfer_t firmware; // firmware details
|
|
node_peering_t peering; // peer if we've joined a group
|
|
} artnet_node_t;
|
|
|
|
|
|
typedef artnet_node_t *node;
|
|
|
|
/*
|
|
* Function definitions follow
|
|
*/
|
|
|
|
// exported from artnet.c
|
|
node_entry_private_t *find_private_entry( node n, artnet_node_entry e);
|
|
void check_timeouts(node n);
|
|
node_entry_private_t *find_entry_from_ip(node_list_t *nl, SI ip);
|
|
int artnet_nl_update(node_list_t *nl, artnet_packet reply);
|
|
|
|
|
|
// exported from receive.c
|
|
int handle(node n, artnet_packet p);
|
|
int16_t get_type(artnet_packet p);
|
|
void reset_firmware_upload(node n);
|
|
|
|
|
|
// exported from transmit.c
|
|
int artnet_tx_poll(node n, const char *ip, artnet_ttm_value_t ttm);
|
|
int artnet_tx_poll_reply(node n, int reply);
|
|
int artnet_tx_tod_data(node n, int id);
|
|
int artnet_tx_firmware_reply(node n, in_addr_t ip, artnet_firmware_status_code code);
|
|
int artnet_tx_firmware_packet(node n, firmware_transfer_t *firm );
|
|
int artnet_tx_tod_request(node n);
|
|
int artnet_tx_tod_control(node n, uint8_t address, artnet_tod_command_code action);
|
|
int artnet_tx_rdm(node n, uint8_t address, uint8_t *data, int length);
|
|
int artnet_tx_build_art_poll_reply(node n);
|
|
|
|
|
|
// exported from network.c
|
|
int artnet_net_recv(node n, artnet_packet p, int block);
|
|
int artnet_net_send(node n, artnet_packet p);
|
|
int artnet_net_set_non_block(node n);
|
|
int artnet_net_init(node n, const char *ip);
|
|
int artnet_net_start(node n);
|
|
int artnet_net_close(int sock);
|
|
int artnet_net_join(node n1, node n2);
|
|
int artnet_net_set_fdset(node n, fd_set *fdset);
|
|
int artnet_net_inet_aton(const char *ip_address, struct in_addr *address);
|
|
const char *artnet_net_last_error();
|
|
|
|
#endif
|