diff --git a/Makefile.am b/Makefile.am
index b39bb6e..b234f34 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,4 @@
ACLOCAL_AMFLAGS = -I m4 # use custom macro's in ./m4
-
lib_LTLIBRARIES=
bin_PROGRAMS=
include_HEADERS=
@@ -16,9 +15,6 @@ include_HEADERS=
# -Wno-multichar - turns off multi-character constant warnings from cmAudioFile.c
-WS_DIR = $(HOME)/sdk/libwebsockets/build/out
-
-
AM_CPPFLAGS = -I.. -I$(srcdir)/src/libcw
AM_CFLAGS = -Wno-multichar
AM_CXXFLAGS = -Wno-multichar
@@ -38,7 +34,7 @@ endif
if OS_LINUX
if OS_64
- AM_LDFLAGS += -L/usr/lib64
+ AM_LDFLAGS += -L/usr/lib64/atlas -L/usr/lib64
AM_CFLAGS += -m64
endif
@@ -86,8 +82,6 @@ if cwWEB
endif
if cwWEBSOCK
- # AM_CPPFLAGS += -I$(WS_DIR)/include
- # AM_LDFLAGS += -L$(WS_DIR)/lib
src_proj_proj_LDADD += -lwebsockets
endif
diff --git a/build/linux/debug/build.sh b/build/linux/debug/build.sh
index 80c1641..d63e7c9 100755
--- a/build/linux/debug/build.sh
+++ b/build/linux/debug/build.sh
@@ -16,8 +16,6 @@ cd ${curdir}
--enable-alsa \
CFLAGS="-g -Wall" \
CXXFLAGS="-g -Wall" \
-CPPFLAGS="-I${HOME}/sdk/libwebsockets/build/out/include" \
-LDFLAGS="-L${HOME}/sdk/libwebsockets/build/out/lib" \
LIBS=
diff --git a/src/proj/html/css/preset_sel.css b/src/proj/html/css/preset_sel.css
new file mode 100644
index 0000000..5ae227f
--- /dev/null
+++ b/src/proj/html/css/preset_sel.css
@@ -0,0 +1,59 @@
+
+
+.fragList {
+ border: 1px solid LightSteelBlue;
+ width: 1000px;
+ height: 450px;
+}
+
+.fragList label {
+ width: 50px;
+ background-color: LightBlue;
+}
+
+.fragList .uiNumbDisp {
+ width: 25px;
+}
+
+.fragPanel {
+ border: 1px solid LightSteelBlue;
+ padding-bottom: 5px;
+ padding-top: 5px;
+}
+
+.fragPanelRow {
+ padding-right: 15px;
+ padding-left: 15px;
+ justify-content: space-around;
+}
+
+.fragPresetCtl {
+ width: 50px;
+}
+
+.fragPresetCtl:nth-of-type(even){
+ border: 1px solid Yellow;
+}
+
+.fragPresetCtl .uiNumber {
+ border: 1px solid LightSteelBlue;
+ width: 80%;
+}
+
+.fragPresetCtl .uiString {
+ border: 1px solid LightSteelBlue;
+ width: 80%;
+}
+
+.fragNote {
+ width: 575px;
+}
+
+.uiRow {
+ padding-bottom: 5px;
+ padding-top: 5px;
+}
+
+.velTunerPanel {
+ border: 1px solid black;
+}
diff --git a/src/proj/html/css/ui.css b/src/proj/html/css/ui.css
new file mode 100644
index 0000000..7c98619
--- /dev/null
+++ b/src/proj/html/css/ui.css
@@ -0,0 +1,148 @@
+
+body {
+ background-color: LightCyan;
+}
+
+
+.title_disconnected {
+ color: red;
+}
+
+.title_connected {
+ color: green;
+}
+
+input, label, button, select {
+ font-family: sans-serif;
+ font-size: 10px;
+ height: 20px;
+}
+
+
+div {
+ /*border: 1px solid black; */
+ background-color: LightSteelBlue;
+}
+
+div p {
+ font-family: sans-serif;
+ font-size: 12px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ background-color: LightSteelBlue;
+}
+
+label {
+ /*border: 1px solid red;*/
+ width: 50px;
+ padding-left: 10px;
+ margin-top: 3px;
+}
+
+
+
+.uiCtlDiv {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ background-color: LightBlue;
+}
+
+.uiCtlDiv input {
+ background-color: PowderBlue;
+}
+
+.uiNumberDiv input {
+ width: 50px;
+}
+
+.uiPanel {
+ background-color: LightBlue;
+}
+
+.uiRow {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ background-color: LightBlue;
+}
+
+.uiCol {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ background-color: LightBlue;
+}
+
+
+/* outer log div - contains the log label and the log scroller */
+.uiLogDiv {
+ display: flex;
+ flex-direction: column;
+
+ align-items: flex-start; /* left justify */
+ align-content: flex-stretch; /* fill horizontal space */
+
+}
+
+.uiLogDiv label {
+ width: 100%;
+ background-color: LightSteelBlue;
+
+}
+
+
+/* log scroller */
+.uiLog {
+ display:flex;
+ flex-direction: column;
+
+ height: 150px;
+ overflow-x: hidden; /* 'hidden' to remove x scroll bar */
+ overflow-y: auto;
+ width: 100%;
+
+ background-color: PowderBlue;
+
+}
+
+/* The log text */
+.uiLog pre {
+}
+
+
+/* outer list div - contains the list label and the list scroller */
+.uiListDiv {
+ display: flex;
+ flex-direction: column;
+
+ align-items: flex-start; /* left justify */
+ align-content: flex-stretch; /* fill horizontal space */
+
+}
+
+.uiListDiv label {
+ width: 100%;
+ background-color: LightSteelBlue;
+
+}
+
+.uiList {
+ display:flex;
+ flex-direction: column;
+
+ height: 100px;
+ overflow-x: hidden; /* 'hidden' to remove scroll bar */
+ overflow-y: auto;
+ width: 100%;
+
+ background-color: PowderBlue;
+}
+
+.uiStringDisp {
+ width: 100%;
+}
+
+.uiSelected {
+ border: 1px solid blue;
+}
diff --git a/src/proj/html/index.html b/src/proj/html/index.html
new file mode 100644
index 0000000..a85daaa
--- /dev/null
+++ b/src/proj/html/index.html
@@ -0,0 +1,24 @@
+
+
+
+
+ Preset Selection App
+
+
+
+
+
+
+
+
+
+
+
Preset Selection:
+
Disconnected
+
+
+
+
+
diff --git a/src/proj/html/js/ui.js b/src/proj/html/js/ui.js
new file mode 100644
index 0000000..5d3031d
--- /dev/null
+++ b/src/proj/html/js/ui.js
@@ -0,0 +1,1201 @@
+var _ws = null;
+var _rootId = "0";
+var _nextEleId = 0;
+var _focusId = null;
+var _focusVal = null;
+var _rootDivEle = null;
+var _rootEle = null;
+
+function set_app_title( suffix, className )
+{
+ var ele = document.getElementById('connectTitleId');
+ if(ele != null)
+ {
+ ele.innerHTML = suffix
+ ele.className = className
+ }
+ else
+ {
+ console.log("Ele. not found. Set title failed.")
+ }
+}
+
+
+function dom_child_by_id( parentEle, child_id )
+{
+ var childrenL = parentEle.children
+ for(var i=0; i 0)
+ {
+ label_ele = dom_create_ele("label");
+
+ label_ele.innerHTML = label;
+
+ div_ele.appendChild(label_ele)
+ }
+ }
+
+ return ui_create_ele( div_ele, ele_type, d, dfltEleClassName );
+}
+
+function ui_create_div( parent_ele, d )
+{
+ var div_ele = ui_create_ele( parent_ele, "div", d, "uiDiv" );
+
+ if( div_ele != null )
+ {
+
+ if( d.title != null )
+ {
+ var title = d.title.trim()
+
+ if( title.length > 0 )
+ {
+ var p_ele = dom_create_ele("p")
+
+ p_ele.innerHTML = title
+
+ div_ele.appendChild( p_ele )
+ }
+ }
+ }
+
+ return div_ele;
+}
+
+function ui_create_panel_div( parent_ele, d )
+{
+ d.type = "div"
+
+ if( !d.hasOwnProperty('className') )
+ d.className = "uiPanel"
+
+ var div_ele = ui_create_div( parent_ele, d );
+
+
+
+ return div_ele
+}
+
+function ui_create_row_div( parent_ele, d )
+{
+ d.type = "div"
+
+ if( !d.hasOwnProperty('className') )
+ d.className = "uiRow"
+
+ var div_ele = ui_create_div( parent_ele, d );
+
+
+ return div_ele
+}
+
+function ui_create_col_div( parent_ele, d )
+{
+ d.type = "div"
+
+ if( !d.hasOwnProperty('className') )
+ d.className = "uiCol"
+
+ var div_ele = ui_create_div( parent_ele, d );
+
+
+ return div_ele
+}
+
+
+function ui_create_label( parent_ele, d )
+{
+ var ele = ui_create_ele( parent_ele, "label", d, "uiLabel" );
+
+ if( ele != null )
+ {
+ ele.innerHTML = d.title;
+ }
+
+ return ele;
+}
+
+function ui_create_button( parent_ele, d )
+{
+ var ele = ui_create_ctl( parent_ele, "button", null, d, "uiButton" );
+
+ if( ele != null )
+ {
+ ele.innerHTML = d.title;
+ ele.onclick = function() { ui_send_int_value(this,1); }
+ }
+
+ return ele;
+}
+
+function ui_create_check( parent_ele, d )
+{
+ var ele = ui_create_ctl( parent_ele, "input", d.title, d, "uiCheck" )
+
+ if( ele != null )
+ {
+ ele.type = "checkbox";
+
+ ele.onclick = function() { ui_send_bool_value(this,dom_get_checkbox(this.id)); }
+
+ if( !d.hasOwnProperty('value') )
+ {
+ ui_send_echo(ele)
+ }
+ else
+ {
+ dom_set_checkbox(ele.id, d.value );
+ ui_send_bool_value(ele,dom_get_checkbox(ele.id))
+ }
+
+ }
+ return ele;
+}
+
+//
+// Note: The value of a 'select' widget is always set by the 'appId'
+// of the selected 'option'. Likewise the 'appId' of the selected
+// option is returned as the value of the select widget.
+//
+function ui_on_select( ele )
+{
+ ui_send_int_value(ele,ele.options[ ele.selectedIndex ].appId);
+}
+
+function ui_select_set_from_option_app_id( sel_ele, option_appId )
+{
+ var i;
+ for(i=0; i= ele.minValue)
+ var max_ok_fl = (!ele.hasOwnProperty('maxValue')) || (value <= ele.maxValue)
+
+ if( min_ok_fl && max_ok_fl )
+ {
+ ele.value = value;
+ if( ele.decpl == 0 )
+ ui_send_int_value( ele, ele.value )
+ else
+ ui_send_float_value( ele, ele.value )
+ }
+ else
+ {
+ ui_error("Number value " + value + " out of range. min:" + ele.minValue + " max:" +ele.maxValue )
+ }
+
+}
+
+function ui_set_number_range( ele, d )
+{
+ _ui_set_number_range(ele,d)
+ if( d.hasOwnProperty('value') )
+ ui_set_number_value(ele,d.value)
+}
+
+function ui_create_number( parent_ele, d )
+{
+ var ele = ui_create_ctl( parent_ele, "input", d.title, d, "uiNumber" );
+
+ if( ele != null )
+ {
+ ele.addEventListener('keyup', ui_number_keyup );
+ ele.addEventListener('focus', function(e) { _ui_on_focus(this); } );
+ ele.addEventListener('blur', function(e) { _ui_on_number_blur(this); } );
+ _ui_set_number_range(ele,d)
+
+
+ if( d.hasOwnProperty('value') )
+ {
+ ui_set_number_value(ele,d.value)
+ }
+ else
+ {
+ ui_send_echo(ele);
+ }
+ }
+ return ele;
+}
+
+function ui_set_number_display( ele_id, value )
+{
+ //console.log("Numb disp: " + ele_id + " " + value)
+
+ var ele = dom_id_to_ele(ele_id);
+
+ if( typeof(value)=="number")
+ {
+ var val = value.toString();
+
+ if( ele.decpl == 0 )
+ ele.innerHTML = parseInt(val,10);
+ else
+ ele.innerHTML = parseFloat(val);
+ }
+}
+
+function ui_create_number_display( parent_ele, d )
+{
+ var ele = ui_create_ctl( parent_ele, "label", d.title, d, "uiNumbDisp" );
+
+ if( ele != null )
+ {
+ ele.decpl = d.decpl;
+
+ if( d.hasOwnProperty('value') )
+ {
+ ui_set_number_display(ele.id, d.value);
+ }
+ else
+ {
+ ui_send_echo(ele);
+ }
+ }
+
+ return ele;
+
+}
+
+function ui_create_text_display( parent_ele, d )
+{
+ return ui_create_ctl( parent_ele, "label", d.title, d, "uiTextDisp" );
+}
+
+
+function ui_set_progress( ele, value )
+{
+ ele.value = Math.round( ele.max * (value - ele.minValue) / (ele.maxValue - ele.minValue));
+}
+
+function _ui_set_prog_range( ele, d )
+{
+ ele.maxValue = d.max;
+ ele.minValue = d.min;
+}
+
+function ui_create_progress( parent_ele, d )
+{
+ var ele = ui_create_ctl( parent_ele, "progress", d.title, d, "uiProgress" );
+
+ if( ele != null )
+ {
+ ele.max = 100;
+ _ui_set_prog_range(ele,d)
+
+ if( !d.hasOwnProperty('value') )
+ ui_send_echo(ele);
+ else
+ {
+ ui_set_progress( ele, d.value );
+ ui_send_int_value( ele, ele.value );
+ }
+
+ }
+ return ele
+}
+
+function ui_set_prog_range( ele, d )
+{
+ _ui_set_prog_range(ele,d)
+ if( d.hasOwnProperty('value'))
+ ui_set_progress(ele,d.value)
+}
+
+function _on_log_click( evt )
+{
+ var pre_ele = dom_id_to_ele(evt.target.id)
+
+ pre_ele.auto_scroll_flag = !pre_ele.auto_scroll_flag;
+}
+
+function ui_set_log_text( ele, value )
+{
+ var child_id = ele.id + "_pre"
+
+ for(var i=0; i to the containing div
+ var ele = dom_create_ele("pre")
+
+ ele.id = log_ele.id + "_pre"
+ ele.onclick = _on_log_click;
+ ele.auto_scroll_flag = true;
+
+ log_ele.appendChild(ele)
+
+ return log_ele
+}
+
+function ui_create_list( parent_ele, d )
+{
+ //console.log(d)
+ var list_ele = ui_create_ctl( parent_ele, "div", d.title, d, "uiList" )
+
+ return list_ele
+}
+
+function ui_set_value( d )
+{
+ var eleId = d.uuId.toString()
+ var ele = dom_id_to_ele(eleId)
+
+ if( ele == null )
+ console.log("ele '"+eleId+"' not found");
+ else
+ {
+ if( !ele.hasOwnProperty("uiEleType") )
+ {
+ console.log("No type");
+ }
+ }
+
+ if( ele != null && ele.hasOwnProperty("uiEleType"))
+ {
+ //console.log("found: "+ele.uiEleType)
+
+ switch( ele.uiEleType )
+ {
+ case "div":
+ break;
+
+ case "label":
+ ele.innerHTML = d.value
+ break;
+
+ case "button":
+ break;
+
+ case "check":
+ dom_set_checkbox(ele.id,d.value)
+ break;
+
+ case "select":
+ ui_select_set_from_option_app_id(ele,d.value)
+ break;
+
+ case "option":
+ break;
+
+ case "str_disp":
+ ui_set_str_display(ele.id,d.value);
+ break
+
+ case "string":
+ ele.value = d.value
+ break;
+
+ case "number":
+ ele.value = d.value
+ break;
+
+ case "numb_disp":
+ ui_set_number_display(ele.id,d.value);
+ break;
+
+ case "progress":
+ ui_set_progress( ele, d.value )
+ //ele.value = d.value
+ break;
+
+ case "log":
+ ui_set_log_text( ele, d.value )
+ break
+
+ default:
+ ui_error("Unknown UI element type on set value: " + d.type )
+ }
+ }
+}
+
+function _ui_modify_class( ele, classLabelArg, enableFl )
+{
+ let classLabel = " " + classLabelArg; // prefix the class label with a space
+
+ //console.log(ele.id + " " + classLabelArg + " " + enableFl )
+
+ let isEnabledFl = false;
+
+ if( ele.hasOwnProperty("className") )
+ isEnabledFl = ele.className.includes(classLabel)
+ else
+ ele.className = ""
+
+ // if the class is not already enabled/disabled
+ if( enableFl != isEnabledFl )
+ {
+ if( enableFl )
+ ele.className += classLabel;
+ else
+ ele.className = ele.className.replace(classLabel, "");
+ }
+
+ //console.log(ele.id + " " + ele.className + " " + enableFl )
+}
+
+function ui_set_select( ele, enableFl )
+{
+ _ui_modify_class(ele,"uiSelected",enableFl)
+ ui_send_select( ele, enableFl )
+}
+
+
+function ui_set_clickable( ele, enableFl )
+{
+ ele.clickableFl = enableFl
+
+ if(enableFl)
+ ele.onclick = function( evt ){ ui_on_click( this, evt ); }
+ else
+ ele.onclick = null
+}
+
+function ui_set_visible( ele, enableFl )
+{
+ if(enableFl)
+ {
+ if(ele.hasOwnProperty("style_display") )
+ {
+ ele.style.display = ele.style_display;
+ }
+ else
+ {
+ ele.style.display = "block";
+ }
+ }
+ else
+ {
+ ele.style_display = ele.style.display;
+ ele.style.display = "none";
+ }
+}
+
+function ui_set_enable( ele, enableFl )
+{
+ ele.disabled = !enableFl
+}
+
+function ui_set_order_key(ele, orderKey)
+{
+ let parent = ele.parentElement // get the parent of the element to reorder
+ ele = parent.removeChild( ele ) // remove the element to reorder from the parent list
+
+ ele.order = orderKey
+
+ let i = 0;
+ for(i=0; i= orderKey)
+ {
+ parent.insertBefore( ele, parent.children[i] )
+ break
+ }
+ }
+
+ // no element was found greater than this element ....
+ if( i == parent.children.length )
+ parent.appendChild(ele) // ... insert the element at the end of the child lsit
+
+}
+
+function ui_set( d )
+{
+ //console.log(d)
+ var ele = dom_id_to_ele(d.uuId.toString())
+
+ if( ele == null )
+ console.log("ele not found");
+
+ if( ele != null)
+ {
+ switch( d.type )
+ {
+ case "number_range":
+ ui_set_number_range(ele, d)
+ break;
+
+ case "progress_range":
+ ui_set_prog_range(ele, d)
+ break;
+
+ case "select":
+ ui_set_select(ele,d.value)
+ break
+
+ case "clickable":
+ ui_set_clickable(ele,d.value)
+ break
+
+ case "visible":
+ ui_set_visible(ele,d.value)
+ break
+
+ case "enable":
+ ui_set_enable(ele,d.value)
+ break
+
+ case "order":
+ ui_set_order_key(ele,d.value)
+ break
+
+ }
+ }
+}
+
+function ui_cache( d )
+{
+ for(i=0; iioH );
+ break;
+
+ case kIoReportBtnId:
+ io::report(app->ioH);
+ break;
+
+ case kNetPrintBtnId:
+ break;
+
+ case kReportBtnId:
+ break;
+
+ case kLatencyBtnId:
+ latency_measure_report(app->ioH);
+ latency_measure_setup(app->ioH);
+ break;
+
+ case kValueNumbId:
+ app->value = m.value->u.u;
+ cwLogInfo("Setting value:%i",app->value);
+ break;
+
+ }
+ return kOkRC;
+}
+
+rc_t _ui_echo_callback(app_t* app, const io::ui_msg_t& m )
+{
+ switch( m.appId )
+ {
+ case kValueNumbId:
+ {
+ uiSendValue( app->ioH, io::uiFindElementUuId( app->ioH, kValueNumbId ), app->value );
+ }
+ break;
+
+ }
+ return kOkRC;
+}
+
+rc_t _ui_callback( app_t* app, const io::ui_msg_t& m )
{
rc_t rc = kOkRC;
- object_t* cfg = nullptr;
- cw::log::createGlobal();
-
- cwLogInfo("Project template: args:%i", argc);
+
+ switch( m.opId )
+ {
+ case ui::kConnectOpId:
+ cwLogInfo("UI Connected: wsSessId:%i.",m.wsSessId);
+ break;
+
+ case ui::kDisconnectOpId:
+ cwLogInfo("UI Disconnected: wsSessId:%i.",m.wsSessId);
+ break;
+
+ case ui::kInitOpId:
+ cwLogInfo("UI Init.");
+ break;
+ case ui::kValueOpId:
+ _ui_value_callback( app, m );
+ break;
+
+ case ui::kCorruptOpId:
+ cwLogInfo("UI Corrupt.");
+ break;
+
+ case ui::kClickOpId:
+ cwLogInfo("UI Click.");
+ break;
+
+ case ui::kSelectOpId:
+ cwLogInfo("UI Select.");
+ break;
+
+ case ui::kEchoOpId:
+ _ui_echo_callback( app, m );
+ break;
+
+ case ui::kIdleOpId:
+ break;
+
+ case ui::kInvalidOpId:
+ // fall through
+ default:
+ assert(0);
+ break;
+
+ }
+
+ return rc;
+}
+
+
+rc_t _io_callback( void* arg, const io::msg_t* m )
+{
+ app_t* app = (app_t*)arg;
+
+ switch( m->tid )
+ {
+ case io::kThreadTId:
+ break;
+
+ case io::kTimerTId:
+ break;
+
+ case io::kSerialTId:
+ break;
+
+ case io::kMidiTId:
+ break;
+
+ case io::kAudioTId:
+ break;
+
+ case io::kAudioMeterTId:
+ break;
+
+ case io::kSockTId:
+ break;
+
+ case io::kWebSockTId:
+ break;
+
+ case io::kUiTId:
+ _ui_callback(app,m->u.ui);
+ break;
+
+ case io::kExecTId:
+ break;
+
+ default:
+ assert(0);
+ }
+
+ return kOkRC;
+}
+
+rc_t _parse_cfg( app_t& app, int argc, char* argv[] )
+{
+ rc_t rc = kOkRC;
+
if( argc < 2 || textLength(argv[1])==0 )
{
- cwLogError(kInvalidArgRC,"No cfg. file was given.");
+ rc = cwLogError(kInvalidArgRC,"No cfg. file was given.");
goto errLabel;
}
else
{
- const char* val = nullptr;
-
- if((rc = objectFromFile(argv[1],cfg)) != kOkRC )
+ if((rc = objectFromFile(argv[1],app.cfg)) != kOkRC )
{
- cwLogError(rc,"The file '%s'.",argv[1]);
+ rc = cwLogError(rc,"The file '%s'.",argv[1]);
goto errLabel;
}
- if((rc = cfg->getv("param",val)) != kOkRC )
+ if((rc = app.cfg->getv("param", app.value,
+ "libcw", app.io_cfg)) != kOkRC )
{
- cwLogError(kSyntaxErrorRC,"The 'param' cfg. field was not found.");
+ rc = cwLogError(kSyntaxErrorRC,"The 'param' cfg. field was not found.");
goto errLabel;
}
- cwLogInfo("param=%s",cwStringNullGuard(val));
+ }
+errLabel:
+ if( rc != kOkRC )
+ rc = cwLogError(rc,"App. cfg. parse failed.");
+ return rc;
+}
+
+int main( int argc, char* argv[] )
+{
+ rc_t rc = kOkRC;
+ app_t app = {};
+ cw::log::createGlobal();
+
+ cwLogInfo("Project template: args:%i", argc);
+
+ if((rc = _parse_cfg(app,argc,argv)) != kOkRC )
+ goto errLabel;
+
+ if((rc = create( app.ioH, app.io_cfg, _io_callback, &app, appIdMapA, appIdMapN ) ) != kOkRC )
+ {
+ rc = cwLogError(rc,"IO create failed.");
+ goto errLabel;
}
+
+ // start the IO framework instance
+ if((rc = io::start(app.ioH)) != kOkRC )
+ {
+ rc = cwLogError(rc,"Preset-select app start failed.");
+ goto errLabel;
+ }
+
+ //io::uiReport(app.ioH);
+
+
+ // execute the io framework
+ while( !io::isShuttingDown(app.ioH))
+ {
+ // This call will block on the websocket handle
+ // for up to io_cfg->ui.websockTimeOutMs milliseconds
+ io::exec(app.ioH);
+
+
+ }
+
+ // stop the io framework
+ if((rc = io::stop(app.ioH)) != kOkRC )
+ {
+ rc = cwLogError(rc,"IO API stop failed.");
+ goto errLabel;
+ }
+
+
errLabel:
+ destroy(app.ioH);
+ if( app.cfg != nullptr )
+ app.cfg->free();
cw::log::destroyGlobal();
return 0;