Updated dns_sd/ to match the Arduino build.

cwAvahiSurface.cpp : initial commit.
This commit is contained in:
kpl 2020-02-13 11:29:52 -05:00
parent ef70cd9420
commit f15e06695b
10 changed files with 655 additions and 89 deletions

View File

@ -23,11 +23,11 @@ SRC += cwAudioBuf.cpp cwAudioDevice.cpp cwAudioDeviceAlsa.cpp cwAudioDeviceTest
HDR += cwTcpSocket.h cwTcpSocketSrv.h cwTcpSocketTest.h
SRC += cwTcpSocket.cpp cwTcpSocketSrv.cpp cwTcpSocketTest.cpp
HDR += cwMdns.h cwEuCon.h cwDnsSd.h dns_sd/dns_sd.h dns_sd/dns_sd_print.h dns_sd/dns_sd_const.h dns_sd/fader.h
SRC += cwMdns.cpp cwEuCon.cpp cwDnsSd.cpp dns_sd/dns_sd.cpp dns_sd/dns_sd_print.cpp dns_sd/fader.cpp
HDR += cwMdns.h cwEuCon.h cwDnsSd.h dns_sd/dns_sd.h dns_sd/dns_sd_print.h dns_sd/dns_sd_const.h dns_sd/fader.h dns_sd/rpt.h
SRC += cwMdns.cpp cwEuCon.cpp cwDnsSd.cpp dns_sd/dns_sd.cpp dns_sd/dns_sd_print.cpp dns_sd/fader.cpp dns_sd/rpt.cpp
# HDR += cwIo.h cwIoTest.h cwNbMem.h
# SRC += cwIo.cpp cwIoTest.cpp cwNbMem.cpp
HDR += cwIo.h cwIoTest.h
SRC += cwIo.cpp cwIoTest.cpp
LIBS = -lpthread -lwebsockets -lasound

473
cwAvahiSurface.cpp Normal file
View File

@ -0,0 +1,473 @@
#include <avahi-client/client.h>
#include <avahi-client/publish.h>
#include <avahi-common/alternative.h>
#include <avahi-common/thread-watch.h>
#include <avahi-common/malloc.h>
#include <avahi-common/error.h>
#include <avahi-common/timeval.h>
#include <avahi-common/strlst.h>
#include "cwCommon.h"
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwTime.h"
#include "cwThread.h"
#include "cwTcpSocket.h"
using namespace cw;
using namespace cw::net;
#define INSTANCE_NAME "MC Mix"
#define SERVICE_NAME "_EuConProxy._tcp"
#define SERVICE_PORT 49168
#define SERVICE_HOST nullptr //"Euphonix-MC-38C9863744E7.local"
#define ENET_INTERFACE "ens9"
#define SERVICE_TXT_0 "lmac=38-C9-86-37-44-E7"
#define SERVICE_TXT_1 "dummy=0"
#define HOST_MAC "hmac=00-E0-4C-A9-A4-8D" // mbp19 enet MAC
typedef struct app_str
{
AvahiEntryGroup *group = nullptr;
AvahiThreadedPoll *poll = nullptr;
char *name = nullptr;
unsigned instanceId = 0;
socket::handle_t tcpH;
thread::handle_t tcpThreadH;
unsigned recvBufByteN = 4096;
unsigned protocolState = 0;
unsigned txtXmtN = 0;
time::spec_t t0;
} app_t;
static void create_services(app_t* app, AvahiClient *c);
void errorv( app_t* app, const char* fmt, va_list vl )
{
vprintf(fmt,vl);
}
void logv( app_t* app, const char* fmt, va_list vl )
{
vprintf(fmt,vl);
}
void error( app_t* app, const char* fmt, ... )
{
va_list vl;
va_start(vl,fmt);
errorv( app, fmt, vl );
va_end(vl);
}
void rpt( app_t* app, const char* fmt, ... )
{
va_list vl;
va_start(vl,fmt);
logv( app, fmt, vl );
va_end(vl);
}
void choose_new_service_name( app_t* app )
{
char buf[255];
app->instanceId += 1;
snprintf(buf,sizeof(buf),"%s - %i", INSTANCE_NAME, app->instanceId);
char* n = avahi_strdup(buf);
avahi_free(app->name);
app->name = n;
rpt(app,"Service name collision, renaming service to '%s'\n", app->name);
}
static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata)
{
app_t* app = (app_t*)userdata;
assert(g == app->group || app->group == nullptr);
app->group = g;
// Called whenever the entry group state changes
switch (state)
{
case AVAHI_ENTRY_GROUP_ESTABLISHED :
// The entry group has been established successfully
rpt( app, "Service '%s' successfully established.\n", app->name);
break;
case AVAHI_ENTRY_GROUP_COLLISION :
{
// A service name collision with a remote service happened. Let's pick a new name.
choose_new_service_name(app);
// And recreate the services
create_services(app,avahi_entry_group_get_client(g));
break;
}
case AVAHI_ENTRY_GROUP_FAILURE :
error(app,"Entry group failure: %s\n", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
/* Some kind of failure happened while we were registering our services */
avahi_threaded_poll_quit(app->poll);
break;
case AVAHI_ENTRY_GROUP_UNCOMMITED:
case AVAHI_ENTRY_GROUP_REGISTERING:
;
}
}
static void create_services(app_t* app, AvahiClient *c)
{
int ret;
AvahiPublishFlags flags = (AvahiPublishFlags)0;
assert(c);
// If this is the first time we're called, create a new entry group
if (!app->group)
{
if (!(app->group = avahi_entry_group_new(c, entry_group_callback, app)))
{
error(app,"avahi_entry_group_new() failed: %s\n", avahi_strerror(avahi_client_errno(c)));
goto fail;
}
}
// If the group is empty (either because it was just created, or because it was reset previously, add our entries.
if (avahi_entry_group_is_empty(app->group))
{
rpt(app,"Adding service '%s'\n", app->name);
// Add the service to the group
if ((ret = avahi_entry_group_add_service(app->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, flags, app->name, SERVICE_NAME, nullptr, SERVICE_HOST, SERVICE_PORT, SERVICE_TXT_0, SERVICE_TXT_1, nullptr)) < 0)
{
if (ret == AVAHI_ERR_COLLISION)
goto collision;
error(app, "Failed to add _ipp._tcp service: %s\n", avahi_strerror(ret));
goto fail;
}
// Tell the server to register the service
if ((ret = avahi_entry_group_commit(app->group)) < 0)
{
error(app,"Failed to commit entry group: %s\n", avahi_strerror(ret));
goto fail;
}
}
return;
collision:
// A service name collision with a local service happened. Pick a new name.
choose_new_service_name(app);
avahi_entry_group_reset(app->group);
create_services(app,c);
return;
fail:
avahi_threaded_poll_quit(app->poll);
}
static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata)
{
assert(c);
app_t* app = (app_t*)userdata;
// Called whenever the client or server state changes
switch (state)
{
case AVAHI_CLIENT_S_RUNNING:
// The server has startup successfully and registered its host
// name on the network, so it's time to create our services
create_services(app,c);
break;
case AVAHI_CLIENT_FAILURE:
error(app,"Client failure: %s\n", avahi_strerror(avahi_client_errno(c)));
avahi_threaded_poll_quit(app->poll);
break;
case AVAHI_CLIENT_S_COLLISION:
// Let's drop our registered services. When the server is back
// in AVAHI_SERVER_RUNNING state we will register them
// again with the new host name.
rpt(app,"S Collision\n");
case AVAHI_CLIENT_S_REGISTERING:
rpt(app,"S Registering\n");
// The server records are now being established. This
// might be caused by a host name change. We need to wait
// for our own records to register until the host name is
// properly esatblished.
if (app->group)
avahi_entry_group_reset(app->group);
break;
case AVAHI_CLIENT_CONNECTING:
;
}
}
rc_t _send_response( app_t* app, const unsigned char* buf, unsigned bufByteN )
{
rc_t rc;
if((rc = socket::send( app->tcpH, buf, bufByteN )) != kOkRC )
{
error(app,"Send failed.");
}
return rc;
}
rc_t send_response1( app_t* app )
{
// wifi: 98 5A EB 89 BA AA
// enet: 38 C9 86 37 44 E7
unsigned char buf[] =
{ 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x02,0x03,0xfc,0x01,0x05,
0x06,0x00,
0x38,0xc9,0x86,0x37,0x44,0xe7,
0x01,0x00,
0xc0,0xa8,0x00,0x44,
0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x03,0xff,0x00,0x30,0x08,0x00,0x00,0x80,0x00,0x40,0x01,0x01,0x00,0x00,0x00,0x00,
0x00,0x00
};
return _send_response(app,buf,sizeof(buf));
}
rc_t send_response2( app_t* app )
{
unsigned char buf[] = { 0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x08 };
return _send_response(app,buf,sizeof(buf));
}
rc_t send_heart_beat( app_t* app )
{
unsigned char buf[] = { 0x03,0x00,0x00,0x00 };
return _send_response(app,buf,sizeof(buf));
}
rc_t send_txt( app_t* app, bool updateFl=true )
{
rc_t rc = kOkRC;
int ret;
const char* array[] =
{
"lmac=38-C9-86-37-44-E7",
"host=mbp19",
"hmac=BE-BD-EA-31-F9-88",
"dummy=1"
};
AvahiStringList* list = avahi_string_list_new_from_array(array,4);
if( updateFl )
ret = avahi_entry_group_update_service_txt_strlst(app->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0, app->name, SERVICE_NAME, nullptr, list);
else
ret = avahi_entry_group_add_service_strlst(app->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0, app->name, SERVICE_NAME, nullptr, nullptr, SERVICE_PORT, list);
if(ret < 0)
{
error(app,"Failed to %s entry group text: %s\n", updateFl ? "update" : "add", avahi_strerror(ret));
goto fail;
}
avahi_string_list_free(list);
fail:
return rc;
}
bool tcpReceiveCallback( void* arg )
{
app_t* app = static_cast<app_t*>(arg);
socket::handle_t sockH = app->tcpH;
char buf[ app->recvBufByteN ];
unsigned readByteN = 0;
rc_t rc = kOkRC;
time::spec_t t1;
if( !socket::isConnected(sockH) )
{
if((rc = socket::accept( sockH )) == kOkRC )
{
rpt(app,"TCP connected.\n");
}
}
else
{
if((rc = socket::receive( sockH, buf, app->recvBufByteN, &readByteN, nullptr )) == kOkRC || rc == kTimeOutRC )
{
if( rc == kTimeOutRC )
{
}
else
if( readByteN > 0 )
{
unsigned* h = (unsigned*)buf;
unsigned id = h[0];
switch( app->protocolState )
{
case 0:
if( id == 10 )
{
send_response1(app);
sleepMs(20);
send_heart_beat(app);
app->protocolState+=1;
}
break;
case 1:
{
if( buf[0] == 0x0c )
{
send_response2(app);
app->protocolState+=1;
time::get(app->t0);
}
}
break;
case 2:
{
time::get(t1);
if( time::elapsedMs( &app->t0, &t1 ) >= 4000 )
{
send_heart_beat(app);
app->t0 = t1;
}
}
break;
}
}
}
}
return true;
}
int main( int argc, const char* argv[] )
{
AvahiClient *client = nullptr;
int err_code;
int ret = 1;
const unsigned sbufN = 31;
char sbuf[ sbufN+1 ];
app_t app;
rc_t rc;
unsigned tcpTimeOutMs = 50;
cw::log::createGlobal();
// create the TCP socket
if((rc = socket::create(
app.tcpH,
SERVICE_PORT,
socket::kTcpFl | socket::kBlockingFl | socket::kStreamFl | socket::kListenFl,
tcpTimeOutMs,
NULL,
socket::kInvalidPortNumber )) != kOkRC )
{
rc = cwLogError(rc,"mDNS TCP socket create failed.");
goto errLabel;
}
unsigned char mac[6];
socket::get_mac( app.tcpH, mac, nullptr, ENET_INTERFACE );
for(int i=0; i<6; ++i)
printf("%02x:",mac[i]);
// create the TCP listening thread
if((rc = thread::create( app.tcpThreadH, tcpReceiveCallback, &app )) != kOkRC )
goto errLabel;
// Allocate Avahi thread
if (!(app.poll = avahi_threaded_poll_new()))
{
error(&app,"Failed to create simple poll object.\n");
goto errLabel;
}
// Assign the service name
app.name = avahi_strdup(INSTANCE_NAME);
// Allocate a new client
if((client = avahi_client_new(avahi_threaded_poll_get(app.poll), (AvahiClientFlags)0, client_callback, &app, &err_code)) == nullptr )
{
error(&app,"Failed to create client: %s\n", avahi_strerror(err_code));
goto errLabel;
}
// start the tcp thread
if((rc = thread::unpause( app.tcpThreadH )) != kOkRC )
goto errLabel;
// start the avahi thread
avahi_threaded_poll_start(app.poll);
while( true )
{
printf("? ");
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
{
if( strcmp(sbuf,"quit\n") == 0)
break;
}
}
avahi_threaded_poll_stop(app.poll);
ret = 0;
errLabel:
//if (client)
// avahi_client_free(client);
thread::destroy(app.tcpThreadH);
socket::destroy(app.tcpH);
if (app.poll)
avahi_threaded_poll_free(app.poll);
avahi_free(app.name);
cw::log::destroyGlobal();
return ret;
}

View File

@ -10,6 +10,8 @@
#include "cwDnsSd.h"
#include "cwUtility.h"
#include "dns_sd/rpt.h"
#include "dns_sd/dns_sd.h"
#include "dns_sd/fader.h"
@ -46,17 +48,25 @@ namespace cw
char* hostIpAddr;
uint16_t hostPort;
unsigned char hostMac[6];
unsigned ticksPerHeartBeat;
unsigned cbCnt;
time::spec_t t0;
} dnssd_t;
void print_callback( const char* text )
{
printf("%s",text);
}
inline dnssd_t* _handleToPtr( handle_t h )
{
return handleToPtr<handle_t,dnssd_t>(h);
}
rc_t _destroy( dnssd_t* p )
{
rc_t rc = kOkRC;
@ -132,7 +142,7 @@ namespace cw
if( dataByteCnt > 0 )
{
p->fdr->host_receive( data, dataByteCnt );
p->fdr->receive( data, dataByteCnt );
}
time::spec_t t1;
@ -219,17 +229,17 @@ namespace cw
delete p->dnsSd;
// create the MDNS logic object
p->dnsSd = new dns_sd(udpSendCallback,p);
p->dnsSd = new dns_sd(udpSendCallback,p,print_callback);
// create the Surface logic object
p->fdr = new fader(p->hostMac, hostAddr.sin_addr.s_addr, tcpSendCallback, p );
p->fdr = new fader(print_callback, p->hostMac, hostAddr.sin_addr.s_addr, tcpSendCallback, p, p->ticksPerHeartBeat );
// Setup the internal dnsSd object
p->dnsSd->setup( p->serviceName, p->serviceType, p->serviceDomain, p->hostName, hostAddr.sin_addr.s_addr, p->hostPort, formatStr );
free(formatStr);
p->dnsSd->gen_response();
p->dnsSd->gen_question();
return rc;
}
@ -292,13 +302,14 @@ cw::rc_t cw::net::dnssd::createV( handle_t& hRef, const char* name, const char*
goto errLabel;
}
p->serviceName = mem::duplStr(name);
p->serviceType = mem::duplStr(type);
p->serviceDomain = mem::duplStr(domain);
p->hostName = mem::duplStr(hostName);
p->hostIpAddr = mem::duplStr(hostIpAddr);
p->hostPort = hostPort;
p->dnsSd = nullptr;
p->serviceName = mem::duplStr(name);
p->serviceType = mem::duplStr(type);
p->serviceDomain = mem::duplStr(domain);
p->hostName = mem::duplStr(hostName);
p->hostIpAddr = mem::duplStr(hostIpAddr);
p->hostPort = hostPort;
p->dnsSd = nullptr;
p->ticksPerHeartBeat = 50;
memcpy(p->hostMac,hostMac,6);
if((rc = _setTextRecdFieldsV( p, text, vl )) != kOkRC )

View File

@ -159,7 +159,8 @@ namespace cw
{
if( dataByteCnt >= 4 )
{
//printHex(data,dataByteCnt);
printHex(data,dataByteCnt);
unsigned hdr = *(const unsigned*)data;
switch( p->protoState )

View File

@ -1,20 +1,29 @@
#include "dns_sd.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#ifdef cwLINUX
#include <arpa/inet.h>
#endif
#ifdef ARDUINO
#include <utility/util.h>
#endif
#include "rpt.h"
#include "dns_sd.h"
#include "dns_sd_const.h"
#include "dns_sd_print.h"
#define DNS_SD_SERVICE_TYPE_STRING "_services._dns-sd._udp"
dns_sd::dns_sd(sendCallback_t sendCbFunc, void* sendCbArg )
: _sendCbFunc(sendCbFunc),_sendCbArg(sendCbArg),_serviceName(nullptr),_serviceType(nullptr),_serviceDomain(nullptr),_hostName(nullptr),_hostPort(0),_text(nullptr)
dns_sd::dns_sd(sendCallback_t sendCbFunc, void* sendCbArg, printCallback_t printCbFunc )
: _sendCbFunc(sendCbFunc),_sendCbArg(sendCbArg),_printCbFunc(printCbFunc),_serviceName(nullptr),_serviceType(nullptr),_serviceDomain(nullptr),_hostName(nullptr),_hostPort(0),_text(nullptr)
{}
dns_sd::dns_sd( sendCallback_t sendCbFunc, void* sendCbArg, const char* serviceName, const char* serviceType, const char* serviceDomain, const char* hostName, uint32_t hostAddr, uint16_t hostPort, const char* text )
: _sendCbFunc(sendCbFunc),_sendCbArg(sendCbArg),_serviceName(nullptr),_serviceType(nullptr),_serviceDomain(nullptr),_hostName(nullptr),_hostPort(0),_text(nullptr)
dns_sd::dns_sd( sendCallback_t sendCbFunc, void* sendCbArg, printCallback_t printCbFunc, const char* serviceName, const char* serviceType, const char* serviceDomain, const char* hostName, uint32_t hostAddr, uint16_t hostPort, const char* text )
: _sendCbFunc(sendCbFunc),_sendCbArg(sendCbArg),_printCbFunc(printCbFunc),_serviceName(nullptr),_serviceType(nullptr),_serviceDomain(nullptr),_hostName(nullptr),_hostPort(0),_text(nullptr)
{
setup( serviceName, serviceType, serviceDomain, hostName, hostAddr, hostPort, text );
}
@ -52,7 +61,6 @@ void dns_sd::gen_question()
_format_question(b, n);
_send(b,n);
free(b);
}
void dns_sd::gen_response()
@ -76,9 +84,14 @@ void dns_sd::_free()
unsigned dns_sd::_calc_question_byte_count()
{
unsigned n = kHdrBodyByteN;
// Question
n += 1 + strlen(_serviceName) + 1 + strlen(_serviceType) + 1 + strlen(_serviceDomain) + 1 + kQuestionBodyByteN;
n += 2 + kRsrcBodyByteN + kSrvBodyByteN + 1 + strlen(_hostName) + 2;
//n += 2 + kRsrcBodyByteN + strlen(_text) + 1;
// SRV
n += 2 + kRsrcBodyByteN + kSrvBodyByteN + 1 + strlen(_hostName) + 2;
// TXT
n += 2 + kRsrcBodyByteN + strlen(_text) + 1;
return n;
}
@ -92,7 +105,7 @@ void dns_sd::_format_question( unsigned char* buf, unsigned bufByteN )
u[1] = htons(0); // flags
u[2] = htons(1); // question
u[3] = htons(0); // answer
u[4] = htons(1); // name server
u[4] = htons(2); // name server
u[5] = htons(0); // other
unsigned char* b = (unsigned char*)(u + 6);
@ -111,7 +124,7 @@ void dns_sd::_format_question( unsigned char* buf, unsigned bufByteN )
b = _write_uint16( b, bend, kInClassDnsFl );
// Format SRV name server
b = _write_ptr( namePtr, b, bend ); // name
b = _write_ptr( b, bend, namePtr ); // name
b = _write_uint16( b, bend, kSRV_DnsTId ); // type
b = _write_uint16( b, bend, kInClassDnsFl ); // class
b = _write_uint32( b, bend, 120 ); // TTL
@ -121,16 +134,19 @@ void dns_sd::_format_question( unsigned char* buf, unsigned bufByteN )
b = _write_uint16( b, bend, _hostPort ); // port
b = _write_text( b, bend, _hostName ); // host
b = _write_ptr( b, bend, domainPtr ); // host suffix (.local)
/*
// Format TXT name server
b = _write_ptr( namePtr, b, bend ); // name
b = _write_uint16( kTXT_DnsTId, b, bend ); // type
b = _write_uint16( kInClassDnsFl, b, bend ); // class
b = _write_uint32( 4500, b, bend ); // TTL
b = _write_uint16( strlen(_text),b, bend ); // dlen
b = _write_text( _text, b, bend ); // text
*/
assert( b == bend );
b = _write_ptr( b, bend, namePtr ); // name
b = _write_uint16( b, bend, kTXT_DnsTId ); // type
b = _write_uint16( b, bend, kInClassDnsFl ); // class
b = _write_uint32( b, bend, 4500 ); // TTL
b = _write_uint16( b, bend, strlen(_text)+1 ); // dlen
b = _write_text( b, bend, _text ); // text
//assert( b == bend );
//rpt(_printCbFunc,"%i %i : %s\n", b - buf, bend - buf, _text );
}
unsigned char* dns_sd::_write_uint16( unsigned char* b, unsigned char* bend, uint16_t value )
@ -152,6 +168,8 @@ unsigned char* dns_sd::_write_uint32( unsigned char* b, unsigned char* bend, uin
unsigned char* dns_sd::_write_ptr( unsigned char* b, unsigned char* bend, const unsigned char ptr[2] )
{
assert( (ptr[0] & 0xc0) == 0xc0 );
assert( bend - b >= 2 );
b[0] = ptr[0];
b[1] = ptr[1];
return b+2;
@ -291,13 +309,15 @@ void dns_sd::_format_response( unsigned char* buf, unsigned bufByteN )
b = _write_ptr( b, bend, typePtr );
printf("%li %li : %s\n", b - buf, bend - buf, _text );
//rpt(_printCbFunc,"%i %i : %s\n", b - buf, bend - buf, _text );
}
void dns_sd::_parse( const char* buf, unsigned bufByteN )
{
dns_sd_print(buf,bufByteN);
//(void)buf;
//(void)bufByteN;
dns_sd_print(_printCbFunc,buf,bufByteN);
}
void dns_sd::_send( const void* buf, unsigned bufByteN )

View File

@ -14,8 +14,8 @@ public:
typedef void (*sendCallback_t)( void* arg, const void* buf, unsigned bufByteN );
dns_sd( sendCallback_t sendCbFunc, void* sendCbArg );
dns_sd( sendCallback_t sendCbFunc, void* sendCbArg, const char* serviceName, const char* serviceType, const char* serviceDomain, const char* hostName, uint32_t hostAddr, uint16_t hostPort, const char* text );
dns_sd( sendCallback_t sendCbFunc, void* sendCbArg, printCallback_t printCbFunc );
dns_sd( sendCallback_t sendCbFunc, void* sendCbArg, printCallback_t printCbFunc, const char* serviceName, const char* serviceType, const char* serviceDomain, const char* hostName, uint32_t hostAddr, uint16_t hostPort, const char* text );
virtual ~dns_sd();
result_t setup( const char* serviceName, const char* serviceType, const char* serviceDomain, const char* hostName, uint32_t hostAddr, uint16_t hostPort, const char* text );
@ -38,15 +38,16 @@ private:
};
sendCallback_t _sendCbFunc;
void* _sendCbArg;
char* _serviceName;
char* _serviceType;
char* _serviceDomain;
char* _hostName;
uint32_t _hostAddr;
uint16_t _hostPort;
char* _text;
sendCallback_t _sendCbFunc;
void* _sendCbArg;
printCallback_t _printCbFunc;
char* _serviceName;
char* _serviceType;
char* _serviceDomain;
char* _hostName;
uint32_t _hostAddr;
uint16_t _hostPort;
char* _text;
void _free();

View File

@ -1,13 +1,24 @@
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#ifdef cwLINUX
#include <arpa/inet.h>
#endif
#ifdef ARDUINO
#include <utility/util.h>
#endif
#include "rpt.h"
#include "dns_sd.h"
#include "dns_sd_print.h"
#include "dns_sd_const.h"
unsigned _print_name( const char* s, const char* buf )
int _print_name( printCallback_t printCbFunc, const unsigned char* s, const unsigned char* buf )
{
unsigned n = 0; // track allocated length of the name in this record
int n = 0; // track allocated length of the name in this record
bool incrFl = true; // do not incrmement 'n' if the name switches to a ptr segment
while( *s )
@ -23,10 +34,12 @@ unsigned _print_name( const char* s, const char* buf )
{
for(char i=0; i<s[0]; ++i)
{
printf("%c",s[i+1]);
char x[2];
x[0] = s[i+1];
x[1] = 0;
rpt(printCbFunc,"%s",x);
if( incrFl )
++n;
++n;
}
s += s[0]+1;
@ -34,54 +47,56 @@ unsigned _print_name( const char* s, const char* buf )
if(*s)
{
printf(".");
rpt(printCbFunc,".");
}
}
}
return n;
}
void dns_sd_print( const void* buf, unsigned bufByteN )
void dns_sd_print( printCallback_t printCbFunc, const void* buf, unsigned bufByteN )
{
const uint16_t* u = (uint16_t*)buf;
const char* b = (const char*)(u+6);
(void)bufByteN;
printf("%s ", ntohs(u[1]) & 0x8000 ? "Response " : "Question ");
const uint16_t* u = (uint16_t*)buf;
const unsigned char* b = (const unsigned char*)(u+6);
rpt(printCbFunc,"%s ", ntohs(u[1]) & 0x8000 ? "Response:" : "Question:");
unsigned n = _print_name(b,(const char*)buf);
int n = _print_name(printCbFunc,b,(const unsigned char*)buf);
rpt(printCbFunc," slen:%i ", n);
printf(" slen:%i ",n);
u = (uint16_t*)(b + n+1); // advance past name
u = (uint16_t*)(b + n + 1); // advance past name
switch( ntohs(u[0]) )
{
case kA_DnsTId: printf("A ");
case kA_DnsTId: rpt(printCbFunc,"A ");
break;
case kPTR_DnsTId: printf("PTR ");
case kPTR_DnsTId: rpt(printCbFunc,"PTR ");
break;
case kTXT_DnsTId: printf("TXT ");
case kTXT_DnsTId: rpt(printCbFunc,"TXT ");
break;
case kSRV_DnsTId: printf("SRV ");
case kSRV_DnsTId: rpt(printCbFunc,"SRV ");
break;
case kAAAA_DnsTId:printf("AAAA ");
case kAAAA_DnsTId:rpt(printCbFunc,"AAAA ");
break;
case kOPT_DnsTId: printf("OPT ");
case kOPT_DnsTId: rpt(printCbFunc,"OPT ");
break;
case kNSEC_DnsTId:printf("NSEC "); break;
case kANY_DnsTId: printf("ANY "); break;
case kNSEC_DnsTId:rpt(printCbFunc,"NSEC "); break;
case kANY_DnsTId: rpt(printCbFunc,"ANY "); break;
default:
printf("<unk> 0x%2x",ntohs(u[0])); break;
rpt(printCbFunc,"<unk> 0x%2x",ntohs(u[0])); break;
}
if( ntohs(u[1]) & 0x80 )
printf("flush ");
rpt(printCbFunc,"flush ");
printf("\n");
rpt(printCbFunc,"\n");
}

View File

@ -1,7 +1,7 @@
#ifndef print_dns_sd_h
#define print_dns_sd_h
void dns_sd_print( const void* buf, unsigned bufByteN );
void dns_sd_print( printCallback_t printCbFunc, const void* buf, unsigned bufByteN );
#endif

View File

@ -2,11 +2,14 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "rpt.h"
#include "fader.h"
fader::fader( const unsigned char faderMac[6], uint32_t faderInetAddr, hostCallback_t hostCbFunc, void* hostCbArg, unsigned chN )
: _inetAddr(faderInetAddr),_lastTickSeconds(0),_chArray(nullptr),_hostCbFunc(hostCbFunc),_hostCbArg(hostCbArg),_protoState(kWaitForHandshake_0_Id)
fader::fader( printCallback_t printCbFunc, const unsigned char faderMac[6], uint32_t faderInetAddr, hostCallback_t hostCbFunc, void* hostCbArg, unsigned ticksPerHeartBeat, unsigned chN )
: _printCbFunc(printCbFunc), _inetAddr(faderInetAddr),_tickN(0),_chArray(nullptr),_hostCbFunc(hostCbFunc),_hostCbArg(hostCbArg),_protoState(kWaitForHandshake_0_Id),_ticksPerHeartBeat(ticksPerHeartBeat)
{
memcpy(_mac,faderMac,6);
@ -24,18 +27,19 @@ fader::~fader()
delete[] _chArray;
}
fader::rc_t fader::host_receive( const void* buf, unsigned bufByteN )
fader::rc_t fader::receive( const void* buf, unsigned bufByteN )
{
rc_t rc = kOkRC;
printf("FDR:%i\n",bufByteN);
const uint8_t* b = (const uint8_t*)buf;
_printCbFunc("FDR ");
switch( _protoState )
{
case kWaitForHandshake_0_Id:
if( bufByteN>0 && ((uint8_t*)buf)[0] == 10 )
if( bufByteN>0 && b[0] == 10 )
{
printf("HS 0\n");
_printCbFunc("HS 0 ");
_send_response_0();
_protoState = kWaitForHandshake_Tick_Id;
}
@ -45,7 +49,8 @@ fader::rc_t fader::host_receive( const void* buf, unsigned bufByteN )
break;
case kWaitForHandshake_1_Id:
printf("HS 1: %i",bufByteN);
_printCbFunc("HS 1 ");
_send_response_1();
_protoState = kWaitForHeartBeat_Id;
break;
@ -64,31 +69,45 @@ fader::rc_t fader::tick()
break;
case kWaitForHandshake_Tick_Id:
printf("HS Tick");
_printCbFunc("HS Tick ");
_send_heartbeat();
_protoState = kWaitForHandshake_1_Id;
break;
case kWaitForHandshake_1_Id:
break;
case kWaitForHeartBeat_Id:
case kWaitForHeartBeat_Id:
break;
}
_tickN += 1;
if( _tickN == _ticksPerHeartBeat )
{
_tickN = 0;
_send_heartbeat();
}
return rc;
}
fader::rc_t fader::physical_fader_touched( uint16_t chanIdx )
{
(void)chanIdx;
return kOkRC;
}
fader::rc_t fader::physical_fader_moved( uint16_t chanIdx, uint16_t value )
{
(void)chanIdx;
(void)value;
return kOkRC;
}
fader::rc_t fader::physical_mute_switched( uint16_t chanIdx, bool value )
{
(void)chanIdx;
(void)value;
return kOkRC;
}
@ -97,9 +116,9 @@ void fader::_send_response_0()
unsigned char buf[] =
{ 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x02,0x03,0xfc,0x01,0x05,
0x06,0x00,
0x38,0xc9,0x86,0x37,0x44,0xe7, // mac: 16
0x38,0xc9,0x86,0x37,0x44,0xe7, // mac: offset 16
0x01,0x00,
0xc0,0xa8,0x00,0x44, // ip: 24
0xc0,0xa8,0x00,0x44, // ip: offset 24
0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
@ -113,6 +132,14 @@ void fader::_send_response_0()
_send(buf,sizeof(buf));
}
void fader::_send_response_1()
{
unsigned char buf[] = { 0x0d,0x00,0x00,0x00, 0x00,0x00,0x00,0x08 };
_send(buf,sizeof(buf));
}
void fader::_send_heartbeat()
{
const unsigned char buf[] = { 0x03, 0x00, 0x00, 0x00 };
@ -126,9 +153,13 @@ void fader::_send( const void* buf, unsigned bufByteN )
void fader::_on_fader_receive( uint16_t chanIdx, uint16_t value )
{
(void)chanIdx;
(void)value;
}
void fader::_on_mute_receive( uint16_t chanIdx, bool value )
{
(void)chanIdx;
(void)value;
}

View File

@ -2,6 +2,17 @@
#define fader_h
/*
1. wait for 0x0a packet
send_response_0()
wait 50 ms
send_heart_beat()
2. wait for next host packet
send_response_1()
*/
class fader
{
public:
@ -15,13 +26,13 @@ public:
// Function to send TCP messages to the host.
typedef void (*hostCallback_t)( void* arg, const void* buf, unsigned bufByteN );
fader( const unsigned char faderMac[6], uint32_t faderInetAddr, hostCallback_t hostCbFunc, void* cbArg, unsigned chN = 8 );
fader( printCallback_t printCbFunc, const unsigned char faderMac[6], uint32_t faderInetAddr, hostCallback_t hostCbFunc, void* cbArg, unsigned ticksPerHeartBeat, unsigned chN = 8 );
virtual ~fader();
// Called by the TCP receive function to update the faders state
// based on host state changes.
// Return kUnknownMsgRC if the received msg is not recognized.
rc_t host_receive( const void* buf, unsigned bufByteN );
rc_t receive( const void* buf, unsigned bufByteN );
// Called by the application to drive time dependent functions.
// Return kTimeOut if the protocol state machine has timed out.
@ -48,16 +59,19 @@ private:
bool muteFl;
} ch_t;
printCallback_t _printCbFunc;
uint32_t _inetAddr;
unsigned _lastTickSeconds;
unsigned _tickN;
ch_t* _chArray;
unsigned _chN;
hostCallback_t _hostCbFunc;
void* _hostCbArg;
protoState_t _protoState;
unsigned char _mac[6];
unsigned _ticksPerHeartBeat;
void _send_response_0();
void _send_response_1();
void _send_heartbeat();
void _send( const void* buf, unsigned bufByteN );
void _on_fader_receive( uint16_t chanIdx, uint16_t position );