diff --git a/Makefile b/Makefile index f0f31e8..643476d 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/cwAvahiSurface.cpp b/cwAvahiSurface.cpp new file mode 100644 index 0000000..1e9d18e --- /dev/null +++ b/cwAvahiSurface.cpp @@ -0,0 +1,473 @@ + +#include +#include + +#include +#include +#include +#include +#include +#include + + +#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(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; +} diff --git a/cwDnsSd.cpp b/cwDnsSd.cpp index a8b8a99..44caa59 100644 --- a/cwDnsSd.cpp +++ b/cwDnsSd.cpp @@ -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(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 ) diff --git a/cwEuCon.cpp b/cwEuCon.cpp index fd70963..3daafd0 100644 --- a/cwEuCon.cpp +++ b/cwEuCon.cpp @@ -159,7 +159,8 @@ namespace cw { if( dataByteCnt >= 4 ) { - //printHex(data,dataByteCnt); + printHex(data,dataByteCnt); + unsigned hdr = *(const unsigned*)data; switch( p->protoState ) diff --git a/dns_sd/dns_sd.cpp b/dns_sd/dns_sd.cpp index 3c676ee..e58c1ad 100644 --- a/dns_sd/dns_sd.cpp +++ b/dns_sd/dns_sd.cpp @@ -1,20 +1,29 @@ -#include "dns_sd.h" #include #include #include + +#ifdef cwLINUX #include +#endif + +#ifdef ARDUINO +#include +#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 ) diff --git a/dns_sd/dns_sd.h b/dns_sd/dns_sd.h index 85cd420..a14a790 100644 --- a/dns_sd/dns_sd.h +++ b/dns_sd/dns_sd.h @@ -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(); diff --git a/dns_sd/dns_sd_print.cpp b/dns_sd/dns_sd_print.cpp index 5c1c3fb..cf245a5 100644 --- a/dns_sd/dns_sd_print.cpp +++ b/dns_sd/dns_sd_print.cpp @@ -1,13 +1,24 @@ #include #include +#include + +#ifdef cwLINUX #include +#endif + +#ifdef ARDUINO +#include +#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 0x%2x",ntohs(u[0])); break; + rpt(printCbFunc," 0x%2x",ntohs(u[0])); break; } if( ntohs(u[1]) & 0x80 ) - printf("flush "); + rpt(printCbFunc,"flush "); - printf("\n"); + rpt(printCbFunc,"\n"); } diff --git a/dns_sd/dns_sd_print.h b/dns_sd/dns_sd_print.h index 4e9ac44..7c55f10 100644 --- a/dns_sd/dns_sd_print.h +++ b/dns_sd/dns_sd_print.h @@ -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 diff --git a/dns_sd/fader.cpp b/dns_sd/fader.cpp index 6cd70ec..28503f7 100644 --- a/dns_sd/fader.cpp +++ b/dns_sd/fader.cpp @@ -2,11 +2,14 @@ #include #include #include +#include +#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; } diff --git a/dns_sd/fader.h b/dns_sd/fader.h index 94e6646..8d9a2e2 100644 --- a/dns_sd/fader.h +++ b/dns_sd/fader.h @@ -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 );