libcw/cwEuCon.cpp
2024-12-01 14:35:24 -05:00

1028 lines
39 KiB
C++

//| Copyright: (C) 2020-2024 Kevin Larke <contact AT larke DOT org>
//| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
#include "cwCommon.h"
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwTest.h"
#include "cwMem.h"
#include "cwObject.h"
#include "cwTime.h"
#include "cwThread.h"
#include "cwSocket.h"
#include "cwUtility.h"
#include "cwEuCon.h"
#include "cwText.h"
#include "cwNumericConvert.h"
#include "dns_sd/dns_sd_const.h"
#include "cwEuConDecls.h"
#define HEART_BEAT "\x04\x00\x00\x00"
#define RESPONSE_1 "\x0a\x00\x00\x00\x6d\x62\x70\x31\x39\x00\x00\x00\x44\x45" \
"\x00\x00\x78\x3f\x39\xe5\xfe\x7f\x00\x00\xc0\x32\x17\x49\xe2\x7f" \
"\x00\x00\xe0\x7d\x2e\x01\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x02\x01\xa8\x03\x00\x60\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x8d\x00\x1f\x0a\xbe\xbd\xea\x31\xf9\x88\xc5\x46\xe2\x7f" \
"\x00\x00\x08\x00\x00\x00\x00\x00\x02\x58"
#define RESPONSE_2 "\x0c\x00\x1f\x0a"
#define RESPONSE_3_A "\x19\x00\x06\x00\x00\x00\x04\x14\x00\x00\x00\x00\x00\x80" \
"\x00\x40\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x54\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\xa8\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x0a\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x19\x01\x06\x00\x00\x00\x04\x14\x00\x00" \
"\x00\x00\x00\x80\x00\x40\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
#define RESPONSE_3_B "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x54\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\xa8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00"
#define RESPONSE_4_A "\x19\x02\x06\x00\x00\x00\x04\x14\x00\x00\x00\x00\x00\x80" \
"\x00\x40\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x54\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\xa8\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x0a\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x19\x03\x06\x00\x00\x00\x04\x14\x00\x00" \
"\x00\x00\x00\x80\x00\x40\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
#define RESPONSE_4_B "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x54\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02\x00\x02" \
"\x00\x02\x00\x02\xa8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00\x08\x00" \
"\x08\x00\x08\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
"\x00\x00"
namespace cw
{
namespace eucon
{
enum
{
kSendHandshake_0_Id, // send [0x0a, ...]
kWaitForHandshake_1_Id, // wait for first heart beat -> then send [0x0c ...]
kWaitForHandshake_2_Id, // wait for [0x0d ...] -> then send response_3_a
kResponse_3_A_Id,
kResponse_3_B_Id,
kResponse_4_A_Id,
kResponse_4_B_Id,
kRunning_Id
};
struct eucon_str;
typedef struct
{
bool muteFl;
} ch_t;
// FBank object
typedef struct fbank_str
{
struct eucon_str* eucon;
unsigned fbIndex;
unsigned sockUserId;
unsigned protoState;
unsigned cbCnt;
time::spec_t nextRecvHbTs;
time::spec_t nextSendHbTs;
struct fbank_str* link;
uint32_t remoteAddr;
ch_t* chA;
unsigned chN;
} fbank_t;
// EuCon manager object
typedef struct eucon_str
{
sock::handle_t sockMgrH; // socket mgr handle
fbank_t* fbankL; // List of fader banks
unsigned maxFaderBankN; // maximum number of fader banks
unsigned sockTimeOutMs; // socket time out
unsigned fdrTcpPort; // Fader TCP port TODO: we shouuld be getting this from the MDNS SRV record
unsigned heartBeatPeriodMs;
} eucon_t;
inline eucon_t* _handleToPtr( handle_t h )
{ return handleToPtr<handle_t,eucon_t>(h); }
rc_t _destroyFBank( eucon_t* p, fbank_t* fb )
{
rc_t rc = kOkRC;
if((rc = sock::destroy(p->sockMgrH, fb->sockUserId )) != kOkRC )
rc = cwLogError(rc,"Fader bank (index:%i) destroy failed.", fb->fbIndex );
return rc;
}
rc_t _destroy( eucon_t* p)
{
rc_t rc = kOkRC;
rc_t rc0;
fbank_t* fb = p->fbankL;
while( fb!=nullptr )
{
fbank_t* fb0 = fb->link;
if((rc0 = _destroyFBank(p,fb)) != kOkRC )
rc = rc0;;
mem::release(fb);
fb = fb0;
}
if( p->sockMgrH.isValid() )
if((rc = sock::destroyMgr(p->sockMgrH)) != kOkRC )
return rc;
mem::release(p);
return rc;
}
rc_t _disconnect( fbank_t* fb )
{
rc_t rc = kOkRC;
//if((rc = sock::destroy(fb->eucon->sockMgrH, fb->sockUserId)) != kOkRC )
// rc = cwLogError(rc,"Socket destroy failed on disconnect attempt on fader bank index:%i.",fb->fbIndex);
fb->protoState = kSendHandshake_0_Id;
return rc;
}
rc_t _send_response( fbank_t* fb, const char* buf, unsigned bufByteN )
{
rc_t rc = kOkRC;
if((rc = sock::send( fb->eucon->sockMgrH, fb->sockUserId, kInvalidId, buf, bufByteN )) != kOkRC )
{
rc = cwLogError(rc,"TCP send failed on fader bank index:%i proto:%i Disconnecting.",fb->fbIndex,fb->protoState);
_disconnect(fb);
}
return rc;
}
rc_t _sendHandshake_0( fbank_t* fb )
{
printf("%i : Sent HS-0: 0x0a\n", fb->fbIndex);
return _send_response(fb,RESPONSE_1,sizeof(RESPONSE_1)-1);
}
rc_t _sendHandshake_1( fbank_t* fb )
{ return _send_response(fb,RESPONSE_2,sizeof(RESPONSE_2)-1); }
rc_t _send_app_msg( fbank_t* fb, uint16_t chIdx, uint16_t msgTypeId, uint16_t value )
{
if( fb->protoState != kRunning_Id )
return kOkRC;
typedef struct fields_str
{
uint16_t channel;
uint16_t typeId;
uint16_t zero;
uint16_t value;
} fields_t;
typedef struct
{
union
{
uint8_t buf[8];
fields_t f;
} u;
} buf_t;
uint16_t v = value;
buf_t b;
b.u.f.channel = chIdx;
b.u.f.typeId = msgTypeId;
b.u.f.zero = 0;
b.u.f.value = ((v & 0xff00) >> 8) + ((v & 0x00ff) << 8);
return _send_response(fb,(char*)(b.u.buf),sizeof(b.u.buf));
}
fbank_t* _createFBank( eucon_t* p, unsigned fbIndex )
{
fbank_t* fb = mem::allocZ<fbank_t>();
fb->eucon = p;
fb->fbIndex = fbIndex;
fb->sockUserId = kBaseSockUserId + fbIndex;
fb->protoState = kSendHandshake_0_Id;
fb->link = p->fbankL;
fb->chN = 8;
fb->chA = mem::allocZ<ch_t>(fb->chN);
p->fbankL = fb;
return fb;
}
fbank_t* _fbIndexToFBank( eucon_t* p, unsigned fbIndex, bool showErrorFl=true )
{
fbank_t* fb = p->fbankL;
for(; fb!=nullptr; fb=fb->link)
if( fb->fbIndex == fbIndex )
return fb;
if( showErrorFl )
cwLogError(kInvalidId,"Fader bank index %i is not valid.", fbIndex );
return nullptr;
}
fbank_t* _ipAddrToFBank( eucon_t* p, uint32_t ipAddr, bool showErrorFl=true )
{
fbank_t* fb = p->fbankL;
for(; fb!=nullptr; fb=fb->link)
if( fb->remoteAddr == ipAddr )
return fb;
if( showErrorFl )
cwLogError(kInvalidId,"Fader bank with dest. addr 0x%x was not found.", ipAddr );
return nullptr;
}
// Heatbeat: 0x03 0x00 0x00 0x00
//
// channel status zero value
// --------- --------- --------- ---------
// 0x00 0x01 0x00 0x00 0x00 0x00 0x02 0x0b fader
// 0x00 0x01 0x02 0x00 0x00 0x00 0x00 0x01 mute
// 0x00 0x01 0x00 0x01 0x00 0x00 0x00 0x00 touch
// 0x00 0x01 0x04 0x00 0x00 0x00 0x00 0x00 ping
void _app_msg_decode(eucon_t* p, fbank_t* fb, const uint8_t* buf, unsigned bufByteN )
{
unsigned bi = 0;
while( bi<bufByteN )
{
char type = 'U';
uint16_t numb = 0;
uint16_t id = 0;
uint16_t chIdx = 0;
unsigned incr = 8;
// if this is a heartbeat msg
if( buf[bi] == kChHb_EuProtoId )
{
type='H';
incr = 4;
}
else
{
uint16_t* v = (uint16_t*)(buf+bi);
chIdx = ntohs(v[0]);
id = ntohs(v[1]);
numb = ntohs(v[3]);
switch(id )
{
case kFPosnEuconId:
type = 'F';
break;
case kTouchEuconId:
type = 'T';
break;
case kFdrMuteEuconId:
{
type = 'M';
fb->chA[chIdx].muteFl = !fb->chA[chIdx].muteFl;
if(_send_app_msg(fb, chIdx, kEucMuteEuconId, !fb->chA[chIdx].muteFl ) != kOkRC )
cwLogError(kOpFailRC,"Send mute msg failed.");
}
break;
case kPingEuconId:
type = 'P';
_send_response(fb,(const char*)(buf+bi),8);
break;
default:
incr = 1;
}
}
if( type != 'H' )
printf("%i %i : %c (0x%x) %i (0x%x)\n",fb->fbIndex, chIdx, type,id,numb,numb);
bi += incr;
}
}
void _tcpCallback( void* arg, sock::cbOpId_t cbOpId, unsigned userId, unsigned connId, const void* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr )
{
eucon_t* p = static_cast<eucon_t*>(arg);
fbank_t* fb;
switch( cbOpId )
{
case sock::kConnectCbId:
cwLogInfo("Connected: user:%i conn:%i", userId, connId );
return;
case sock::kDisconnectCbId:
cwLogInfo("Disconnected: user:%i conn:%i", userId, connId );
return;
case sock::kReceiveCbId:
break;
default:
cwLogError(kInvalidIdRC,"An invalid socket callback id (%i) was received.",cbOpId);
return;
}
// get the fader bank this message is intended for
if((fb = _ipAddrToFBank( p, fromAddr->sin_addr.s_addr )) == nullptr )
{
cwLogError(kOpFailRC,"Fader bank not found. TCP message not delivered.");
return;
}
//
if( data!=nullptr && dataByteCnt >= 4 )
{
//printHex(data,dataByteCnt);
unsigned hdr = *(const unsigned*)data;
switch( fb->protoState )
{
case kWaitForHandshake_1_Id:
if( hdr == kHs1_b_EuProtoId )
{
fb->protoState = kWaitForHandshake_2_Id;
_sendHandshake_1( fb );
cwLogInfo("%i : Rcvd (0x0b) HS 1 - sent 0x0c\n", fb->fbIndex);
}
break;
case kWaitForHandshake_2_Id:
if( hdr == kHs3_d_EuProtoId )
{
fb->protoState = kResponse_3_A_Id;
cwLogInfo("%i : Rcvd (0x0d) HS 2 - Sending setup data\n",fb->fbIndex);
}
break;
}
}
switch(fb->protoState)
{
case kResponse_3_A_Id:
_send_response(fb,RESPONSE_3_A,sizeof(RESPONSE_3_A)-1);
fb->protoState = kResponse_3_B_Id;
break;
case kResponse_3_B_Id:
_send_response(fb,RESPONSE_3_B,sizeof(RESPONSE_3_B)-1);
fb->protoState = kResponse_4_A_Id;
break;
case kResponse_4_A_Id:
_send_response(fb,RESPONSE_4_A,sizeof(RESPONSE_4_A)-1);
fb->protoState = kResponse_4_B_Id;
break;
case kResponse_4_B_Id:
_send_response(fb,RESPONSE_4_B,sizeof(RESPONSE_4_B)-1);
fb->protoState = kRunning_Id;
// set the initial next heart-beat times for this fader bank
time::futureMs(fb->nextSendHbTs,fb->eucon->heartBeatPeriodMs);
break;
case kRunning_Id:
{
_app_msg_decode(p, fb, (const uint8_t*)data, dataByteCnt );
//printf("%i : Rcv: %i : ",fb->fbIndex, dataByteCnt );
//for(unsigned i=0; i<dataByteCnt; ++i)
// printf("0x%02x ",((uint8_t*)data)[i]);
//printf("\n");
}
}
//printf("fbi: %i : proto:%i rcv\n",fb->fbIndex,fb->protoState);
time::futureMs(fb->nextRecvHbTs,fb->eucon->heartBeatPeriodMs*2);
}
rc_t _on_McMix_DNS_SD_TXT( eucon_t* p, const char* numberText, unsigned numberTextCharN, const struct sockaddr_in* fromAddr )
{
rc_t rc = kOkRC;
unsigned tcpFlags = sock::kTcpFl | sock::kBlockingFl | sock::kStreamFl | sock::kReuseAddrFl | sock::kReusePortFl;
fbank_t* fb = nullptr;
unsigned fbIndex = 0;
char fbIP[ INET_ADDRSTRLEN+1 ];
// copy the "MC Mix" suffix number into a zero terminated string
char numbBuf[ numberTextCharN + 1 ];
strncpy(numbBuf,numberText,numberTextCharN);
numbBuf[numberTextCharN] = '\0';
// convert the "MC Mix" suffix to a number
if((rc = string_to_number<unsigned>(numbBuf,fbIndex)) != kOkRC )
return cwLogError(kSyntaxErrorRC,"The 'MC Mix' suffix number could not be parsed.");
// validate the value
if( !(0 < fbIndex && fbIndex <= p->maxFaderBankN ) )
return cwLogError(kInvalidArgRC,"The fader bank number %i is not valid.", fbIndex );
// convert fbIndex to a zero based index
fbIndex -= 1;
// If this fader bank does not already exist ....
if((fb = _fbIndexToFBank(p,fbIndex,false)) == nullptr )
{
// ... then create it
if((fb = _createFBank(p,fbIndex)) == nullptr )
return cwLogError(kOpFailRC,"The fader bank index %i failed.", fbIndex );
}
if( fb->protoState == kSendHandshake_0_Id )
{
// convert the fromAddr to a string
if((rc = sock::addrToString( fromAddr, fbIP, INET_ADDRSTRLEN)) != kOkRC )
return cwLogError(rc,"IP address to string conversion failed.", fbIndex);
// create the TCP socket
if((rc = sock::create( p->sockMgrH, fb->sockUserId, sock::kInvalidPortNumber, tcpFlags, p->sockTimeOutMs, _tcpCallback, p, fbIP, p->fdrTcpPort )) != kOkRC )
return cwLogError(rc,"The TCP socket for fader bank index %i failed. ", fbIndex);
fb->remoteAddr = fromAddr->sin_addr.s_addr;
time::futureMs(fb->nextRecvHbTs,fb->eucon->heartBeatPeriodMs*2);
// Send the initial handshake to the fader bank
_sendHandshake_0( fb );
fb->protoState = kWaitForHandshake_1_Id;
}
return rc;
}
void _udpCallback( void* arg, sock::cbOpId_t cbId, unsigned userId, unsigned connId, const void* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr )
{
rc_t rc = kOkRC;
eucon_t* p = (eucon_t*)arg;
const uint16_t* u = (const uint16_t*)data;
// if this is a DNS-SD reply
if( cwIsFlag(ntohs(u[1]), kReplyHdrDnsFl ) )
{
const char* name = (const char*)(u+6);
const char* label = "MC Mix - ";
unsigned sn = strlen(label);
printf("%.*s|%i\n", name[0], name+1, sn );
// if this a 'MC Mix' DNS-SD SRV reply
if( strncmp(label, name+1, strlen(label)) == 0 )
{
unsigned n = strlen(label);
if((rc = _on_McMix_DNS_SD_TXT( p, name+n+1, name[0]-n, fromAddr )) != kOkRC )
cwLogError(rc,"%.*s initialization failed.",name[0],name+1);
}
}
}
}
}
cw::rc_t cw::eucon::create( handle_t& hRef, const args_t& args )
{
rc_t rc = kOkRC;
unsigned udpFlags = sock::kBlockingFl | sock::kReuseAddrFl | sock::kReusePortFl | sock::kMultiCastTtlFl | sock::kMultiCastLoopFl;
if((rc = destroy(hRef)) != kOkRC )
return rc;
eucon_t* p = mem::allocZ<eucon_t>();
// create the socket manager
if((rc = sock::createMgr(p->sockMgrH, args.recvBufByteN, args.maxSockN)) != kOkRC )
{
rc = cwLogError(rc,"Socket manager create failed during eucon mgr. allocation.");
goto errLabel;
}
// create the MDNS/DNS SD UDP socket
if((rc = sock::create( p->sockMgrH, kUdpSockUserId, args.mdnsPort, udpFlags, args.sockTimeOutMs, _udpCallback, p )) != kOkRC )
{
rc = cwLogError(rc,"The Eucon controller UDP socket creation failed. ");
goto errLabel;
}
// add the mDNS socket to the multicast group
if((rc = join_multicast_group( p->sockMgrH, kUdpSockUserId, args.mdnsIP )) != kOkRC )
{
rc = cwLogError(rc,"The Eucon controller UDP socket could not be added to the multicast group. ");
goto errLabel;
}
// set the TTL for multicast
if((rc = set_multicast_time_to_live( p->sockMgrH, kUdpSockUserId, 255 )) != kOkRC )
{
rc = cwLogError(rc,"The multicast assignment to Eucon controller UDP socket failed. ");
goto errLabel;
}
p->maxFaderBankN = args.maxFaderBankN;
p->sockTimeOutMs = args.sockTimeOutMs;
p->fdrTcpPort = args.fdrTcpPort;
p->heartBeatPeriodMs = args.heartBeatPeriodMs;
hRef.set(p);
errLabel:
if( rc != kOkRC )
_destroy(p);
return rc;
}
cw::rc_t cw::eucon::destroy( handle_t& hRef )
{
rc_t rc = kOkRC;
if( !hRef.isValid() )
return rc;
eucon_t* p = _handleToPtr(hRef);
if((rc = _destroy(p)) != kOkRC )
return rc;
hRef.clear();
return rc;
}
cw::rc_t cw::eucon::exec( handle_t h, unsigned sockTimeOutMs )
{
rc_t rc = kOkRC;
eucon_t* p = _handleToPtr(h);
unsigned totalReadByteN = 0;
time::spec_t t0;
// poll sockets for incoming EuCon messages
if((rc = sock::receive_all(p->sockMgrH, sockTimeOutMs, totalReadByteN )) != kOkRC )
return rc;
switch( rc )
{
case kOkRC:
case kTimeOutRC:
rc = kOkRC;
break;
default:
rc = cwLogError(rc,"EuCon network receive failed.");
};
// get the current time
time::get(t0);
// check the health of each fader bank
for(fbank_t* fb = p->fbankL; fb!=nullptr; fb=fb->link)
if( fb->protoState != kSendHandshake_0_Id )
{
// has it been more than 'heartBeatPerioMs' millisecnods since we received a msg from this fader bank
if( time::isGTE( t0, fb->nextRecvHbTs ) )
{
cwLogInfo("Missed heart-beat disconnecting fader bank index %i.",fb->fbIndex );
_disconnect(fb);
}
// is it time to send a heart-beat to this fader bank
if( time::isGTE( t0, fb->nextSendHbTs ) )
{
_send_response( fb, HEART_BEAT, sizeof(HEART_BEAT)-1 );
time::futureMs(fb->nextSendHbTs,fb->eucon->heartBeatPeriodMs);
}
}
return rc;
}
bool cw::eucon::areMsgsWaiting( handle_t h )
{
//eucon_t* p = _handleToPtr(h);
return false;
}
cw::rc_t cw::eucon::getMsgs( handle_t h, msgCallback_t cbFunc, void* cbArg )
{
rc_t rc = kOkRC;
//eucon_t* p = _handleToPtr(h);
return rc;
}
cw::rc_t cw::eucon::sendMsg( handle_t h, unsigned fbIndex, unsigned fbChIndex, unsigned msgTypeId, unsigned value )
{
rc_t rc = kOkRC;
eucon_t* p = _handleToPtr(h);
fbank_t* fb = p->fbankL;
while( fb != nullptr )
if( fb->fbIndex == fbIndex )
{
rc = _send_app_msg(fb, fbChIndex, msgTypeId, value );
break;
}
return rc;
}
namespace cw
{
namespace eucon
{
typedef struct app_str
{
bool quitFl;
handle_t h;
thread::handle_t thH;
unsigned sockTimeOutMs;
} app_t;
bool appThreadFunc( void* arg )
{
app_t* app = static_cast<app_t*>(arg);
exec(app->h,app->sockTimeOutMs);
return true;
}
rc_t appBegin( const args_t& args, app_t& app )
{
rc_t rc = kOkRC;
// Create the EuCon controller
if((rc = create( app.h, args )) != kOkRC )
return cwLogError(rc,"Unable to create EuCon server.");
// Create the application thread
if((rc = thread::create( app.thH, appThreadFunc, &app, "eu_con" )) != kOkRC )
return cwLogError(rc,"App thread create failed.");
// Start the application thread
if((rc = thread::unpause( app.thH )) != kOkRC )
return cwLogError(rc,"App thread start failed.");
app.sockTimeOutMs = args.sockTimeOutMs;
return rc;
}
rc_t appEnd( app_t& app )
{
rc_t rc = kOkRC;
// Destroy the application thread
if((rc = thread::destroy(app.thH)) != kOkRC )
cwLogError(rc,"EuCon app thread destroy failed.");
// Destroy the EuCon controller
if((rc = destroy(app.h)) != kOkRC )
cwLogError(rc,"Eucon app object destroy failed.");
return rc;
}
}
}
cw::rc_t cw::eucon::test()
{
rc_t rc = kOkRC;
app_t app;
args_t args;
const unsigned sbufN = 31;
char sbuf[ sbufN+1 ];
memset(&args,0,sizeof(app));
args.recvBufByteN = 4096;
args.mdnsIP = "224.0.0.251";
args.mdnsPort = 5353;
args.sockTimeOutMs = 50;
args.maxFaderBankN = 8;
args.fdrTcpPort = 49168;
args.maxSockN = 50;
args.heartBeatPeriodMs = 4000;
if((rc = appBegin(args,app)) != kOkRC )
return 1;
printf("'quit' to exit\n");
// readline loop
while( true )
{
printf("? ");
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
{
printf("Sending:%s",sbuf);
if( strcmp(sbuf,"quit\n") == 0)
break;
}
}
appEnd(app);
return rc;
}