diff --git a/src/vscp/common/register.cpp b/src/vscp/common/register.cpp index f9c1fcb18..e4f527cfd 100644 --- a/src/vscp/common/register.cpp +++ b/src/vscp/common/register.cpp @@ -31,31 +31,31 @@ #include #endif +#include #include #include -#include -#include #include +#include #include +#include #include #include -#include #include #ifdef WIN32 -static void -win_usleep(__int64 usec) -{ - HANDLE timer; - LARGE_INTEGER ft; - - ft.QuadPart = -(10*usec); // Convert to 100 nanosecond interval, negative value indicates relative time - - timer = CreateWaitableTimer(NULL, TRUE, NULL); - SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); - WaitForSingleObject(timer, INFINITE); - CloseHandle(timer); +static void +win_usleep(__int64 usec) +{ + HANDLE timer; + LARGE_INTEGER ft; + + ft.QuadPart = -(10 * usec); // Convert to 100 nanosecond interval, negative value indicates relative time + + timer = CreateWaitableTimer(NULL, TRUE, NULL); + SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); + WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); } #endif @@ -68,13 +68,13 @@ win_usleep(__int64 usec) */ int -vscp_readLevel1Register(CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint16_t page, - uint8_t offset, - uint8_t& value, - uint32_t timeout) +vscp_readLevel1Register(CVscpClient &client, + cguid &guidNode, + cguid &guidInterface, + uint16_t page, + uint8_t offset, + uint8_t &value, + uint32_t timeout) { int rv = VSCP_ERROR_ERROR; vscpEventEx ex; @@ -83,16 +83,17 @@ vscp_readLevel1Register(CVscpClient& client, uint8_t nickname = guidNode.getNickname(); uint8_t ifoffset = guidInterface.isNULL() ? 0 : 16; - ex.head = VSCP_PRIORITY_NORMAL; + ex.head = VSCP_PRIORITY_NORMAL; ex.vscp_class = VSCP_CLASS1_PROTOCOL + (guidInterface.isNULL() ? 0 : 512); ex.vscp_type = VSCP_TYPE_PROTOCOL_EXTENDED_PAGE_READ; ex.sizeData = ifoffset + 5; - if (ifoffset) memcpy(ex.data, guidInterface.getGUID(), 16); - ex.data[0 + ifoffset] = nickname; - ex.data[1 + ifoffset] = (page >> 8) & 0x0ff; - ex.data[2 + ifoffset] = page & 0x0ff; - ex.data[3 + ifoffset] = offset; - ex.data[4 + ifoffset] = 1; + if (ifoffset) + memcpy(ex.data, guidInterface.getGUID(), 16); + ex.data[0 + ifoffset] = nickname; + ex.data[1 + ifoffset] = (page >> 8) & 0x0ff; + ex.data[2 + ifoffset] = page & 0x0ff; + ex.data[3 + ifoffset] = offset; + ex.data[4 + ifoffset] = 1; // Clear input queue if (VSCP_ERROR_SUCCESS != (rv = client.clear())) { @@ -113,21 +114,15 @@ vscp_readLevel1Register(CVscpClient& client, // Get response uint16_t count; rv = client.getcount(&count); - if (count && - VSCP_ERROR_SUCCESS == rv) { + if (count && VSCP_ERROR_SUCCESS == rv) { if (VSCP_ERROR_SUCCESS != (rv = client.receive(ex))) { return rv; } - if (VSCP_CLASS1_PROTOCOL == ex.vscp_class && - VSCP_TYPE_PROTOCOL_EXTENDED_PAGE_RESPONSE == ex.vscp_type) { - if ((ex.GUID[15] = nickname) && - (ex.sizeData >= 5) && - (ex.data[0] == 0) && - (ex.data[1] == ((page >> 8) & 0xff)) && - (ex.data[2] == (page & 0x0ff)) && - (ex.data[3] == offset)) { + if (VSCP_CLASS1_PROTOCOL == ex.vscp_class && VSCP_TYPE_PROTOCOL_EXTENDED_PAGE_RESPONSE == ex.vscp_type) { + if ((ex.GUID[15] = nickname) && (ex.sizeData >= 5) && (ex.data[0] == 0) && + (ex.data[1] == ((page >> 8) & 0xff)) && (ex.data[2] == (page & 0x0ff)) && (ex.data[3] == offset)) { value = ex.data[4]; return VSCP_ERROR_SUCCESS; } @@ -138,10 +133,9 @@ vscp_readLevel1Register(CVscpClient& client, rv = VSCP_ERROR_TIMEOUT; break; } - #ifdef WIN32 - win_usleep(2000); + win_usleep(2000); #else usleep(2000); #endif @@ -156,13 +150,13 @@ vscp_readLevel1Register(CVscpClient& client, // int -vscp_writeLevel1Register(CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint16_t page, - uint8_t offset, - uint8_t value, - uint32_t timeout) +vscp_writeLevel1Register(CVscpClient &client, + cguid &guidNode, + cguid &guidInterface, + uint16_t page, + uint8_t offset, + uint8_t value, + uint32_t timeout) { int rv = VSCP_ERROR_ERROR; vscpEventEx ex; @@ -170,18 +164,19 @@ vscp_writeLevel1Register(CVscpClient& client, uint8_t nickname = guidNode.getNickname(); uint8_t ifoffset = guidInterface.isNULL() ? 0 : 16; - ex.head = VSCP_PRIORITY_NORMAL; - ex.vscp_class = VSCP_CLASS1_PROTOCOL+ (guidInterface.isNULL() ? 0 : 512);; - ex.vscp_type = VSCP_TYPE_PROTOCOL_EXTENDED_PAGE_WRITE; - ex.sizeData = ifoffset + 5; - if (ifoffset) memcpy(ex.data, guidInterface.getGUID(), 16); - ex.data[0 + ifoffset] = nickname; - ex.data[1 + ifoffset] = (page >> 8) & 0x0ff; - ex.data[2 + ifoffset] = page & 0x0ff; - ex.data[3 + ifoffset] = offset; - ex.data[4 + ifoffset] = value; - - + ex.head = VSCP_PRIORITY_NORMAL; + ex.vscp_class = VSCP_CLASS1_PROTOCOL + (guidInterface.isNULL() ? 0 : 512); + ; + ex.vscp_type = VSCP_TYPE_PROTOCOL_EXTENDED_PAGE_WRITE; + ex.sizeData = ifoffset + 5; + if (ifoffset) + memcpy(ex.data, guidInterface.getGUID(), 16); + ex.data[0 + ifoffset] = nickname; + ex.data[1 + ifoffset] = (page >> 8) & 0x0ff; + ex.data[2 + ifoffset] = page & 0x0ff; + ex.data[3 + ifoffset] = offset; + ex.data[4 + ifoffset] = value; + // Clear the input queue if (VSCP_ERROR_SUCCESS != (rv = client.clear())) { return rv; @@ -195,13 +190,12 @@ vscp_writeLevel1Register(CVscpClient& client, uint32_t startTime = vscp_getMsTimeStamp(); // Wait for reponse - + do { // Get response uint16_t count; rv = client.getcount(&count); - if (count && - VSCP_ERROR_SUCCESS == rv) { + if (count && VSCP_ERROR_SUCCESS == rv) { if (VSCP_ERROR_SUCCESS != (rv = client.receive(ex))) { return rv; @@ -209,12 +203,8 @@ vscp_writeLevel1Register(CVscpClient& client, if (VSCP_CLASS1_PROTOCOL == ex.vscp_class) { if (VSCP_TYPE_PROTOCOL_EXTENDED_PAGE_RESPONSE == ex.vscp_type) { - if ((ex.GUID[15] = nickname) && - (ex.sizeData >= 5) && - (ex.data[0] == 0) && - (ex.data[1] == ((page >> 8) & 0x0ff)) && - (ex.data[2] == (page & 0x0ff)) && - (ex.data[3] == offset) && + if ((ex.GUID[15] = nickname) && (ex.sizeData >= 5) && (ex.data[0] == 0) && + (ex.data[1] == ((page >> 8) & 0x0ff)) && (ex.data[2] == (page & 0x0ff)) && (ex.data[3] == offset) && (ex.data[4] == value)) { return VSCP_ERROR_SUCCESS; } @@ -222,14 +212,14 @@ vscp_writeLevel1Register(CVscpClient& client, } } - //std::cout << "." << std::flush; + // std::cout << "." << std::flush; if (timeout && ((vscp_getMsTimeStamp() - startTime) > timeout)) { rv = VSCP_ERROR_TIMEOUT; break; } #ifdef WIN32 - win_usleep(2000); + win_usleep(2000); #else usleep(2000); #endif @@ -243,43 +233,45 @@ vscp_writeLevel1Register(CVscpClient& client, // vscp_readLevel1RegisterBlock // -int vscp_readLevel1RegisterBlock( CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint16_t page, - uint8_t offset, - uint8_t count, - std::map& values, - uint32_t timeout) +int +vscp_readLevel1RegisterBlock(CVscpClient &client, + cguid &guidNode, + cguid &guidInterface, + uint16_t page, + uint8_t offset, + uint8_t count, + std::map &values, + uint32_t timeout) { - int rv = VSCP_ERROR_ERROR; - uint8_t rcvcnt = 0; // Number of registers read + int rv = VSCP_ERROR_ERROR; + uint8_t rcvcnt = 0; // Number of registers read vscpEventEx ex; CVscpClient::connType conntype = client.getType(); uint8_t nickname = guidNode.getNickname(); uint8_t ifoffset = guidInterface.isNULL() ? 0 : 16; - + /* Frames may not come in order on all interfaces */ std::set frameset; - for (int i=0; i> 8) & 0x0ff; - ex.data[2 + ifoffset] = page & 0x0ff; - ex.data[3 + ifoffset] = offset; - ex.data[4 + ifoffset] = count; + if (ifoffset) + memcpy(ex.data, guidInterface.getGUID(), 16); + ex.data[0 + ifoffset] = nickname; + ex.data[1 + ifoffset] = (page >> 8) & 0x0ff; + ex.data[2 + ifoffset] = page & 0x0ff; + ex.data[3 + ifoffset] = offset; + ex.data[4 + ifoffset] = count; // Clear input queue if (VSCP_ERROR_SUCCESS != (rv = client.clear())) { @@ -294,7 +286,7 @@ int vscp_readLevel1RegisterBlock( CVscpClient& client, uint32_t startTime = vscp_getMsTimeStamp(); // Wait for reponse - + do { // Get response uint16_t cntRead; @@ -305,25 +297,23 @@ int vscp_readLevel1RegisterBlock( CVscpClient& client, return rv; } - //std::cout << "class=" << (int)ex.vscp_class << " type = " << (int)ex.vscp_type << std::endl << std::flush; + // std::cout << "class=" << (int)ex.vscp_class << " type = " << (int)ex.vscp_type << std::endl << std::flush; if (VSCP_CLASS1_PROTOCOL == ex.vscp_class) { if (VSCP_TYPE_PROTOCOL_EXTENDED_PAGE_RESPONSE == ex.vscp_type) { - if ((ex.GUID[15] = nickname) && - (ex.sizeData >= 5) && + if ((ex.GUID[15] = nickname) && (ex.sizeData >= 5) && /* ex.data[0] is frame index */ - (ex.data[1] == ((page >> 8) & 0x0ff)) && - (ex.data[2] == (page & 0x0ff)) - /*(ex.data[3] == offset + rcvcnt)*/ ) { - - // Another frame received - frameset.erase(ex.data[0]); - //std::cout << "idx=" << (int)ex.data[0] << " left = " << (int)frameset.size() << std::endl << std::flush; - - // Get read data - for (int i = 0; i < ex.sizeData-4; i++) { - //values[offset + rcvcnt] = ex.data[4 + i]; - values[ex.data[3]+i] = ex.data[4 + i]; + (ex.data[1] == ((page >> 8) & 0x0ff)) && (ex.data[2] == (page & 0x0ff)) + /*(ex.data[3] == offset + rcvcnt)*/) { + + // Another frame received + frameset.erase(ex.data[0]); + // std::cout << "idx=" << (int)ex.data[0] << " left = " << (int)frameset.size() << std::endl << std::flush; + + // Get read data + for (int i = 0; i < ex.sizeData - 4; i++) { + // values[offset + rcvcnt] = ex.data[4 + i]; + values[ex.data[3] + i] = ex.data[4 + i]; rcvcnt++; } @@ -342,7 +332,7 @@ int vscp_readLevel1RegisterBlock( CVscpClient& client, } #ifdef WIN32 - win_usleep(2000); + win_usleep(2000); #else usleep(2000); #endif @@ -356,27 +346,28 @@ int vscp_readLevel1RegisterBlock( CVscpClient& client, // vscp_writeLevel1RegisterBlock // -int vscp_writeLevel1RegisterBlock( CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint16_t page, - std::map& regvalues, - uint32_t timeout) +int +vscp_writeLevel1RegisterBlock(CVscpClient &client, + cguid &guidNode, + cguid &guidInterface, + uint16_t page, + std::map ®values, + uint32_t timeout) { - int rv = VSCP_ERROR_SUCCESS; + int rv = VSCP_ERROR_SUCCESS; CVscpClient::connType conntype = client.getType(); uint8_t nickname = guidNode.getNickname(); uint8_t ifoffset = guidInterface.isNULL() ? 0 : 16; - int reg = -99; - int count = 0; + int reg = -99; + int count = 0; vscpEventEx ex; uint8_t offset_data = 0; - std::map startmap; - + std::map startmap; + // The startregs map contains reg, count for each sequence start - for (auto const& item : regvalues) { + for (auto const &item : regvalues) { if (item.first != (reg + count)) { - reg = item.first; + reg = item.first; startmap[item.first] = count = 1; } else { @@ -386,32 +377,36 @@ int vscp_writeLevel1RegisterBlock( CVscpClient& client, } // Write out - for (auto const& start : startmap) { + for (auto const &start : startmap) { + + // std::cout << "Writing reg: " << (int)start.first << " count: " << (int)start.second << std::endl; - //std::cout << "Writing reg: " << (int)start.first << " count: " << (int)start.second << std::endl; - // Find out how many frames to send - uint8_t nwrites = start.second/4; - if (start.second%4) nwrites++; - - for (int i=0; i 4) bytes2write = 4; - - ex.head = VSCP_PRIORITY_NORMAL; - ex.vscp_class = VSCP_CLASS1_PROTOCOL+ (guidInterface.isNULL() ? 0 : 512);; - ex.vscp_type = VSCP_TYPE_PROTOCOL_EXTENDED_PAGE_WRITE; - ex.sizeData = ifoffset + 4 + bytes2write; - if (ifoffset) memcpy(ex.data, guidInterface.getGUID(), 16); - ex.data[0 + ifoffset] = nickname; - ex.data[1 + ifoffset] = (page >> 8) & 0x0ff; - ex.data[2 + ifoffset] = page & 0x0ff; - ex.data[3 + ifoffset] = start.first + i*4; - - // Fill data - for (int j=0; j 4) + bytes2write = 4; + + ex.head = VSCP_PRIORITY_NORMAL; + ex.vscp_class = VSCP_CLASS1_PROTOCOL + (guidInterface.isNULL() ? 0 : 512); + ; + ex.vscp_type = VSCP_TYPE_PROTOCOL_EXTENDED_PAGE_WRITE; + ex.sizeData = ifoffset + 4 + bytes2write; + if (ifoffset) + memcpy(ex.data, guidInterface.getGUID(), 16); + ex.data[0 + ifoffset] = nickname; + ex.data[1 + ifoffset] = (page >> 8) & 0x0ff; + ex.data[2 + ifoffset] = page & 0x0ff; + ex.data[3 + ifoffset] = start.first + i * 4; + + // Fill data + for (int j = 0; j < bytes2write; j++) { + ex.data[4 + ifoffset + j] = regvalues[start.first + i * 4 + j]; } // Clear input queue @@ -427,7 +422,7 @@ int vscp_writeLevel1RegisterBlock( CVscpClient& client, uint32_t startTime = vscp_getMsTimeStamp(); // Wait for reponse - + do { // Get response uint16_t count; @@ -440,19 +435,16 @@ int vscp_writeLevel1RegisterBlock( CVscpClient& client, if (VSCP_CLASS1_PROTOCOL == ex.vscp_class) { if (VSCP_TYPE_PROTOCOL_EXTENDED_PAGE_RESPONSE == ex.vscp_type) { - if ((ex.GUID[15] = nickname) && - (ex.sizeData >= 5) && - (ex.data[0] == 0) && - (ex.data[1] == ((page >> 8) & 0x0ff)) && - (ex.data[2] == (page & 0x0ff))) { - - for (int k=4; k= 5) && (ex.data[0] == 0) && + (ex.data[1] == ((page >> 8) & 0x0ff)) && (ex.data[2] == (page & 0x0ff))) { + + for (int k = 4; k < ex.sizeData; k++) { + if (ex.data[k] == regvalues[ex.data[3] + k - 4]) { + regvalues.erase(ex.data[3] + k - 4); } - //std::cout << " Erased reg: " << (int)ex.data[3]+k-4 << std::endl; + // std::cout << " Erased reg: " << (int)ex.data[3]+k-4 << std::endl; } - + if (regvalues.empty()) { return VSCP_ERROR_SUCCESS; } @@ -468,11 +460,11 @@ int vscp_writeLevel1RegisterBlock( CVscpClient& client, break; } - #ifdef WIN32 - win_usleep(2000); - #else +#ifdef WIN32 + win_usleep(2000); +#else usleep(2000); - #endif +#endif } while (timeout); @@ -483,17 +475,14 @@ int vscp_writeLevel1RegisterBlock( CVscpClient& client, return rv; } - /////////////////////////////////////////////////////////////////////////////// // vscp_scanForDevices // -int vscp_scanForDevices(CVscpClient& client, - cguid& guid, - std::set &found, - uint32_t timeout) +int +vscp_scanForDevices(CVscpClient &client, cguid &guid, std::set &found, uint32_t timeout) { - int rv = VSCP_ERROR_SUCCESS; + int rv = VSCP_ERROR_SUCCESS; uint8_t offset = guid.isNULL() ? 0 : 16; vscpEventEx ex; @@ -501,9 +490,9 @@ int vscp_scanForDevices(CVscpClient& client, ex.vscp_class = VSCP_CLASS1_PROTOCOL + (guid.isNULL() ? 0 : 512); ex.vscp_type = VSCP_TYPE_PROTOCOL_WHO_IS_THERE; memcpy(ex.data + offset, guid.getGUID(), 16); // Use GUID of interface - memset(ex.GUID, 0, 16); // Use GUID of interface - ex.sizeData = 17; - ex.data[16] = 0xff; // all devices + memset(ex.GUID, 0, 16); // Use GUID of interface + ex.sizeData = 17; + ex.data[16] = 0xff; // all devices // Clear input queue if (VSCP_ERROR_SUCCESS != (rv = client.clear())) { @@ -523,8 +512,7 @@ int vscp_scanForDevices(CVscpClient& client, rv = client.receive(ex); } if (VSCP_ERROR_SUCCESS == rv) { - if ( ex.vscp_class == VSCP_CLASS1_PROTOCOL && - ex.vscp_type == VSCP_TYPE_PROTOCOL_WHO_IS_THERE_RESPONSE ) { + if (ex.vscp_class == VSCP_CLASS1_PROTOCOL && ex.vscp_type == VSCP_TYPE_PROTOCOL_WHO_IS_THERE_RESPONSE) { found.insert(ex.GUID[15] + (ex.GUID[14] << 8)); } } @@ -542,34 +530,42 @@ int vscp_scanForDevices(CVscpClient& client, // vscp_scanSlowForDevices // -int vscp_scanSlowForDevices(CVscpClient& client, - cguid& guid, - std::set &search_nodes, - std::set &found_nodes, - uint32_t delay, - uint32_t timeout) +int +vscp_scanSlowForDevices(CVscpClient &client, + cguid &guid, + std::set &search_nodes, + std::set &found_nodes, + uint32_t delay, + uint32_t timeout) { - int rv = VSCP_ERROR_SUCCESS; + uint16_t offset = 0; + int rv = VSCP_ERROR_SUCCESS; vscpEventEx ex; CVscpClient::connType conntype = client.getType(); - + + if (guid.isNULL()) { + offset = 16; + } + memset(&ex, 0, sizeof(vscpEventEx)); - ex.vscp_class = VSCP_CLASS1_PROTOCOL + 512; + ex.vscp_class = VSCP_CLASS1_PROTOCOL + offset; ex.vscp_type = VSCP_TYPE_PROTOCOL_READ_REGISTER; - memcpy(ex.data, guid.getGUID(), 16); + if (!guid.isNULL()) { + memcpy(ex.data, guid.getGUID(), 16); + } memset(ex.GUID, 0, 16); // Use GUID of interface - ex.sizeData = 18; + ex.sizeData = 2 + offset; // Clear input queue if (VSCP_ERROR_SUCCESS != (rv = client.clear())) { return rv; } - for ( auto const& idx : search_nodes ) { - - ex.data[15] = idx << 8; // nodeid MSB - ex.data[16] = idx & 0xff; // nodeid LSB - ex.data[17] = 0xd0; // register: First byte of GUID + // Send reads (First byte of GUID) + for (auto const &idx : search_nodes) { + + ex.data[0 + offset] = idx; // nodeid + ex.data[1 + offset] = 0xd0; // register: First byte of GUID rv = client.send(ex); if (VSCP_ERROR_SUCCESS != rv) { @@ -580,8 +576,9 @@ int vscp_scanSlowForDevices(CVscpClient& client, win_usleep(delay); #else usleep(delay); -#endif - } +#endif + + } uint32_t startTime = vscp_getMsTimeStamp(); @@ -589,24 +586,23 @@ int vscp_scanSlowForDevices(CVscpClient& client, uint16_t cnt; rv = client.getcount(&cnt); - if (cnt) { - - rv = client.receive(ex); - if (VSCP_ERROR_SUCCESS != rv) { - return rv; - } + if (VSCP_ERROR_SUCCESS != rv) { + return rv; + } - //std::cout << "Class: " << ex.vscp_class << " Type: " << ex.vscp_type << std::endl; + if (cnt) { + printf("cnt %d\n", (int)cnt); + rv = client.receive(ex); + if (VSCP_ERROR_SUCCESS == rv) { + std::cout << "Class: " << ex.vscp_class << " Type: " << ex.vscp_type << std::endl; - if ((ex.vscp_class == VSCP_CLASS1_PROTOCOL) && - (ex.vscp_type == VSCP_TYPE_PROTOCOL_RW_RESPONSE)) { - found_nodes.insert(ex.GUID[15] + (ex.GUID[14] << 8)); - } - else if ((ex.vscp_class == VSCP_CLASS2_LEVEL1_PROTOCOL) && - (ex.vscp_type == VSCP_TYPE_PROTOCOL_RW_RESPONSE)) { - found_nodes.insert(ex.GUID[15] + (ex.GUID[14] << 8)); + if ((ex.vscp_class == VSCP_CLASS1_PROTOCOL) && (ex.vscp_type == VSCP_TYPE_PROTOCOL_RW_RESPONSE)) { + found_nodes.insert(ex.GUID[15] + (ex.GUID[14] << 8)); + } + else if ((ex.vscp_class == VSCP_CLASS2_LEVEL1_PROTOCOL) && (ex.vscp_type == VSCP_TYPE_PROTOCOL_RW_RESPONSE)) { + found_nodes.insert(ex.GUID[15] + (ex.GUID[14] << 8)); + } } - } // If all nodes found we are done @@ -627,38 +623,32 @@ int vscp_scanSlowForDevices(CVscpClient& client, // vscp_scanSlowForDevices // -int vscp_scanSlowForDevices(CVscpClient& client, - cguid& guid, - uint8_t start_node, - uint8_t end_node, - std::set &found_nodes, - uint32_t delay, - uint32_t timeout) +int +vscp_scanSlowForDevices(CVscpClient &client, + cguid &guid, + uint8_t start_node, + uint8_t end_node, + std::set &found_nodes, + uint32_t delay, + uint32_t timeout) { - std::set search_nodes; + std::set search_nodes; - for(int i=start_node; i<=end_node; i++) { + for (int i = start_node; i <= end_node; i++) { search_nodes.insert(i); } - return vscp_scanSlowForDevices(client, - guid, - search_nodes, - found_nodes, - delay, - timeout); + return vscp_scanSlowForDevices(client, guid, search_nodes, found_nodes, delay, timeout); } // ---------------------------------------------------------------------------- -template< typename T > -static std::string -int_to_hex( T i ) +template +static std::string +int_to_hex(T i) { std::stringstream stream; - stream << "0x" - << std::setfill ('0') << std::setw(sizeof(T)*2) - << std::hex << i; + stream << "0x" << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex << i; return stream.str(); } @@ -666,7 +656,8 @@ int_to_hex( T i ) // fillDeviceHtmlInfo // -std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) +std::string +vscp_getDeviceInfoHtml(CMDF &mdf, CStandardRegisters &stdregs) { int idx; std::string html; @@ -750,8 +741,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) html += "
"; html += "User Device ID: "; - html += - std::to_string(stdregs.getReg(VSCP_STD_REGISTER_USER_ID)); + html += std::to_string(stdregs.getReg(VSCP_STD_REGISTER_USER_ID)); html += "."; html += std::to_string(stdregs.getReg(VSCP_STD_REGISTER_USER_ID + 1)); html += "."; @@ -763,10 +753,9 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) html += "
"; html += "
Manufacturer Device ID: "; - html += int_to_hex(stdregs.getManufacturerDeviceID()); // TODO: print as hex + html += int_to_hex(stdregs.getManufacturerDeviceID()); // TODO: print as hex html += " - "; - html += std::to_string(stdregs.getReg(VSCP_STD_REGISTER_USER_MANDEV_ID)) - ; + html += std::to_string(stdregs.getReg(VSCP_STD_REGISTER_USER_MANDEV_ID)); html += "."; html += std::to_string(stdregs.getReg(VSCP_STD_REGISTER_USER_MANDEV_ID + 1)); html += "."; @@ -843,7 +832,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) } html += "
"; - CMDF_DecisionMatrix* pdm = mdf.getDM(); + CMDF_DecisionMatrix *pdm = mdf.getDM(); if ((nullptr == pdm) || !pdm->getRowCount()) { html += "No Decision Matrix is available on this device."; html += "
"; @@ -925,7 +914,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) html += "

"; idx = 0; - CMDF_Item* phone; + CMDF_Item *phone; while (nullptr != (phone = mdf.getManufacturer()->getPhoneObj(idx))) { html += "
Phone: "; html += phone->getName(); @@ -936,7 +925,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) } idx = 0; - CMDF_Item* fax; + CMDF_Item *fax; while (nullptr != (fax = mdf.getManufacturer()->getFaxObj(idx))) { html += "Fax: "; html += fax->getName(); @@ -947,7 +936,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) } idx = 0; - CMDF_Item* email; + CMDF_Item *email; while (nullptr != (email = mdf.getManufacturer()->getEmailObj(idx))) { html += "Email: "; html += email->getName(); @@ -958,7 +947,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) } idx = 0; - CMDF_Item* web; + CMDF_Item *web; while (nullptr != (web = mdf.getManufacturer()->getWebObj(idx))) { html += "Web: "; html += web->getName(); @@ -979,7 +968,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) html += "
  • getUrl(); html += "\">"; - + if (mdf.getPictureObj(i)->getName().length()) { html += mdf.getPictureObj(i)->getName(); } @@ -1000,7 +989,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) html += "
  • getUrl(); html += "\">"; - + if (mdf.getVideoObj(i)->getName().length()) { html += mdf.getVideoObj(i)->getName(); } @@ -1021,7 +1010,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) html += "
  • getUrl(); html += "\">"; - + if (mdf.getFirmwareObj(i)->getName().length()) { html += mdf.getFirmwareObj(i)->getName(); } @@ -1042,7 +1031,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) html += "
  • getUrl(); html += "\">"; - + if (mdf.getDriverObj(i)->getName().length()) { html += mdf.getDriverObj(i)->getName(); } @@ -1063,7 +1052,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) html += "
  • getUrl(); html += "\">"; - + if (mdf.getManualObj(i)->getName().length()) { html += mdf.getManualObj(i)->getName(); } @@ -1084,7 +1073,7 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) html += "
  • getUrl(); html += "\">"; - + if (mdf.getSetupObj(i)->getName().length()) { html += mdf.getSetupObj(i)->getName(); } @@ -1098,20 +1087,16 @@ std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs) // ------------------------------------------------------------------------ - html += ""; html += ""; // Set the HTML - //ui->infoArea->setHtml(html.c_str()); + // ui->infoArea->setHtml(html.c_str()); return html; } - // -------------------------------------------------------------------------- - - /////////////////////////////////////////////////////////////////////////////// // Constructor // @@ -1131,10 +1116,10 @@ CRegisterPage::~CRegisterPage() // putLevel1Registers // -void -CRegisterPage::putLevel1Registers(std::map& registers) +void +CRegisterPage::putLevel1Registers(std::map ®isters) { - for (auto const& reg : registers) { + for (auto const ® : registers) { putReg(reg.first, reg.second); } } @@ -1143,10 +1128,10 @@ CRegisterPage::putLevel1Registers(std::map& registers) // getLevel1Registers // -void -CRegisterPage::getLevel1Registers(std::map& registers) +void +CRegisterPage::getLevel1Registers(std::map ®isters) { - for (auto const& reg : m_registers) { + for (auto const ® : m_registers) { if (reg.first < 128) { registers[reg.first] = reg.second; } @@ -1183,11 +1168,12 @@ CRegisterPage::putReg(uint32_t reg, uint8_t value) return -1; // Invalid reg offset for Level I device } - //std::cout << "Put reg " << (int)reg << " new value = " << (int)value << " old value = " << (int)m_registers[reg] << std::endl; + // std::cout << "Put reg " << (int)reg << " new value = " << (int)value << " old value = " << (int)m_registers[reg] + // << std::endl; // Mark as changed only if different if (m_registers[reg] != value) { - m_change[reg] = true; // Mark as changed + m_change[reg] = true; // Mark as changed m_list_undo_value[reg].push_back(m_registers[reg]); // Save old value } @@ -1198,10 +1184,10 @@ CRegisterPage::putReg(uint32_t reg, uint8_t value) // hasChanges // -bool +bool CRegisterPage::hasChanges(void) { - for (auto const& reg : m_change) { + for (auto const ® : m_change) { if (reg.second) { return true; } @@ -1211,8 +1197,6 @@ CRegisterPage::hasChanges(void) //----------------------------------------------------------------------------- - - /////////////////////////////////////////////////////////////////////////////// // Constructor // @@ -1226,7 +1210,7 @@ CStandardRegisters::CStandardRegisters(uint8_t level) // Destructor // -CStandardRegisters::~CStandardRegisters() +CStandardRegisters::~CStandardRegisters() { ; } @@ -1235,10 +1219,8 @@ CStandardRegisters::~CStandardRegisters() // getFirmwareVersionString. // -int CStandardRegisters::init(CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint32_t timeout) +int +CStandardRegisters::init(CVscpClient &client, cguid &guidNode, cguid &guidInterface, uint32_t timeout) { int rv; m_regs.clear(); @@ -1251,13 +1233,14 @@ int CStandardRegisters::init(CVscpClient& client, // getFirmwareVersionString. // -int CStandardRegisters::init(CRegisterPage& regPage) +int +CStandardRegisters::init(CRegisterPage ®Page) { if (regPage.getPage() != 0) { return VSCP_ERROR_INIT_MISSING; } - for (int i=0x80; i<0x100; i++) { + for (int i = 0x80; i < 0x100; i++) { if ((i < 0xa5) || (i > 0xcf)) { m_regs[i] = regPage.getReg(i); } @@ -1270,14 +1253,12 @@ int CStandardRegisters::init(CRegisterPage& regPage) // restoreStandardConfig. // -int restoreStandardConfig(CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint32_t timeout) +int +restoreStandardConfig(CVscpClient &client, cguid &guidNode, cguid &guidInterface, uint32_t timeout) { int rv; rv = vscp_writeLevel1Register(client, guidNode, guidInterface, 0, 0xA2, 0x55, timeout); - if ( VSCP_ERROR_SUCCESS != rv ) { + if (VSCP_ERROR_SUCCESS != rv) { return rv; } rv = vscp_writeLevel1Register(client, guidNode, guidInterface, 0, 0xA2, 0xAA, timeout); @@ -1297,15 +1278,15 @@ CStandardRegisters::getFirmwareVersionString(void) return str; } - /////////////////////////////////////////////////////////////////////////////// // getGUID // -void CStandardRegisters::getGUID(cguid& guid) -{ - for (int i=0; i<16; i++) { - //std::cout << std::hex << (int)m_regs[0xd0 + i] << std::endl; +void +CStandardRegisters::getGUID(cguid &guid) +{ + for (int i = 0; i < 16; i++) { + // std::cout << std::hex << (int)m_regs[0xd0 + i] << std::endl; guid.setAt(i, m_regs[0xd0 + i]); } } @@ -1325,17 +1306,17 @@ CStandardRegisters::getMDF(void) } remoteFile = std::string(url); - return(remoteFile); + return (remoteFile); } /////////////////////////////////////////////////////////////////////////////// // hasChanges // -bool +bool CStandardRegisters::hasChanges(void) { - for (auto const& reg : m_change) { + for (auto const ® : m_change) { if (reg.second) { return true; } @@ -1343,12 +1324,8 @@ CStandardRegisters::hasChanges(void) return false; } - - //----------------------------------------------------------------------------- - - /////////////////////////////////////////////////////////////////////////////// // Constructor // @@ -1362,7 +1339,7 @@ CUserRegisters::CUserRegisters(uint8_t level) // Destructor // -CUserRegisters::~CUserRegisters() +CUserRegisters::~CUserRegisters() { ; } @@ -1371,28 +1348,22 @@ CUserRegisters::~CUserRegisters() // init // -int CUserRegisters::init(CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - std::set& pages, - uint32_t timeout) +int +CUserRegisters::init(CVscpClient &client, + cguid &guidNode, + cguid &guidInterface, + std::set &pages, + uint32_t timeout) { int rv = VSCP_ERROR_SUCCESS; m_pages.clear(); - for (auto const& page : pages) { - + for (auto const &page : pages) { + std::map registers; m_registerPageMap[page] = new CRegisterPage(m_level, page); - rv = vscp_readLevel1RegisterBlock(client, - guidNode, - guidInterface, - page, - 0, - 127, - registers, - timeout); - if ( VSCP_ERROR_SUCCESS != rv ) { + rv = vscp_readLevel1RegisterBlock(client, guidNode, guidInterface, page, 0, 127, registers, timeout); + if (VSCP_ERROR_SUCCESS != rv) { return rv; } @@ -1400,7 +1371,7 @@ int CUserRegisters::init(CVscpClient& client, m_registerPageMap[page]->putLevel1Registers(registers); m_registerPageMap[page]->clearChanges(); m_pages.insert(page); - //std::cout << "Page " << std::hex << page << " size " << registers.size() << std::endl; + // std::cout << "Page " << std::hex << page << " size " << registers.size() << std::endl; } return rv; } @@ -1409,11 +1380,12 @@ int CUserRegisters::init(CVscpClient& client, // getRegPointer // -std::map *CUserRegisters::getRegisterMap( uint16_t page ) -{ +std::map * +CUserRegisters::getRegisterMap(uint16_t page) +{ CRegisterPage *pPage = NULL; - pPage = m_registerPageMap[page]; + pPage = m_registerPageMap[page]; if (nullptr == pPage) { return nullptr; } @@ -1447,7 +1419,7 @@ CUserRegisters::getReg(uint32_t offset, uint16_t page) if (it == ppage->getRegisterMap()->end()) { return -1; } - + return ppage->getRegisterMap()->at(offset); } @@ -1469,8 +1441,8 @@ CUserRegisters::putReg(uint32_t reg, uint32_t page, uint8_t value) return false; // Invalid page for level II device } } - else { - return false; // Level is wrong + else { + return false; // Level is wrong } // A new page will automatically be created @@ -1514,7 +1486,7 @@ CUserRegisters::putReg(uint32_t reg, uint32_t page, uint8_t value) // setChangedState // -bool +bool CUserRegisters::setChangedState(uint32_t offset, uint16_t page, bool state) { CRegisterPage *pPage = m_registerPageMap[page]; @@ -1522,7 +1494,7 @@ CUserRegisters::setChangedState(uint32_t offset, uint16_t page, bool state) return false; } - pPage->setChangedState(offset, state); + pPage->setChangedState(offset, state); return true; } @@ -1530,7 +1502,7 @@ CUserRegisters::setChangedState(uint32_t offset, uint16_t page, bool state) // isChanged // -bool +bool CUserRegisters::isChanged(uint32_t offset, uint16_t page) { CRegisterPage *pPage = m_registerPageMap[page]; @@ -1538,14 +1510,14 @@ CUserRegisters::isChanged(uint32_t offset, uint16_t page) return false; } - return pPage->isChanged(offset); + return pPage->isChanged(offset); } /////////////////////////////////////////////////////////////////////////////// // hasWrittenChange // -bool +bool CUserRegisters::hasWrittenChange(uint32_t offset, uint16_t page) { CRegisterPage *pPage = m_registerPageMap[page]; @@ -1564,9 +1536,9 @@ CUserRegisters::hasWrittenChange(uint32_t offset, uint16_t page) void CUserRegisters::clearChanges(void) { - for (auto const& page : m_registerPageMap) { + for (auto const &page : m_registerPageMap) { page.second->clearChanges(); - } + } } /////////////////////////////////////////////////////////////////////////////// @@ -1576,9 +1548,9 @@ CUserRegisters::clearChanges(void) void CUserRegisters::clearHistory(void) { - for (auto const& page : m_registerPageMap) { + for (auto const &page : m_registerPageMap) { page.second->clearHistory(); - } + } } /////////////////////////////////////////////////////////////////////////////// @@ -1586,9 +1558,7 @@ CUserRegisters::clearHistory(void) // int -CUserRegisters::remoteVarFromRegToString(CMDF_RemoteVariable& remoteVar, - std::string& strValue, - uint8_t format) +CUserRegisters::remoteVarFromRegToString(CMDF_RemoteVariable &remoteVar, std::string &strValue, uint8_t format) { int rv = VSCP_ERROR_SUCCESS; @@ -1603,250 +1573,207 @@ CUserRegisters::remoteVarFromRegToString(CMDF_RemoteVariable& remoteVar, // vscp_remote_variable_type switch (remoteVar.getType()) { - case remote_variable_type_string: - { - uint8_t *pstr; - pstr = new uint8_t[remoteVar.getTypeByteCount() + 1 ]; - if ( nullptr == pstr ) return false; - memset(pstr, 0, sizeof(pstr)); - for (unsigned int i = remoteVar.getOffset(); - i < (remoteVar.getOffset() + remoteVar.getTypeByteCount()); - i++) { - pstr[i] = ppage->getReg(i); - } - strValue = (const char *)pstr; - delete [] pstr; + case remote_variable_type_string: { + uint8_t *pstr; + pstr = new uint8_t[remoteVar.getTypeByteCount() + 1]; + if (nullptr == pstr) + return false; + memset(pstr, 0, sizeof(pstr)); + for (unsigned int i = remoteVar.getOffset(); i < (remoteVar.getOffset() + remoteVar.getTypeByteCount()); i++) { + pstr[i] = ppage->getReg(i); } - break; + strValue = (const char *) pstr; + delete[] pstr; + } break; + + case remote_variable_type_boolean: { + strValue = ppage->getReg(remoteVar.getOffset() & (1 << remoteVar.getBitPos())) ? "true" : "false"; + } break; - case remote_variable_type_boolean: - { - strValue = ppage->getReg(remoteVar.getOffset() & (1<getReg(remoteVar.getOffset())); } - break; + else { + strValue = vscp_str_format("0x%02hx", ppage->getReg(remoteVar.getOffset())); + } + } break; - case remote_variable_type_int8_t: - { - if ( FORMAT_REMOTEVAR_DECIMAL == format ) { - strValue = vscp_str_format("%had", ppage->getReg(remoteVar.getOffset())); - } - else { - strValue = vscp_str_format( "0x%02hx", ppage->getReg(remoteVar.getOffset())); - } + case remote_variable_type_uint8_t: { + if (FORMAT_REMOTEVAR_DECIMAL == format) { + strValue = vscp_str_format("%hu", ppage->getReg(remoteVar.getOffset())); } - break; + else { + strValue = vscp_str_format("0x%02hx", ppage->getReg(remoteVar.getOffset())); + } + } break; + + case remote_variable_type_int16_t: { + uint8_t buf[2]; + buf[0] = ppage->getReg(remoteVar.getOffset()); + buf[1] = ppage->getReg(remoteVar.getOffset() + 1); + int16_t val = (buf[0] << 8) + buf[1]; + + if (FORMAT_REMOTEVAR_DECIMAL == format) { + strValue = vscp_str_format("%hd", val); + } + else { + strValue = vscp_str_format("0x%04hx", val); + } + } break; - case remote_variable_type_uint8_t: - { - if ( FORMAT_REMOTEVAR_DECIMAL == format ) { - strValue = vscp_str_format( "%hu", ppage->getReg(remoteVar.getOffset())); + case remote_variable_type_uint16_t: { + uint8_t buf[2]; + buf[0] = ppage->getReg(remoteVar.getOffset()); + buf[1] = ppage->getReg(remoteVar.getOffset() + 1); + uint16_t val = (buf[0] << 8) + buf[1]; + + if (FORMAT_REMOTEVAR_DECIMAL == format) { + strValue = vscp_str_format("hd", val); + } + else { + strValue = vscp_str_format("0x%04hx", val); + } + } break; + + case remote_variable_type_int32_t: { + uint8_t *buf; + buf = (uint8_t *) malloc(remoteVar.getTypeByteCount()); + if (NULL != buf) { + for (int i = 0; i < remoteVar.getTypeByteCount(); i++) { + buf[i] = ppage->getReg(remoteVar.getOffset() + i); + } + int32_t val = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; + if (FORMAT_REMOTEVAR_DECIMAL == format) { + strValue = vscp_str_format("%ld", val); } else { - strValue = vscp_str_format( "0x%02hx", ppage->getReg(remoteVar.getOffset())); + strValue = vscp_str_format("0x%04lx", val); } + delete[] buf; } - break; - - case remote_variable_type_int16_t: - { - uint8_t buf[2]; - buf[0] = ppage->getReg(remoteVar.getOffset()); - buf[1] = ppage->getReg(remoteVar.getOffset()+1); - int16_t val = (buf[0] << 8 ) + buf[1]; - - if ( FORMAT_REMOTEVAR_DECIMAL == format ) { - strValue = vscp_str_format( "%hd", val ); + } break; + + case remote_variable_type_uint32_t: { + uint8_t *buf; + buf = (uint8_t *) malloc(remoteVar.getTypeByteCount()); + if (NULL != buf) { + for (int i = 0; i < remoteVar.getTypeByteCount(); i++) { + buf[i] = ppage->getReg(remoteVar.getOffset() + i); + } + uint32_t val = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; + if (FORMAT_REMOTEVAR_DECIMAL == format) { + strValue = vscp_str_format("%lu", val); } else { - strValue = vscp_str_format( "0x%04hx", val ); + strValue = vscp_str_format("0x%04lx", val); } + delete[] buf; } - break; + } break; + + case remote_variable_type_int64_t: { + uint8_t *buf; + buf = (uint8_t *) malloc(remoteVar.getTypeByteCount()); + if (NULL != buf) { + for (int i = 0; i < remoteVar.getTypeByteCount(); i++) { + buf[i] = ppage->getReg(remoteVar.getOffset() + i); + } - case remote_variable_type_uint16_t: - { - uint8_t buf[2]; - buf[0] = ppage->getReg(remoteVar.getOffset()); - buf[1] = ppage->getReg(remoteVar.getOffset()+1); - uint16_t val = (buf[0] << 8 ) + buf[1]; + int64_t val = (int64_t) (((uint64_t) buf[0] << 56) + ((uint64_t) buf[1] << 48) + ((uint64_t) buf[2] << 40) + + ((uint64_t) buf[3] << 32) + ((uint64_t) buf[4] << 24) + ((uint64_t) buf[5] << 16) + + ((uint64_t) buf[6] << 8) + (uint64_t) buf[7]); - if ( FORMAT_REMOTEVAR_DECIMAL == format ) { - strValue = vscp_str_format( "hd", val ); + if (FORMAT_REMOTEVAR_DECIMAL == format) { + strValue = vscp_str_format("%lld", val); } else { - strValue = vscp_str_format( "0x%04hx", val ); + strValue = vscp_str_format("0x%llx", val); } + delete[] buf; } - break; - - case remote_variable_type_int32_t: - { - uint8_t *buf; - buf = (uint8_t *)malloc(remoteVar.getTypeByteCount()); - if (NULL != buf) { - for ( int i = 0; i < remoteVar.getTypeByteCount(); i++ ) { - buf[i] = ppage->getReg(remoteVar.getOffset() + i); - } - int32_t val = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; - if ( FORMAT_REMOTEVAR_DECIMAL == format ) { - strValue = vscp_str_format( "%ld", val); - } - else { - strValue = vscp_str_format( "0x%04lx", val); - } - delete [] buf; + } break; + + case remote_variable_type_uint64_t: { + uint8_t *buf; + buf = (uint8_t *) malloc(remoteVar.getTypeByteCount()); + if (NULL != buf) { + for (int i = 0; i < remoteVar.getTypeByteCount(); i++) { + buf[i] = ppage->getReg(remoteVar.getOffset() + i); } - } - break; - case remote_variable_type_uint32_t: - { - uint8_t *buf; - buf = (uint8_t *)malloc(remoteVar.getTypeByteCount()); - if (NULL != buf) { - for ( int i = 0; i < remoteVar.getTypeByteCount(); i++ ) { - buf[i] = ppage->getReg(remoteVar.getOffset() + i); - } - uint32_t val = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; - if ( FORMAT_REMOTEVAR_DECIMAL == format ) { - strValue = vscp_str_format( "%lu", val); - } - else { - strValue = vscp_str_format( "0x%04lx", val); - } - delete [] buf; + uint64_t val = ((uint64_t) buf[0] << 56) + ((uint64_t) buf[1] << 48) + ((uint64_t) buf[2] << 40) + + ((uint64_t) buf[3] << 32) + ((uint64_t) buf[4] << 24) + ((uint64_t) buf[5] << 16) + + ((uint64_t) buf[6] << 8) + (uint64_t) buf[7]; + if (FORMAT_REMOTEVAR_DECIMAL == format) { + strValue = vscp_str_format("%ullu", val); } - } - break; - - case remote_variable_type_int64_t: - { - uint8_t *buf; - buf = (uint8_t *)malloc(remoteVar.getTypeByteCount()); - if (NULL != buf) { - for ( int i = 0; i < remoteVar.getTypeByteCount(); i++ ) { - buf[i] = ppage->getReg(remoteVar.getOffset() + i); - } - - int64_t val = (int64_t)(((uint64_t)buf[0] << 56) + - ((uint64_t)buf[1] << 48) + - ((uint64_t)buf[2] << 40) + - ((uint64_t)buf[3] << 32) + - ((uint64_t)buf[4] << 24) + - ((uint64_t)buf[5] << 16) + - ((uint64_t)buf[6] << 8) + - (uint64_t)buf[7]); - - if ( FORMAT_REMOTEVAR_DECIMAL == format ) { - strValue = vscp_str_format( "%lld", val ); - } - else { - strValue = vscp_str_format( "0x%llx", val ); - } - delete [] buf; + else { + strValue = vscp_str_format("0x%ullx", val); } + delete[] buf; } - break; - - case remote_variable_type_uint64_t: - { - uint8_t *buf; - buf = (uint8_t *)malloc(remoteVar.getTypeByteCount()); - if (NULL != buf) { - for ( int i = 0; i < remoteVar.getTypeByteCount(); i++ ) { - buf[i] = ppage->getReg(remoteVar.getOffset() + i); - } - - uint64_t val = ((uint64_t)buf[0] << 56) + - ((uint64_t)buf[1] << 48) + - ((uint64_t)buf[2] << 40) + - ((uint64_t)buf[3] << 32) + - ((uint64_t)buf[4] << 24) + - ((uint64_t)buf[5] << 16) + - ((uint64_t)buf[6] << 8) + - (uint64_t)buf[7]; - if ( FORMAT_REMOTEVAR_DECIMAL == format ) { - strValue = vscp_str_format("%ullu", val); - } - else { - strValue = vscp_str_format("0x%ullx", val); - } - delete [] buf; + } break; + + case remote_variable_type_float: { + uint8_t *buf; + buf = (uint8_t *) malloc(remoteVar.getTypeByteCount()); + if (NULL != buf) { + for (int i = 0; i < remoteVar.getTypeByteCount(); i++) { + buf[i] = ppage->getReg(remoteVar.getOffset() + i); } + uint32_t n = VSCP_UINT32_SWAP_ON_LE(*((uint32_t *) buf)); + float f = *((float *) ((uint8_t *) &n)); + strValue = vscp_str_format("%f", *((float *) buf)); + delete[] buf; } - break; - - case remote_variable_type_float: - { - uint8_t *buf; - buf = (uint8_t *)malloc(remoteVar.getTypeByteCount()); - if (NULL != buf) { - for ( int i = 0; i < remoteVar.getTypeByteCount(); i++ ) { - buf[i] = ppage->getReg(remoteVar.getOffset() + i); - } - uint32_t n = VSCP_UINT32_SWAP_ON_LE( *((uint32_t *)buf)); - float f = *( (float *)((uint8_t *)&n ) ); - strValue = vscp_str_format( "%f", *((float *)buf)); - delete [] buf; + } break; + + case remote_variable_type_double: { + uint8_t *buf; + buf = (uint8_t *) malloc(remoteVar.getTypeByteCount()); + if (NULL != buf) { + for (int i = 0; i < remoteVar.getTypeByteCount(); i++) { + buf[i] = ppage->getReg(remoteVar.getOffset() + i); } - } - break; + uint64_t n = VSCP_UINT32_SWAP_ON_LE(*((uint32_t *) buf)); + double f = *((double *) ((uint8_t *) &n)); + strValue = vscp_str_format("%g", *((double *) buf)); - case remote_variable_type_double: - { - uint8_t *buf; - buf = (uint8_t *)malloc(remoteVar.getTypeByteCount()); - if (NULL != buf) { - for ( int i = 0; i < remoteVar.getTypeByteCount(); i++ ) { - buf[i] = ppage->getReg(remoteVar.getOffset() + i); - } - uint64_t n = VSCP_UINT32_SWAP_ON_LE( *( (uint32_t *)buf)); - double f = *( (double *)((uint8_t *)&n ) ); - strValue = vscp_str_format( "%g", *((double *)buf)); - - delete [] buf; - } + delete[] buf; } - break; - - case remote_variable_type_date: - { - uint8_t *buf; - buf = (uint8_t *)malloc(remoteVar.getTypeByteCount()); - if (NULL != buf) { - for ( int i = 0; i < remoteVar.getTypeByteCount(); i++ ) { - buf[i] = ppage->getReg(remoteVar.getOffset() + i); - } - strValue = vscp_str_format("%02d-%02d-%02d", - *((uint8_t *)buf), - *((uint8_t *)(buf+2)), - *((uint8_t *)(buf+4))); - delete [] buf; + } break; + + case remote_variable_type_date: { + uint8_t *buf; + buf = (uint8_t *) malloc(remoteVar.getTypeByteCount()); + if (NULL != buf) { + for (int i = 0; i < remoteVar.getTypeByteCount(); i++) { + buf[i] = ppage->getReg(remoteVar.getOffset() + i); } + strValue = + vscp_str_format("%02d-%02d-%02d", *((uint8_t *) buf), *((uint8_t *) (buf + 2)), *((uint8_t *) (buf + 4))); + delete[] buf; } - break; - - case remote_variable_type_time: - { - uint8_t *buf; - buf = (uint8_t *)malloc(remoteVar.getTypeByteCount()); - if (NULL != buf) { - for ( int i = 0; i < remoteVar.getTypeByteCount(); i++ ) { - buf[i] = ppage->getReg(remoteVar.getOffset() + i); - } - strValue = vscp_str_format("%02d:%02d:%02d", - *((uint8_t *)buf), - *((uint8_t *)(buf+2)), - *((uint8_t *)(buf+4))); - delete [] buf; - } + } break; + + case remote_variable_type_time: { + uint8_t *buf; + buf = (uint8_t *) malloc(remoteVar.getTypeByteCount()); + if (NULL != buf) { + for (int i = 0; i < remoteVar.getTypeByteCount(); i++) { + buf[i] = ppage->getReg(remoteVar.getOffset() + i); + } + strValue = + vscp_str_format("%02d:%02d:%02d", *((uint8_t *) buf), *((uint8_t *) (buf + 2)), *((uint8_t *) (buf + 4))); + delete[] buf; } - break; + } break; case remote_variable_type_unknown: default: - strValue = ""; - break; + strValue = ""; + break; } return rv; @@ -1857,188 +1784,161 @@ CUserRegisters::remoteVarFromRegToString(CMDF_RemoteVariable& remoteVar, // int -CUserRegisters::remoteVarFromStringToReg(CMDF_RemoteVariable& remoteVar, std::string &strValue) +CUserRegisters::remoteVarFromStringToReg(CMDF_RemoteVariable &remoteVar, std::string &strValue) { - bool rv = VSCP_ERROR_SUCCESS; - CRegisterPage *ppage = getRegisterPage( remoteVar.getPage() ); - if (nullptr == ppage) return VSCP_ERROR_ERROR; + bool rv = VSCP_ERROR_SUCCESS; + CRegisterPage *ppage = getRegisterPage(remoteVar.getPage()); + if (nullptr == ppage) + return VSCP_ERROR_ERROR; switch (remoteVar.getType()) { - case remote_variable_type_string: - { - /*! - It is possible to write registers here that is out of bonds - for a level I device but that is not a problem as they never - will be written to the device. - */ - for (int i=0; iputReg(remoteVar.getOffset() + i, strValue[i]); - } - } - break; - - case remote_variable_type_boolean: - { - uint8_t val = ppage->getReg(remoteVar.getOffset()); - if ( 0 == strValue.compare("true") ) { - val |= (1 << remoteVar.getBitPos()); - } - else if ( 0 == strValue.compare("false") ) { - val &= ~(1 << remoteVar.getBitPos()); - } - else { - val = (uint8_t)vscp_readStringValue(strValue); - } - - ppage->putReg(remoteVar.getOffset(), val); - } - break; - - case remote_variable_type_int8_t: - { - int8_t val = vscp_readStringValue(strValue); - ppage->putReg(remoteVar.getOffset(), val); - } - break; - - case remote_variable_type_uint8_t: - { - uint8_t val = vscp_readStringValue(strValue); - ppage->putReg(remoteVar.getOffset(), val); - } - break; - - case remote_variable_type_int16_t: - { - int16_t val = vscp_readStringValue(strValue); - ppage->putReg(remoteVar.getOffset(), (val >> 8) & 0xff); - ppage->putReg(remoteVar.getOffset() + 1, val & 0xff); - } - break; - - case remote_variable_type_uint16_t: - { - uint16_t val = vscp_readStringValue(strValue); - ppage->putReg(remoteVar.getOffset(), (val >> 8) & 0xff); - ppage->putReg(remoteVar.getOffset() + 1, val & 0xff); - } - break; - - case remote_variable_type_int32_t: - { - int32_t val = vscp_readStringValue(strValue); - ppage->putReg(remoteVar.getOffset(), (val >> 24) & 0xff); - ppage->putReg(remoteVar.getOffset() + 1, (val >> 16) & 0xff); - ppage->putReg(remoteVar.getOffset() + 2, (val >> 8) & 0xff); - ppage->putReg(remoteVar.getOffset() + 3, val & 0xff); + case remote_variable_type_string: { + /*! + It is possible to write registers here that is out of bonds + for a level I device but that is not a problem as they never + will be written to the device. + */ + for (int i = 0; i < strValue.length(); i++) { + ppage->putReg(remoteVar.getOffset() + i, strValue[i]); } - break; + } break; - case remote_variable_type_uint32_t: - { - uint32_t val = vscp_readStringValue(strValue); - ppage->putReg(remoteVar.getOffset(), (val >> 24) & 0xff); - ppage->putReg(remoteVar.getOffset() + 1, (val >> 16) & 0xff); - ppage->putReg(remoteVar.getOffset() + 2, (val >> 8) & 0xff); - ppage->putReg(remoteVar.getOffset() + 3, val & 0xff); + case remote_variable_type_boolean: { + uint8_t val = ppage->getReg(remoteVar.getOffset()); + if (0 == strValue.compare("true")) { + val |= (1 << remoteVar.getBitPos()); } - break; - - case remote_variable_type_int64_t: - { - int64_t val = vscp_readStringValue(strValue); - ppage->putReg(remoteVar.getOffset(), (val >> 56) & 0xff); - ppage->putReg(remoteVar.getOffset() + 1, (val >> 48) & 0xff); - ppage->putReg(remoteVar.getOffset() + 2, (val >> 40) & 0xff); - ppage->putReg(remoteVar.getOffset() + 3, (val >> 32) & 0xff); - ppage->putReg(remoteVar.getOffset() + 4, (val >> 24) & 0xff); - ppage->putReg(remoteVar.getOffset() + 5, (val >> 16) & 0xff); - ppage->putReg(remoteVar.getOffset() + 6, (val >> 8) & 0xff); - ppage->putReg(remoteVar.getOffset() + 7, val & 0xff); - } - break; - - case remote_variable_type_uint64_t: - { - uint64_t val = vscp_readStringValue(strValue); - ppage->putReg(remoteVar.getOffset(), (val >> 56) & 0xff); - ppage->putReg(remoteVar.getOffset() + 1, (val >> 48) & 0xff); - ppage->putReg(remoteVar.getOffset() + 2, (val >> 40) & 0xff); - ppage->putReg(remoteVar.getOffset() + 3, (val >> 32) & 0xff); - ppage->putReg(remoteVar.getOffset() + 4, (val >> 24) & 0xff); - ppage->putReg(remoteVar.getOffset() + 5, (val >> 16) & 0xff); - ppage->putReg(remoteVar.getOffset() + 6, (val >> 8) & 0xff); - ppage->putReg(remoteVar.getOffset() + 7, val & 0xff); + else if (0 == strValue.compare("false")) { + val &= ~(1 << remoteVar.getBitPos()); } - break; - - case remote_variable_type_float: - { - float val = (float)vscp_readStringValue(strValue); - uint8_t *p = (uint8_t *)&val; - val = (float)VSCP_INT32_SWAP_ON_LE(*((int64_t *)p)); - ppage->putReg(remoteVar.getOffset(), *p); - ppage->putReg(remoteVar.getOffset() + 1, *(p+1)); - ppage->putReg(remoteVar.getOffset() + 2, *(p+2)); - ppage->putReg(remoteVar.getOffset() + 3, *(p+3)); + else { + val = (uint8_t) vscp_readStringValue(strValue); } - break; - case remote_variable_type_double: - { - double val = vscp_readStringValue(strValue); - uint8_t *p = (uint8_t *)&val; + ppage->putReg(remoteVar.getOffset(), val); + } break; + + case remote_variable_type_int8_t: { + int8_t val = vscp_readStringValue(strValue); + ppage->putReg(remoteVar.getOffset(), val); + } break; + + case remote_variable_type_uint8_t: { + uint8_t val = vscp_readStringValue(strValue); + ppage->putReg(remoteVar.getOffset(), val); + } break; + + case remote_variable_type_int16_t: { + int16_t val = vscp_readStringValue(strValue); + ppage->putReg(remoteVar.getOffset(), (val >> 8) & 0xff); + ppage->putReg(remoteVar.getOffset() + 1, val & 0xff); + } break; + + case remote_variable_type_uint16_t: { + uint16_t val = vscp_readStringValue(strValue); + ppage->putReg(remoteVar.getOffset(), (val >> 8) & 0xff); + ppage->putReg(remoteVar.getOffset() + 1, val & 0xff); + } break; + + case remote_variable_type_int32_t: { + int32_t val = vscp_readStringValue(strValue); + ppage->putReg(remoteVar.getOffset(), (val >> 24) & 0xff); + ppage->putReg(remoteVar.getOffset() + 1, (val >> 16) & 0xff); + ppage->putReg(remoteVar.getOffset() + 2, (val >> 8) & 0xff); + ppage->putReg(remoteVar.getOffset() + 3, val & 0xff); + } break; + + case remote_variable_type_uint32_t: { + uint32_t val = vscp_readStringValue(strValue); + ppage->putReg(remoteVar.getOffset(), (val >> 24) & 0xff); + ppage->putReg(remoteVar.getOffset() + 1, (val >> 16) & 0xff); + ppage->putReg(remoteVar.getOffset() + 2, (val >> 8) & 0xff); + ppage->putReg(remoteVar.getOffset() + 3, val & 0xff); + } break; + + case remote_variable_type_int64_t: { + int64_t val = vscp_readStringValue(strValue); + ppage->putReg(remoteVar.getOffset(), (val >> 56) & 0xff); + ppage->putReg(remoteVar.getOffset() + 1, (val >> 48) & 0xff); + ppage->putReg(remoteVar.getOffset() + 2, (val >> 40) & 0xff); + ppage->putReg(remoteVar.getOffset() + 3, (val >> 32) & 0xff); + ppage->putReg(remoteVar.getOffset() + 4, (val >> 24) & 0xff); + ppage->putReg(remoteVar.getOffset() + 5, (val >> 16) & 0xff); + ppage->putReg(remoteVar.getOffset() + 6, (val >> 8) & 0xff); + ppage->putReg(remoteVar.getOffset() + 7, val & 0xff); + } break; + + case remote_variable_type_uint64_t: { + uint64_t val = vscp_readStringValue(strValue); + ppage->putReg(remoteVar.getOffset(), (val >> 56) & 0xff); + ppage->putReg(remoteVar.getOffset() + 1, (val >> 48) & 0xff); + ppage->putReg(remoteVar.getOffset() + 2, (val >> 40) & 0xff); + ppage->putReg(remoteVar.getOffset() + 3, (val >> 32) & 0xff); + ppage->putReg(remoteVar.getOffset() + 4, (val >> 24) & 0xff); + ppage->putReg(remoteVar.getOffset() + 5, (val >> 16) & 0xff); + ppage->putReg(remoteVar.getOffset() + 6, (val >> 8) & 0xff); + ppage->putReg(remoteVar.getOffset() + 7, val & 0xff); + } break; + + case remote_variable_type_float: { + float val = (float) vscp_readStringValue(strValue); + uint8_t *p = (uint8_t *) &val; + val = (float) VSCP_INT32_SWAP_ON_LE(*((int64_t *) p)); + ppage->putReg(remoteVar.getOffset(), *p); + ppage->putReg(remoteVar.getOffset() + 1, *(p + 1)); + ppage->putReg(remoteVar.getOffset() + 2, *(p + 2)); + ppage->putReg(remoteVar.getOffset() + 3, *(p + 3)); + } break; + + case remote_variable_type_double: { + double val = vscp_readStringValue(strValue); + uint8_t *p = (uint8_t *) &val; #ifndef __BIG_ENDIAN__ - val = (double)Swap8Bytes(*((int64_t *)p)); -#endif - ppage->putReg(remoteVar.getOffset(), *p); - ppage->putReg(remoteVar.getOffset() + 1, *(p+1)); - ppage->putReg(remoteVar.getOffset() + 2, *(p+2)); - ppage->putReg(remoteVar.getOffset() + 3, *(p+3)); - ppage->putReg(remoteVar.getOffset() + 4, *(p+4)); - ppage->putReg(remoteVar.getOffset() + 5, *(p+5)); - ppage->putReg(remoteVar.getOffset() + 6, *(p+6)); - ppage->putReg(remoteVar.getOffset() + 7, *(p+7)); - } - break; + val = (double) Swap8Bytes(*((int64_t *) p)); +#endif + ppage->putReg(remoteVar.getOffset(), *p); + ppage->putReg(remoteVar.getOffset() + 1, *(p + 1)); + ppage->putReg(remoteVar.getOffset() + 2, *(p + 2)); + ppage->putReg(remoteVar.getOffset() + 3, *(p + 3)); + ppage->putReg(remoteVar.getOffset() + 4, *(p + 4)); + ppage->putReg(remoteVar.getOffset() + 5, *(p + 5)); + ppage->putReg(remoteVar.getOffset() + 6, *(p + 6)); + ppage->putReg(remoteVar.getOffset() + 7, *(p + 7)); + } break; // YY:MM:DD - case remote_variable_type_date: - { - std::deque vec; - vscp_split(vec, strValue, ":"); - if (vec.size() == 3) { - uint8_t val = vscp_readStringValue(vec[0]); - ppage->putReg(remoteVar.getOffset(), val); - val = vscp_readStringValue(vec[1]); - ppage->putReg(remoteVar.getOffset() + 1, val); - val = vscp_readStringValue(vec[2]); - ppage->putReg(remoteVar.getOffset() + 2, val); - } + case remote_variable_type_date: { + std::deque vec; + vscp_split(vec, strValue, ":"); + if (vec.size() == 3) { + uint8_t val = vscp_readStringValue(vec[0]); + ppage->putReg(remoteVar.getOffset(), val); + val = vscp_readStringValue(vec[1]); + ppage->putReg(remoteVar.getOffset() + 1, val); + val = vscp_readStringValue(vec[2]); + ppage->putReg(remoteVar.getOffset() + 2, val); } - break; + } break; // HH:MM:SS - case remote_variable_type_time: - { - std::deque vec; - vscp_split(vec, strValue, ":"); - if (vec.size() == 3) { - uint8_t val = vscp_readStringValue(vec[0]); - ppage->putReg(remoteVar.getOffset(), val); - val = vscp_readStringValue(vec[1]); - ppage->putReg(remoteVar.getOffset() + 1, val); - val = vscp_readStringValue(vec[2]); - ppage->putReg(remoteVar.getOffset() + 2, val); - } + case remote_variable_type_time: { + std::deque vec; + vscp_split(vec, strValue, ":"); + if (vec.size() == 3) { + uint8_t val = vscp_readStringValue(vec[0]); + ppage->putReg(remoteVar.getOffset(), val); + val = vscp_readStringValue(vec[1]); + ppage->putReg(remoteVar.getOffset() + 1, val); + val = vscp_readStringValue(vec[2]); + ppage->putReg(remoteVar.getOffset() + 2, val); } - break; + } break; case remote_variable_type_unknown: default: - break; - } + break; + } return rv; } @@ -2046,8 +1946,8 @@ CUserRegisters::remoteVarFromStringToReg(CMDF_RemoteVariable& remoteVar, std::st // vscp_getGetDmRegisterContent // -int -CUserRegisters::vscp_getGetDmRegisterContent(CMDF_DecisionMatrix& dm, uint16_t row, uint8_t pos) +int +CUserRegisters::vscp_getGetDmRegisterContent(CMDF_DecisionMatrix &dm, uint16_t row, uint8_t pos) { CRegisterPage *ppage = getRegisterPage(dm.getStartPage()); if (nullptr == ppage) { @@ -2065,15 +1965,15 @@ CUserRegisters::vscp_getGetDmRegisterContent(CMDF_DecisionMatrix& dm, uint16_t r } // Get register - return(ppage->getReg(dm.getRowSize() * row)); + return (ppage->getReg(dm.getRowSize() * row)); } /////////////////////////////////////////////////////////////////////////////// // vscp_readDmRow // -int -CUserRegisters::vscp_readDmRow(CMDF_DecisionMatrix& dm, uint16_t row, uint8_t *buf) +int +CUserRegisters::vscp_readDmRow(CMDF_DecisionMatrix &dm, uint16_t row, uint8_t *buf) { CRegisterPage *ppage = getRegisterPage(dm.getStartPage()); if (nullptr == ppage) { @@ -2092,13 +1992,12 @@ CUserRegisters::vscp_readDmRow(CMDF_DecisionMatrix& dm, uint16_t row, uint8_t *b return VSCP_ERROR_SUCCESS; } - /////////////////////////////////////////////////////////////////////////////// // vscp_writeDmRow // -int -CUserRegisters::vscp_writeDmRow(CMDF_DecisionMatrix& dm, uint16_t row, uint8_t *buf) +int +CUserRegisters::vscp_writeDmRow(CMDF_DecisionMatrix &dm, uint16_t row, uint8_t *buf) { CRegisterPage *ppage = getRegisterPage(dm.getStartPage()); if (nullptr == ppage) { @@ -2121,7 +2020,7 @@ CUserRegisters::vscp_writeDmRow(CMDF_DecisionMatrix& dm, uint16_t row, uint8_t * // hasChanges // -bool +bool CUserRegisters::hasChanges(void) { for (auto it = m_registerPageMap.begin(); it != m_registerPageMap.end(); ++it) { @@ -2134,14 +2033,6 @@ CUserRegisters::hasChanges(void) /////////////////////////////////////////////////////////////////////////////// +CVscpNode::CVscpNode() {} -CVscpNode::CVscpNode() -{ - -} - - -CVscpNode::~CVscpNode() -{ - -} \ No newline at end of file +CVscpNode::~CVscpNode() {} \ No newline at end of file diff --git a/src/vscp/common/register.h b/src/vscp/common/register.h index b3df53880..2cbb88370 100644 --- a/src/vscp/common/register.h +++ b/src/vscp/common/register.h @@ -28,18 +28,18 @@ #ifndef _VSCP_REGISTER_H_ #define _VSCP_REGISTER_H_ -#include #include +#include -#include -#include -#include #include #include +#include +#include #include +#include -#define FORMAT_REMOTEVAR_DECIMAL 0 -#define FORMAT_REMOTEVAR_HEX 1 +#define FORMAT_REMOTEVAR_DECIMAL 0 +#define FORMAT_REMOTEVAR_HEX 1 class CRegisterPage; class CUserRegisters; @@ -50,68 +50,71 @@ class CStandardRegisters; @param client VSCP client derived from the client vase class over which the communication is carried out. @param guidNode GUID of the device to read from. Only the lsb (nickname) - is used for level I communication. + is used for level I communication. @param guidInterface GUID of the interface to read from. Set to all zero - if no interface. - @param page Register page to read from. + if no interface. + @param page Register page to read from. @param offset Register offset on page to read from. @param value Value read from register. @param timeout Timeout in milliseconds. Zero means no timeout i.e. wait forever. @return VSCP_ERROR_SUCCESS on success. */ -int vscp_readLevel1Register( CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint16_t page, - uint8_t offset, - uint8_t& value, - uint32_t timeout = 2000); +int +vscp_readLevel1Register(CVscpClient &client, + cguid &guidNode, + cguid &guidInterface, + uint16_t page, + uint8_t offset, + uint8_t &value, + uint32_t timeout = 2000); /*! Write VSCP register @param client VSCP client derived from the client vase class over - which the communication is carried out. + which the communication is carried out. @param guid GUID of the device to read from. Only the lsb (nickname) - is used for level I communication. + is used for level I communication. @param guidInterface GUID of the interface to read from. Set to all zero - if no interface. - @param page Register page to read from. + if no interface. + @param page Register page to read from. @param offset Register offset on page to read from. @param value Value to write. @param timeout Timeout in milliseconds. Zero means no timeout i.e. wait forever. - @return VSCP_ERROR_SUCCESS on success. + @return VSCP_ERROR_SUCCESS on success. */ -int vscp_writeLevel1Register( CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint16_t page, - uint8_t offset, - uint8_t value, - uint32_t timeout = 2000 ); +int +vscp_writeLevel1Register(CVscpClient &client, + cguid &guidNode, + cguid &guidInterface, + uint16_t page, + uint8_t offset, + uint8_t value, + uint32_t timeout = 2000); /*! Read VSCP register block. @param client VSCP client derived from the client vase class over which the communication is carried out. @param guidNode GUID of the device to read from. Only the lsb (nickname) - is used for level I communication. + is used for level I communication. @param guidInterface GUID of the interface to read from. Set to all zero - if no interface. - @param page Register page to read from. + if no interface. + @param page Register page to read from. @param offset Register offset on page to read from. @param count Number of registers to read. Zero means read 256 registers (0-255). @param values Pointer to map with registers to read. @param timeout Timeout in milliseconds. Zero means no timeout i.e. wait forever. @return VSCP_ERROR_SUCCESS on success. */ -int vscp_readLevel1RegisterBlock( CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint16_t page, - uint8_t offset, - uint8_t count, - std::map& values, - uint32_t timeout = 2000); +int +vscp_readLevel1RegisterBlock(CVscpClient &client, + cguid &guidNode, + cguid &guidInterface, + uint16_t page, + uint8_t offset, + uint8_t count, + std::map &values, + uint32_t timeout = 2000); /*! Write VSCP register block. @@ -119,82 +122,83 @@ int vscp_readLevel1RegisterBlock( CVscpClient& client, @param client VSCP client derived from the client vase class over which the communication is carried out. @param guidNode GUID of the device to read from. Only the lsb (nickname) - is used for level I communication. + is used for level I communication. @param guidInterface GUID of the interface to read from. Set to all zero - if no interface. - @param page Register page to read from. + if no interface. + @param page Register page to read from. @param values Pointer to map with register values to write. @param timeout Timeout in milliseconds. Zero means no timeout i.e. wait forever. @return VSCP_ERROR_SUCCESS on success. */ -int vscp_writeLevel1RegisterBlock( CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint16_t page, - std::map& values, - uint32_t timeout = 2000); +int +vscp_writeLevel1RegisterBlock(CVscpClient &client, + cguid &guidNode, + cguid &guidInterface, + uint16_t page, + std::map &values, + uint32_t timeout = 2000); /*! Read all standard registers */ -int vscp_readStandardRegisters(CVscpClient& client, - cguid& guid, - cguid& guidInterface, - CStandardRegisters& stdregs, - uint32_t timeout = 2000 ); +int +vscp_readStandardRegisters(CVscpClient &client, + cguid &guid, + cguid &guidInterface, + CStandardRegisters &stdregs, + uint32_t timeout = 2000); /*! Do a fast register scan using who is there protocol functionality - @param client VSCP client derived from the client vase class over + @param client VSCP client derived from the client over which the communication is carried out. @param guid GUID of the interface to search on. If zero no interface is used. @param found A set with nodeid's for found nodes. @param timeout Timeout in milliseconds. Zero means no timeout */ -int vscp_scanForDevices(CVscpClient& client, - cguid& guid, - std::set &found, - uint32_t timeout = 2000); +int +vscp_scanForDevices(CVscpClient &client, cguid &guid, std::set &found, uint32_t timeout = 2000); /*! - Do a fast register scan using who is there protocol functionality - @param client VSCP client derived from the client vase class over + Do a slow register scan using read register (firts byte of GUID) + @param client VSCP client derived from the client over which the communication is carried out. @param guid GUID of the interface to search on. If zero no interface is used. - @param search_nodes A set that contains all nodes to search - @param found_nodes A set with nodeid's for found nodes. + @param search_nodes A set that contains all nodes to search + @param found_nodes A set with nodeid's for found nodes. @param delay Delay in micro seconds between nodeid's to search. @param timeout Timeout in milliseconds. Zero means no timeout */ -int vscp_scanSlowForDevices(CVscpClient& client, - cguid& guid, - std::set &search_nodes, - std::set &found_nodes, - uint32_t delay = 10000, - uint32_t timeout = 2000); +int +vscp_scanSlowForDevices(CVscpClient &client, + cguid &guid, + std::set &search_nodes, + std::set &found_nodes, + uint32_t delay = 10000, + uint32_t timeout = 2000); /*! - Do a fast register scan using who is there protocol functionality - @param client VSCP client derived from the client vase class over + Do a slow register scan using register read functionality + @param client VSCP client derived from the client over which the communication is carried out. @param guid GUID of the interface to search on. If zero no interface is used. @param start_nodeid Start nodeid to search from. - @param end_nodeid End nodeid to search to. - @param found_nodes A set with nodeid's for found nodes. + @param end_nodeid End nodeid to search to. + @param found_nodes A set with nodeid's for found nodes. @param delay Delay in micro seconds between nodeid's to search. @param timeout Timeout in milliseconds. Zero means no timeout */ -int vscp_scanSlowForDevices(CVscpClient& client, - cguid& guid, - uint8_t start_node, - uint8_t end_node, - std::set &found_nodes, - uint32_t delay = 10000, - uint32_t timeout = 2000); - +int +vscp_scanSlowForDevices(CVscpClient &client, + cguid &guid, + uint8_t start_node, + uint8_t end_node, + std::set &found_nodes, + uint32_t delay = 10000, + uint32_t timeout = 2000); /*! Get device information on HTML format @@ -202,21 +206,19 @@ int vscp_scanSlowForDevices(CVscpClient& client, @param stdregs INitialized standard registers @return HTML formatted device information in a standard string */ -std::string vscp_getDeviceInfoHtml(CMDF& mdf, CStandardRegisters& stdregs); +std::string +vscp_getDeviceInfoHtml(CMDF &mdf, CStandardRegisters &stdregs); /////////////////////////////////////////////////////////////////////////////// - - /*! \class CRegistersPage \brief Encapsulates one page of user registers of a device - This class encapsulates one page of user registers of a device. For a + This class encapsulates one page of user registers of a device. For a level II device this is the page 0x00 (the only page). */ -class CRegisterPage -{ +class CRegisterPage { public: /*! @@ -231,13 +233,13 @@ class CRegisterPage Write level 1 register map to page map @param registers - Registers to write */ - void putLevel1Registers(std::map& registers); + void putLevel1Registers(std::map ®isters); /*! - Get level 1 register map + Get level 1 register map @param registers - Registers to write */ - void getLevel1Registers(std::map& registers); + void getLevel1Registers(std::map ®isters); /*! Read register content on a register page. @@ -285,7 +287,11 @@ class CRegisterPage /*! Clear history */ - void clearHistory() { m_list_undo_value.clear(); m_list_redo_value.clear(); }; + void clearHistory() + { + m_list_undo_value.clear(); + m_list_redo_value.clear(); + }; /*! Get the register changes @@ -323,10 +329,9 @@ class CRegisterPage /*! Get the register map for this page */ - std::map *getRegisterMap(void) { return &m_registers; }; + std::map *getRegisterMap(void) { return &m_registers; }; private: - /*! The level for the device this registerset belongs to. VSCP_LEVEL1 or VSCP_LEVEL2 @@ -339,11 +344,11 @@ class CRegisterPage */ uint16_t m_page; - /*! + /*! Defined registers on the register page [offset, value] - + Level I devices: 0-127 - Level II devices have a single page of registers in the + Level II devices have a single page of registers in the range 0x00000000 - 0xffff0000. */ std::map m_registers; @@ -353,19 +358,19 @@ class CRegisterPage 0 = register 1 = group */ - std::map m_rowType; + std::map m_rowType; /*! This map contains pointers to MDF remote variable objects for registers that define remote variables. */ - std::map m_remoteVariableMap; + std::map m_remoteVariableMap; /*! This map contains pointers to MDF remote variable objects for registers that define remote variables. */ - std::map m_DecsionMatrixMap; + std::map m_DecsionMatrixMap; /*! Here a register position is true for a register that @@ -377,42 +382,36 @@ class CRegisterPage undo/redo queues put: write old value to m_list_undo_value - undo: + undo: current value to m_list_redo_value (if there is undo values) m_list_undo_value to current value (if there is undo values) redo: current value to m_list_undo_value (if there is redo values) - m_list_redo_value to current value (if there is redo values) + m_list_redo_value to current value (if there is redo values) */ // offset, queue with value std::map> m_list_undo_value; std::map> m_list_redo_value; - //std::deque m_list_undo_value; // List with undo values - //std::deque m_list_redo_value; // List with redo values + // std::deque m_list_undo_value; // List with undo values + // std::deque m_list_redo_value; // List with redo values }; - - /////////////////////////////////////////////////////////////////////////////// - - /*! \class CUserRegisters - \brief Encapsulates the user registers (all pages) for a Level I or Level + \brief Encapsulates the user registers (all pages) for a Level I or Level II device */ -class CUserRegisters -{ +class CUserRegisters { public: - - CUserRegisters( uint8_t level = VSCP_LEVEL1 ); + CUserRegisters(uint8_t level = VSCP_LEVEL1); ~CUserRegisters(); - /*! + /*! Read all user register content @param client The communication interface to use @param guidNode GUID for node. Only LSB is used for level I node. @@ -421,11 +420,11 @@ class CUserRegisters @param timeout Timeout in milliseconds. Zero means no timeout @return VSCP_ERROR_SUCCESS on success. */ - int init(CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - std::set& pages, - uint32_t timeout = 1000); + int init(CVscpClient &client, + cguid &guidNode, + cguid &guidInterface, + std::set &pages, + uint32_t timeout = 1000); /*! Set value for register @@ -438,7 +437,7 @@ class CUserRegisters Return a pointer to the register storage map for a page of registers @return A pointer to the register storage map */ - std::map *getRegisterMap( uint16_t page ); + std::map *getRegisterMap(uint16_t page); /*! Get pointer to a user register page @@ -450,7 +449,7 @@ class CUserRegisters /*! Get the register content from a register at a specific page @param offset Register offset on page to read from. - @param page Page to read from. + @param page Page to read from. @return Register content or -1 on failure. */ int getReg(uint32_t offset, uint16_t page = 0); @@ -468,7 +467,7 @@ class CUserRegisters @param state State to set @return true on success. */ - bool setChangedState(uint32_t offset, uint16_t page = 0, bool state = true); + bool setChangedState(uint32_t offset, uint16_t page = 0, bool state = true); /*! Check if a register has an unwritten change @@ -508,18 +507,17 @@ class CUserRegisters @param strValue Abstraction value in string form on return if call successful. @return VSCP_ERROR_SUCCES on success and error code else. */ - int remoteVarFromRegToString( CMDF_RemoteVariable& remoteVar, - std::string& strValue, - uint8_t format = FORMAT_REMOTEVAR_DECIMAL ); + int remoteVarFromRegToString(CMDF_RemoteVariable &remoteVar, + std::string &strValue, + uint8_t format = FORMAT_REMOTEVAR_DECIMAL); /* - * Store abstraction value in string format in corresponding registers. - * @param abstraction Abstraction record from MDF. - * @param strValue Abstraction value in string form. - * @return VSCP_ERROR_SUCCES on success and error code else. - */ - int remoteVarFromStringToReg(CMDF_RemoteVariable& remoteVar, - std::string &strValue); + * Store abstraction value in string format in corresponding registers. + * @param abstraction Abstraction record from MDF. + * @param strValue Abstraction value in string form. + * @return VSCP_ERROR_SUCCES on success and error code else. + */ + int remoteVarFromStringToReg(CMDF_RemoteVariable &remoteVar, std::string &strValue); /*! Get register content for pos in DM row @@ -528,7 +526,7 @@ class CUserRegisters @param pos Position in DM row @return Register content for DM pos or -1 on failure. */ - int vscp_getGetDmRegisterContent(CMDF_DecisionMatrix& dm, uint16_t row, uint8_t pos); + int vscp_getGetDmRegisterContent(CMDF_DecisionMatrix &dm, uint16_t row, uint8_t pos); /*! Read DM row @@ -538,9 +536,9 @@ class CUserRegisters data is fiven by the DM row size. @return VSCP_ERROR_SUCCESS on success or error code on failure. */ - int vscp_readDmRow(CMDF_DecisionMatrix& dm, uint16_t row, uint8_t *buf); + int vscp_readDmRow(CMDF_DecisionMatrix &dm, uint16_t row, uint8_t *buf); - /*! + /*! Write DM row @param dm Decsion matrix @param row DM row to read. @@ -548,50 +546,45 @@ class CUserRegisters size of the data is fiven by the DM row size. @return VSCP_ERROR_SUCCESS on success or error code on failure. */ - int vscp_writeDmRow(CMDF_DecisionMatrix& dm, uint16_t row, uint8_t *buf); + int vscp_writeDmRow(CMDF_DecisionMatrix &dm, uint16_t row, uint8_t *buf); private: + /*! + Tells if this is Level I or Level II registers + */ + uint8_t m_level; - /*! - Tells if this is Level I or Level II registers - */ - uint8_t m_level; - - // set with valid register pages - std::set m_pages; + // set with valid register pages + std::set m_pages; - // pages {page number, defined registers} - std::map m_registerPageMap; - + // pages {page number, defined registers} + std::map m_registerPageMap; }; - - /////////////////////////////////////////////////////////////////////////////// - - struct __struct_standard_register_defs { uint16_t reg; - uint8_t access; // 0 = read only, 1 = read/write, 2 = write only + uint8_t access; // 0 = read only, 1 = read/write, 2 = write only uint32_t bgcolor; std::string name; std::string description; }; #define __GUID_STDREG_DESCRIPTION__ __MDF_STDREG_DESCRIPTION__ -#define __MDF_STDREG_DESCRIPTION__ "Module Description File URL. A zero terminates the ASCII string if not exactly 32 bytes long. The URL points to a file that gives further information about where drivers for different environments are located. Can be returned as a zero string for devices with low memory. For a node with an embedded MDF return a zero string. The CLASS1.PROTOCOL, Type=34/35 can then be used to get the information if available." - +#define __MDF_STDREG_DESCRIPTION__ \ + "Module Description File URL. A zero terminates the ASCII string if not exactly 32 bytes long. The URL points to a " \ + "file that gives further information about where drivers for different environments are located. Can be returned " \ + "as a zero string for devices with low memory. For a node with an embedded MDF return a zero string. The " \ + "CLASS1.PROTOCOL, Type=34/35 can then be used to get the information if available." /*! \class CStandardRegisters \brief Encapsulates the standard registers of a device */ -class CStandardRegisters -{ +class CStandardRegisters { public: - /*! Default Constructor */ @@ -606,96 +599,211 @@ class CStandardRegisters Standard register definitions */ - const __struct_standard_register_defs m_vscp_standard_registers_defs[85] = - { - {0x80,0,0xccffdd,"Alarm status register","Alarm status register content (!= 0 indicates alarm). Condition is reset by a read operation. The bits represent different alarm conditions."}, - {0x81,0,0xffff12,"VSCP specification major version number conformance","VSCP Major version number this device is constructed for."}, - {0x82,0,0xffff12,"VSCP specification minor version number conformance","VSCP Minor version number this device is constructed for."}, - {0x83,0,0xffffd2,"Error counter (was node control flag prior to version 1.6)","VSCP error counter is increased when an error occurs on the device. Reset error counter by reading it."}, - {0x84,1,0xffff12,"User id 0","Client user node-ID byte 0. Use for location info or similar."}, - {0x85,1,0xffff12,"User id 1","Client user node-ID byte 1. Use for location info or similar."}, - {0x86,1,0xffff12,"User id 2","Client user node-ID byte 2. Use for location info or similar."}, - {0x87,1,0xffff12,"User id 3","Client user node-ID byte 3. Use for location info or similar."}, - {0x88,1,0xffff12,"User id 4","Client user node-ID byte 4. Use for location info or similar."}, - {0x89,0,0xffffd2,"Manufacturer device id 0","Manufacturer device ID byte 0. For hardware/firmware/manufacturing info."}, - {0x8A,0,0xffffd2,"Manufacturer device id 1","Manufacturer device ID byte 1. For hardware/firmware/manufacturing info."}, - {0x8B,0,0xffffd2,"Manufacturer device id 2","Manufacturer device ID byte 2. For hardware/firmware/manufacturing info."}, - {0x8C,0,0xffffd2,"Manufacturer device id 3","Manufacturer device ID byte 3. For hardware/firmware/manufacturing info."}, - {0x8D,0,0xffff12,"Manufacturer sub device id 0","Manufacturer sub device ID byte 0. For hardware/firmware/manufacturing info."}, - {0x8E,0,0xffff12,"Manufacturer sub device id 1","Manufacturer sub device ID byte 1. For hardware/firmware/manufacturing info."}, - {0x8F,0,0xffff12,"Manufacturer sub device id 2","Manufacturer sub device ID byte 2. For hardware/firmware/manufacturing info."}, - {0x90,0,0xffff12,"Manufacturer sub device id 3","Manufacturer sub device ID byte 3. For hardware/firmware/manufacturing info."}, - {0x91,0,0xffffd2,"Nickname id","Nickname for the device"}, - {0x92,1,0xffff12,"Page select MSB","MSB byte of current selected register page."}, - {0x93,1,0xffff12,"Page select LSB","LSB byte of current selected register page."}, - {0x94,0,0xffffd2,"Firmware major version number","Major version number for device firmware."}, - {0x95,0,0xffffd2,"Firmware minor version number","Minor version number for device firmware."}, - {0x96,0,0xffffd2,"Firmware build version number","Build version of device firmware."}, - {0x97,0,0xb3d9ff,"Boot loader algorithm","Boot loader algorithm used to bootload this device. Code 0xFF is used for no boot loader support. All defined codes for algorithms are specified here"}, - {0x98,0,0xffffd2,"Buffer size","Buffer size. The value here gives an indication for clients that want to talk to this node if it can support the larger mid level Level I control events which has the full GUID. If set to 0 the default size should used. That is 8 bytes for Level I and 512-25 for Level II."}, - {0x99,0,0xb3d9ff,"Deprecated: Number of register pages used","Number of register pages used. If not implemented one page is assumed. Set to zero if your device have more then 255 pages. Deprecated: Use the MDF instead as the central place for information about actual number of pages."}, - {0x9A,0,0xffff12,"Standard device family code MSB","Standard device family code (MSB) Devices can belong to a common register structure standard. For such devices this describes the family coded as a 32-bit integer. Set all bytes to zero if not used. Also 0xff is reserved and should be interpreted as zero was read. Added in version 1.9.0 of the specification."}, - {0x9B,0,0xffff12,"Standard device family code","Standard device family code Added in version 1.9.0 of the specification."}, - {0x9C,0,0xffff12,"Standard device family code","Standard device family code Added in version 1.9.0 of the specification."}, - {0x9D,0,0xffff12,"Standard device family code LSB","Standard device family code Added in version 1.9.0 of the specification."}, - {0x9E,0,0xffffd2,"Standard device type MSB","Standard device type (MSB) This is part of the code that specifies a device that adopts to a common register standard. This is the type code represented by a 32-bit integer and defines the type belonging to a specific standard. Added in version 1.9.0 of the specification."}, - {0x9F,0,0xffffd2,"Standard device type","Standard device family code. Added in version 1.9.0 of the specification.."}, - {0xA0,0,0xffffd2,"Standard device type","Standard device family code. Added in version 1.9.0 of the specification.."}, - {0xA1,0,0xffffd2,"Standard device type LSB","Standard device family code (LSB). Added in version 1.9.0 of the specification.."}, - {0xA2,2,0xff9999,"Restore factory defaults (Added in version 1.10)}","Standard configuration should be restored for a unit if first 0x55 and then 0xAA is written to this location and is done so withing one second. Added in version 1.10.0 of the specification."}, - {0xA3,0,0xffffd2,"Firmware device code MSB (Added in version 1.13)","Firmware device code MSB. Added in version 1.13.0 of the specification."}, - {0xA4,0,0xffffd2,"Firmware device code LSB (Added in version 1.13)","Firmware device code LSB. Added in version 1.13.0 of the specification."}, - {0xD0,0,0xb3d9ff,"GUID byte 0 MSB",__MDF_STDREG_DESCRIPTION__}, - {0xD1,0,0xb3d9ff,"GUID byte 1",__MDF_STDREG_DESCRIPTION__}, - {0xD2,0,0xb3d9ff,"GUID byte 2",__MDF_STDREG_DESCRIPTION__}, - {0xD3,0,0xb3d9ff,"GUID byte 3",__MDF_STDREG_DESCRIPTION__}, - {0xD4,0,0xb3d9ff,"GUID byte 4",__MDF_STDREG_DESCRIPTION__}, - {0xD5,0,0xb3d9ff,"GUID byte 5",__MDF_STDREG_DESCRIPTION__}, - {0xD6,0,0xb3d9ff,"GUID byte 6",__MDF_STDREG_DESCRIPTION__}, - {0xD7,0,0xb3d9ff,"GUID byte 7",__MDF_STDREG_DESCRIPTION__}, - {0xD8,0,0xb3d9ff,"GUID byte 8",__MDF_STDREG_DESCRIPTION__}, - {0xD9,0,0xb3d9ff,"GUID byte 9",__MDF_STDREG_DESCRIPTION__}, - {0xDA,0,0xb3d9ff,"GUID byte 10",__MDF_STDREG_DESCRIPTION__}, - {0xDB,0,0xb3d9ff,"GUID byte 11",__MDF_STDREG_DESCRIPTION__}, - {0xDC,0,0xb3d9ff,"GUID byte 12",__MDF_STDREG_DESCRIPTION__}, - {0xDD,0,0xb3d9ff,"GUID byte 13",__MDF_STDREG_DESCRIPTION__}, - {0xDE,0,0xb3d9ff,"GUID byte 14",__MDF_STDREG_DESCRIPTION__}, - {0xDF,0,0xb3d9ff,"GUID byte 15 LSB",__MDF_STDREG_DESCRIPTION__}, - {0xE0,0,0xccffdd,"MDF byte 0 MSB",__MDF_STDREG_DESCRIPTION__}, - {0xE1,0,0xccffdd,"MDF byte 1",__MDF_STDREG_DESCRIPTION__}, - {0xE2,0,0xccffdd,"MDF byte 2",__MDF_STDREG_DESCRIPTION__}, - {0xE3,0,0xccffdd,"MDF byte 3",__MDF_STDREG_DESCRIPTION__}, - {0xE4,0,0xccffdd,"MDF byte 4",__MDF_STDREG_DESCRIPTION__}, - {0xE5,0,0xccffdd,"MDF byte 5",__MDF_STDREG_DESCRIPTION__}, - {0xE6,0,0xccffdd,"MDF byte 6",__MDF_STDREG_DESCRIPTION__}, - {0xE7,0,0xccffdd,"MDF byte 7",__MDF_STDREG_DESCRIPTION__}, - {0xE8,0,0xccffdd,"MDF byte 8",__MDF_STDREG_DESCRIPTION__}, - {0xE9,0,0xccffdd,"MDF byte 9",__MDF_STDREG_DESCRIPTION__}, - {0xEA,0,0xccffdd,"MDF byte 10",__MDF_STDREG_DESCRIPTION__}, - {0xEB,0,0xccffdd,"MDF byte 11",__MDF_STDREG_DESCRIPTION__}, - {0xEC,0,0xccffdd,"MDF byte 12",__MDF_STDREG_DESCRIPTION__}, - {0xED,0,0xccffdd,"MDF byte 13",__MDF_STDREG_DESCRIPTION__}, - {0xEE,0,0xccffdd,"MDF byte 14",__MDF_STDREG_DESCRIPTION__}, - {0xEF,0,0xccffdd,"MDF byte 15",__MDF_STDREG_DESCRIPTION__}, - {0xF0,0,0xccffdd,"MDF byte 16",__MDF_STDREG_DESCRIPTION__}, - {0xF1,0,0xccffdd,"MDF byte 17",__MDF_STDREG_DESCRIPTION__}, - {0xF2,0,0xccffdd,"MDF byte 18",__MDF_STDREG_DESCRIPTION__}, - {0xF3,0,0xccffdd,"MDF byte 19",__MDF_STDREG_DESCRIPTION__}, - {0xF4,0,0xccffdd,"MDF byte 20",__MDF_STDREG_DESCRIPTION__}, - {0xF5,0,0xccffdd,"MDF byte 21",__MDF_STDREG_DESCRIPTION__}, - {0xF6,0,0xccffdd,"MDF byte 22",__MDF_STDREG_DESCRIPTION__}, - {0xF7,0,0xccffdd,"MDF byte 23",__MDF_STDREG_DESCRIPTION__}, - {0xF8,0,0xccffdd,"MDF byte 24",__MDF_STDREG_DESCRIPTION__}, - {0xF9,0,0xccffdd,"MDF byte 25",__MDF_STDREG_DESCRIPTION__}, - {0xFA,0,0xccffdd,"MDF byte 26",__MDF_STDREG_DESCRIPTION__}, - {0xFB,0,0xccffdd,"MDF byte 27",__MDF_STDREG_DESCRIPTION__}, - {0xFC,0,0xccffdd,"MDF byte 28",__MDF_STDREG_DESCRIPTION__}, - {0xFD,0,0xccffdd,"MDF byte 29",__MDF_STDREG_DESCRIPTION__}, - {0xFE,0,0xccffdd,"MDF byte 30",__MDF_STDREG_DESCRIPTION__}, - {0xFF,0,0xccffdd,"MDF byte 31 LSB",__MDF_STDREG_DESCRIPTION__} + const __struct_standard_register_defs m_vscp_standard_registers_defs[85] = { + { 0x80, + 0, + 0xccffdd, + "Alarm status register", + "Alarm status register content (!= 0 indicates alarm). Condition is reset by a read operation. The bits " + "represent different alarm conditions." }, + { 0x81, + 0, + 0xffff12, + "VSCP specification major version number conformance", + "VSCP Major version number this device is constructed for." }, + { 0x82, + 0, + 0xffff12, + "VSCP specification minor version number conformance", + "VSCP Minor version number this device is constructed for." }, + { 0x83, + 0, + 0xffffd2, + "Error counter (was node control flag prior to version 1.6)", + "VSCP error counter is increased when an error occurs on the device. Reset error counter by reading it." }, + { 0x84, 1, 0xffff12, "User id 0", "Client user node-ID byte 0. Use for location info or similar." }, + { 0x85, 1, 0xffff12, "User id 1", "Client user node-ID byte 1. Use for location info or similar." }, + { 0x86, 1, 0xffff12, "User id 2", "Client user node-ID byte 2. Use for location info or similar." }, + { 0x87, 1, 0xffff12, "User id 3", "Client user node-ID byte 3. Use for location info or similar." }, + { 0x88, 1, 0xffff12, "User id 4", "Client user node-ID byte 4. Use for location info or similar." }, + { 0x89, + 0, + 0xffffd2, + "Manufacturer device id 0", + "Manufacturer device ID byte 0. For hardware/firmware/manufacturing info." }, + { 0x8A, + 0, + 0xffffd2, + "Manufacturer device id 1", + "Manufacturer device ID byte 1. For hardware/firmware/manufacturing info." }, + { 0x8B, + 0, + 0xffffd2, + "Manufacturer device id 2", + "Manufacturer device ID byte 2. For hardware/firmware/manufacturing info." }, + { 0x8C, + 0, + 0xffffd2, + "Manufacturer device id 3", + "Manufacturer device ID byte 3. For hardware/firmware/manufacturing info." }, + { 0x8D, + 0, + 0xffff12, + "Manufacturer sub device id 0", + "Manufacturer sub device ID byte 0. For hardware/firmware/manufacturing info." }, + { 0x8E, + 0, + 0xffff12, + "Manufacturer sub device id 1", + "Manufacturer sub device ID byte 1. For hardware/firmware/manufacturing info." }, + { 0x8F, + 0, + 0xffff12, + "Manufacturer sub device id 2", + "Manufacturer sub device ID byte 2. For hardware/firmware/manufacturing info." }, + { 0x90, + 0, + 0xffff12, + "Manufacturer sub device id 3", + "Manufacturer sub device ID byte 3. For hardware/firmware/manufacturing info." }, + { 0x91, 0, 0xffffd2, "Nickname id", "Nickname for the device" }, + { 0x92, 1, 0xffff12, "Page select MSB", "MSB byte of current selected register page." }, + { 0x93, 1, 0xffff12, "Page select LSB", "LSB byte of current selected register page." }, + { 0x94, 0, 0xffffd2, "Firmware major version number", "Major version number for device firmware." }, + { 0x95, 0, 0xffffd2, "Firmware minor version number", "Minor version number for device firmware." }, + { 0x96, 0, 0xffffd2, "Firmware build version number", "Build version of device firmware." }, + { 0x97, + 0, + 0xb3d9ff, + "Boot loader algorithm", + "Boot loader algorithm used to bootload this device. Code 0xFF is used for no boot loader support. All defined " + "codes for algorithms are specified here" }, + { 0x98, + 0, + 0xffffd2, + "Buffer size", + "Buffer size. The value here gives an indication for clients that want to talk to this node if it can support " + "the larger mid level Level I control events which has the full GUID. If set to 0 the default size should used. " + "That is 8 bytes for Level I and 512-25 for Level II." }, + { 0x99, + 0, + 0xb3d9ff, + "Deprecated: Number of register pages used", + "Number of register pages used. If not implemented one page is assumed. Set to zero if your device have more " + "then 255 pages. Deprecated: Use the MDF instead as the central place for information about actual number " + "of pages." }, + { 0x9A, + 0, + 0xffff12, + "Standard device family code MSB", + "Standard device family code (MSB) Devices can belong to a common register structure standard. For such devices " + "this describes the family coded as a 32-bit integer. Set all bytes to zero if not used. Also 0xff is reserved " + "and should be interpreted as zero was read. Added in version 1.9.0 of the specification." }, + { 0x9B, + 0, + 0xffff12, + "Standard device family code", + "Standard device family code Added in version 1.9.0 of the specification." }, + { 0x9C, + 0, + 0xffff12, + "Standard device family code", + "Standard device family code Added in version 1.9.0 of the specification." }, + { 0x9D, + 0, + 0xffff12, + "Standard device family code LSB", + "Standard device family code Added in version 1.9.0 of the specification." }, + { 0x9E, + 0, + 0xffffd2, + "Standard device type MSB", + "Standard device type (MSB) This is part of the code that specifies a device that adopts to a common register " + "standard. This is the type code represented by a 32-bit integer and defines the type belonging to a specific " + "standard. Added in version 1.9.0 of the specification." }, + { 0x9F, + 0, + 0xffffd2, + "Standard device type", + "Standard device family code. Added in version 1.9.0 of the specification.." }, + { 0xA0, + 0, + 0xffffd2, + "Standard device type", + "Standard device family code. Added in version 1.9.0 of the specification.." }, + { 0xA1, + 0, + 0xffffd2, + "Standard device type LSB", + "Standard device family code (LSB). Added in version 1.9.0 of the specification.." }, + { 0xA2, + 2, + 0xff9999, + "Restore factory defaults (Added in version 1.10)}", + "Standard configuration should be restored for a unit if first 0x55 and then 0xAA is written to this location " + "and is done so withing one second. Added in version 1.10.0 of the specification." }, + { 0xA3, + 0, + 0xffffd2, + "Firmware device code MSB (Added in version 1.13)", + "Firmware device code MSB. Added in version 1.13.0 of the specification." }, + { 0xA4, + 0, + 0xffffd2, + "Firmware device code LSB (Added in version 1.13)", + "Firmware device code LSB. Added in version 1.13.0 of the specification." }, + { 0xD0, 0, 0xb3d9ff, "GUID byte 0 MSB", __MDF_STDREG_DESCRIPTION__ }, + { 0xD1, 0, 0xb3d9ff, "GUID byte 1", __MDF_STDREG_DESCRIPTION__ }, + { 0xD2, 0, 0xb3d9ff, "GUID byte 2", __MDF_STDREG_DESCRIPTION__ }, + { 0xD3, 0, 0xb3d9ff, "GUID byte 3", __MDF_STDREG_DESCRIPTION__ }, + { 0xD4, 0, 0xb3d9ff, "GUID byte 4", __MDF_STDREG_DESCRIPTION__ }, + { 0xD5, 0, 0xb3d9ff, "GUID byte 5", __MDF_STDREG_DESCRIPTION__ }, + { 0xD6, 0, 0xb3d9ff, "GUID byte 6", __MDF_STDREG_DESCRIPTION__ }, + { 0xD7, 0, 0xb3d9ff, "GUID byte 7", __MDF_STDREG_DESCRIPTION__ }, + { 0xD8, 0, 0xb3d9ff, "GUID byte 8", __MDF_STDREG_DESCRIPTION__ }, + { 0xD9, 0, 0xb3d9ff, "GUID byte 9", __MDF_STDREG_DESCRIPTION__ }, + { 0xDA, 0, 0xb3d9ff, "GUID byte 10", __MDF_STDREG_DESCRIPTION__ }, + { 0xDB, 0, 0xb3d9ff, "GUID byte 11", __MDF_STDREG_DESCRIPTION__ }, + { 0xDC, 0, 0xb3d9ff, "GUID byte 12", __MDF_STDREG_DESCRIPTION__ }, + { 0xDD, 0, 0xb3d9ff, "GUID byte 13", __MDF_STDREG_DESCRIPTION__ }, + { 0xDE, 0, 0xb3d9ff, "GUID byte 14", __MDF_STDREG_DESCRIPTION__ }, + { 0xDF, 0, 0xb3d9ff, "GUID byte 15 LSB", __MDF_STDREG_DESCRIPTION__ }, + { 0xE0, 0, 0xccffdd, "MDF byte 0 MSB", __MDF_STDREG_DESCRIPTION__ }, + { 0xE1, 0, 0xccffdd, "MDF byte 1", __MDF_STDREG_DESCRIPTION__ }, + { 0xE2, 0, 0xccffdd, "MDF byte 2", __MDF_STDREG_DESCRIPTION__ }, + { 0xE3, 0, 0xccffdd, "MDF byte 3", __MDF_STDREG_DESCRIPTION__ }, + { 0xE4, 0, 0xccffdd, "MDF byte 4", __MDF_STDREG_DESCRIPTION__ }, + { 0xE5, 0, 0xccffdd, "MDF byte 5", __MDF_STDREG_DESCRIPTION__ }, + { 0xE6, 0, 0xccffdd, "MDF byte 6", __MDF_STDREG_DESCRIPTION__ }, + { 0xE7, 0, 0xccffdd, "MDF byte 7", __MDF_STDREG_DESCRIPTION__ }, + { 0xE8, 0, 0xccffdd, "MDF byte 8", __MDF_STDREG_DESCRIPTION__ }, + { 0xE9, 0, 0xccffdd, "MDF byte 9", __MDF_STDREG_DESCRIPTION__ }, + { 0xEA, 0, 0xccffdd, "MDF byte 10", __MDF_STDREG_DESCRIPTION__ }, + { 0xEB, 0, 0xccffdd, "MDF byte 11", __MDF_STDREG_DESCRIPTION__ }, + { 0xEC, 0, 0xccffdd, "MDF byte 12", __MDF_STDREG_DESCRIPTION__ }, + { 0xED, 0, 0xccffdd, "MDF byte 13", __MDF_STDREG_DESCRIPTION__ }, + { 0xEE, 0, 0xccffdd, "MDF byte 14", __MDF_STDREG_DESCRIPTION__ }, + { 0xEF, 0, 0xccffdd, "MDF byte 15", __MDF_STDREG_DESCRIPTION__ }, + { 0xF0, 0, 0xccffdd, "MDF byte 16", __MDF_STDREG_DESCRIPTION__ }, + { 0xF1, 0, 0xccffdd, "MDF byte 17", __MDF_STDREG_DESCRIPTION__ }, + { 0xF2, 0, 0xccffdd, "MDF byte 18", __MDF_STDREG_DESCRIPTION__ }, + { 0xF3, 0, 0xccffdd, "MDF byte 19", __MDF_STDREG_DESCRIPTION__ }, + { 0xF4, 0, 0xccffdd, "MDF byte 20", __MDF_STDREG_DESCRIPTION__ }, + { 0xF5, 0, 0xccffdd, "MDF byte 21", __MDF_STDREG_DESCRIPTION__ }, + { 0xF6, 0, 0xccffdd, "MDF byte 22", __MDF_STDREG_DESCRIPTION__ }, + { 0xF7, 0, 0xccffdd, "MDF byte 23", __MDF_STDREG_DESCRIPTION__ }, + { 0xF8, 0, 0xccffdd, "MDF byte 24", __MDF_STDREG_DESCRIPTION__ }, + { 0xF9, 0, 0xccffdd, "MDF byte 25", __MDF_STDREG_DESCRIPTION__ }, + { 0xFA, 0, 0xccffdd, "MDF byte 26", __MDF_STDREG_DESCRIPTION__ }, + { 0xFB, 0, 0xccffdd, "MDF byte 27", __MDF_STDREG_DESCRIPTION__ }, + { 0xFC, 0, 0xccffdd, "MDF byte 28", __MDF_STDREG_DESCRIPTION__ }, + { 0xFD, 0, 0xccffdd, "MDF byte 29", __MDF_STDREG_DESCRIPTION__ }, + { 0xFE, 0, 0xccffdd, "MDF byte 30", __MDF_STDREG_DESCRIPTION__ }, + { 0xFF, 0, 0xccffdd, "MDF byte 31 LSB", __MDF_STDREG_DESCRIPTION__ } }; - /*! + /*! Read all standard register content @param client The communication interface to use @param guidNode GUID for node. Only LSB is used for level I node. @@ -703,17 +811,14 @@ class CStandardRegisters @param timeout Timeout in milliseconds. Zero means no timeout @return VSCP_ERROR_SUCCESS on success. */ - int init(CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint32_t timeout = 1000); + int init(CVscpClient &client, cguid &guidNode, cguid &guidInterface, uint32_t timeout = 1000); /*! Initialization with already read standard registers @param userRegs Reference to already read registers. @return VSCP_ERROR_SUCCESS on success. */ - int init(CRegisterPage& userRegs); + int init(CRegisterPage &userRegs); /*! Get alarm byte @@ -721,7 +826,6 @@ class CStandardRegisters */ uint8_t getAlarm(void) { return m_regs[0x80]; }; - /*! Get VSCP protocol conformance major version @return VSCP protocol conformance major version @@ -746,70 +850,64 @@ class CStandardRegisters @param index Index of user ID to get. @return User ID for pos */ - uint8_t getUserId(uint8_t index) {return m_regs[ 0x84 + index ];}; + uint8_t getUserId(uint8_t index) { return m_regs[0x84 + index]; }; /*! Get user ID @param uid Buffer of five bytes for user id. */ - void getUserId(uint8_t *puid) - { - puid[0] = m_regs[0x84]; - puid[1] = m_regs[0x85]; - puid[2] = m_regs[0x86]; - puid[3] = m_regs[0x87]; - puid[4] = m_regs[0x88]; - }; + void getUserId(uint8_t *puid) + { + puid[0] = m_regs[0x84]; + puid[1] = m_regs[0x85]; + puid[2] = m_regs[0x86]; + puid[3] = m_regs[0x87]; + puid[4] = m_regs[0x88]; + }; /*! Get manufacturer device id @return Manufacturer device id */ uint32_t getManufacturerDeviceID(void) - { return ( ( m_regs[0x89] << 24 ) + - ( m_regs[0x8A] << 16 ) + - ( m_regs[0x8B] << 8 ) + - ( m_regs[0x8C] ) ); }; + { + return ((m_regs[0x89] << 24) + (m_regs[0x8A] << 16) + (m_regs[0x8B] << 8) + (m_regs[0x8C])); + }; /*! Get manufacturer sub device id @return Manufacturer sub device id */ uint32_t getManufacturerSubDeviceID(void) - { return ( ( m_regs[0x8D] << 24 ) + - ( m_regs[0x8E] << 16 ) + - ( m_regs[0x8F] << 8 ) + - ( m_regs[0x90] ) ); }; + { + return ((m_regs[0x8D] << 24) + (m_regs[0x8E] << 16) + (m_regs[0x8F] << 8) + (m_regs[0x90])); + }; /*! Get nickname id @return nickname id */ - uint8_t getNickname(void) {return m_regs[0x91];}; + uint8_t getNickname(void) { return m_regs[0x91]; }; /*! Get register page @return register page */ - uint16_t getRegisterPage(void) { return ( m_regs[0x92] * 256 + - m_regs[0x93] ); }; + uint16_t getRegisterPage(void) { return (m_regs[0x92] * 256 + m_regs[0x93]); }; /*! Get firmware major version */ - uint8_t getFirmwareMajorVersion(void) - {return m_regs[0x94];}; + uint8_t getFirmwareMajorVersion(void) { return m_regs[0x94]; }; /*! Get firmware minor version */ - uint8_t getFirmwareMinorVersion(void) - {return m_regs[0x95];}; + uint8_t getFirmwareMinorVersion(void) { return m_regs[0x95]; }; /*! Get firmware sub minor version */ - uint8_t getFirmwareSubMinorVersion(void) - {return m_regs[0x96];}; + uint8_t getFirmwareSubMinorVersion(void) { return m_regs[0x96]; }; /*! Get firmware version as string @@ -820,62 +918,53 @@ class CStandardRegisters Get bootloader algorithm @return bootloader algorithm */ - uint8_t getBootloaderAlgorithm(void) - {return m_regs[0x97];}; + uint8_t getBootloaderAlgorithm(void) { return m_regs[0x97]; }; - /*! + /*! Get buffer size @return buffer size */ - uint8_t getBufferSize(void) {return m_regs[0x98];}; + uint8_t getBufferSize(void) { return m_regs[0x98]; }; /*! Get number of register pages !!!DEPRECATED!!! @return number of register pages */ - uint8_t getNumberOfRegisterPages(void) {return m_regs[0x99]; }; + uint8_t getNumberOfRegisterPages(void) { return m_regs[0x99]; }; /*! Get standard family code (added in spec 1.9) @return Standard family code as 32-bit unsigned integer. */ - uint32_t getStandardDeviceFamilyCode(void) - { return ( ( m_regs[0x9A] << 24 ) + - ( m_regs[0x9B] << 16 ) + - ( m_regs[0x9C] << 8 ) + - ( m_regs[0x9D] ) ); }; + uint32_t getStandardDeviceFamilyCode(void) + { + return ((m_regs[0x9A] << 24) + (m_regs[0x9B] << 16) + (m_regs[0x9C] << 8) + (m_regs[0x9D])); + }; /*! Get standard family type (added in spec 1.9) @return Standard family type as 32-bit unsigned integer. */ - uint32_t getStandardDeviceFamilyType(void) - { return ( ( m_regs[0x9E] << 24 ) + - ( m_regs[0x9F] << 16 ) + - ( m_regs[0xA0] << 8 ) + - ( m_regs[0xA1] ) ); }; + uint32_t getStandardDeviceFamilyType(void) + { + return ((m_regs[0x9E] << 24) + (m_regs[0x9F] << 16) + (m_regs[0xA0] << 8) + (m_regs[0xA1])); + }; /*! Restore standard configuration for node */ - int restoreStandardConfig(CVscpClient& client, - cguid& guidNode, - cguid& guidInterface, - uint32_t timeout = 1000); + int restoreStandardConfig(CVscpClient &client, cguid &guidNode, cguid &guidInterface, uint32_t timeout = 1000); /*! Get firmare device code (added in 1.13) @return Firmware device code as 16-bit unsigned integer */ - uint16_t getFirmwareDeviceCode(void) - { return ( (m_regs[0xA3] << 8 ) + - (m_regs[0xA4] ) ); }; - + uint16_t getFirmwareDeviceCode(void) { return ((m_regs[0xA3] << 8) + (m_regs[0xA4])); }; + /*! Get guid as GUID class */ - void getGUID(cguid& guid); - + void getGUID(cguid &guid); /*! Get MDF URL @@ -883,7 +972,6 @@ class CStandardRegisters */ std::string getMDF(void); - /*! Get a standard register value from offset @param reg Offset of standard register to read @@ -930,8 +1018,7 @@ class CStandardRegisters bool hasChanges(void); private: - - /// LEVEL1 or LEVEL2 + /// LEVEL1 or LEVEL2 uint8_t m_level; /// Standard register storage @@ -944,16 +1031,13 @@ class CStandardRegisters std::map m_change; }; - /////////////////////////////////////////////////////////////////////////////// - /*! Class that describes a full node of a VSCP device */ -class CVscpNode -{ +class CVscpNode { public: CVscpNode(void); @@ -963,16 +1047,15 @@ class CVscpNode Get pointer to user register object @return Pointer to user register object */ - CUserRegisters *getUserRegs(void) {return &m_reg;}; + CUserRegisters *getUserRegs(void) { return &m_reg; }; /*! Get pointer to standard register object @return Pointer to standard register object */ - CStandardRegisters *getStandardRegs( void ) {return &m_stdReg;}; + CStandardRegisters *getStandardRegs(void) { return &m_stdReg; }; private: - /*! Holds the user registers of the device */ @@ -982,7 +1065,6 @@ class CVscpNode Holds the standard registers of the device */ CStandardRegisters m_stdReg; - }; #endif diff --git a/src/vscp/common/vscp_client_base.cpp b/src/vscp/common/vscp_client_base.cpp index 2fe6b155f..5a84d2534 100644 --- a/src/vscp/common/vscp_client_base.cpp +++ b/src/vscp/common/vscp_client_base.cpp @@ -9,8 +9,8 @@ // // This file is part of the VSCP (https://www.vscp.org) // -// Copyright: (C)2007-2022 -// Ake Hedman, the VSCP project, +// Copyright © 2000-2024 Ake Hedman, Grodans Paradis AB +// // // This file is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/src/vscp/common/vscp_client_base.h b/src/vscp/common/vscp_client_base.h index eb0d1e28e..ef93706da 100644 --- a/src/vscp/common/vscp_client_base.h +++ b/src/vscp/common/vscp_client_base.h @@ -9,8 +9,8 @@ // // This file is part of the VSCP (https://www.vscp.org) // -// Copyright: (C) 2007-2023 -// Ake Hedman, the VSCP project, +// Copyright © 2000-2024 Ake Hedman, Grodans Paradis AB +// // // This file is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,7 +26,7 @@ #if !defined(VSCPCLIENTBASE_H__INCLUDED_) #define VSCPCLIENTBASE_H__INCLUDED_ -#include "vscp.h" +#include "vscp.h" #include // nlohmann @@ -42,247 +42,240 @@ using json = nlohmann::json; // as it wants. #ifdef WIN32 -typedef void ( __stdcall * LPFNDLL_EV_CALLBACK) ( vscpEvent *pev, void *pobj ); // Event callback -typedef void ( __stdcall * LPFNDLL_EX_CALLBACK) ( vscpEventEx *pex, void *pobj ); // Event ex callbac +typedef void(__stdcall *LPFNDLL_EV_CALLBACK)(vscpEvent *pev, void *pobj); // Event callback +typedef void(__stdcall *LPFNDLL_EX_CALLBACK)(vscpEventEx *pex, void *pobj); // Event ex callbac #else -typedef void ( *LPFNDLL_EV_CALLBACK ) ( vscpEvent *pev, void *pobj ); // Event callback -typedef void ( *LPFNDLL_EX_CALLBACK ) ( vscpEventEx *pex, void *pobj ); // Event ex callback +typedef void (*LPFNDLL_EV_CALLBACK)(vscpEvent *pev, void *pobj); // Event callback +typedef void (*LPFNDLL_EX_CALLBACK)(vscpEventEx *pex, void *pobj); // Event ex callback #endif -class CVscpClient -{ +class CVscpClient { public: + CVscpClient(); + ~CVscpClient(); + + /*! + vscp-client class types + ======================= + - NONE - Undefined + - LOCAL - No connection, can handle files, logs etc + - TCPIP - VSCP tcp/ip link protocol. + - CANAL - The CANAL protocol. This is the same as a VSCP level I driver. + - SOCKETCAN - VSCP events sent ovr socketcan. + - WS1 - VSCP websocket ws1 protocol. + - WS2 - VSCP websocket ws2 protocol. + - MQTT - VSCP over MQTT. + - UDP - VSCP over UDP. + - MULTICAST - VSCP multicast protocol. + - REST - VSCP REST interface. + - RS232 - VSCP over serial link. + - RS485 - VSCP over multidrop serial link. + - RAWCAN - Handle standard CAN and CANFD. + - RAWMQTT - Handle standard MQTT. + */ + + typedef enum class connType { + NONE = 0, + LOCAL, + TCPIP, + CANAL, + LEVEL2, + SOCKETCAN, + WS1, + WS2, + MQTT, + UDP, + MULTICAST, + REST, + RS232, + RS485, + RAWCAN, + RAWMQTT + } connType; + + /*! + Connect to remote host + @param bPoll If true polling is used. + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int connect(void) = 0; + + /*! + Disconnect from remote host + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int disconnect(void) = 0; + + /*! + Check if connected. + @return true if connected, false otherwise. + */ + virtual bool isConnected(void) = 0; + + /*! + Send VSCP event to remote host. + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int send(vscpEvent &ev) = 0; + + /*! + Send VSCP event to remote host. + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int send(vscpEventEx &ex) = 0; + + /*! + Receive VSCP event from remote host + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int receive(vscpEvent &ev) = 0; + + /*! + Receive VSCP event ex from remote host + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int receive(vscpEventEx &ex) = 0; + + /*! + Set interface filter + @param filter VSCP Filter to set. + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int setfilter(vscpEventFilter &filter) = 0; + + /*! + Get number of events waiting to be received on remote + interface + @param pcount Pointer to an unsigned integer that get the count of events. + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int getcount(uint16_t *pcount) = 0; + + /*! + Clear the input queue + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int clear(void) = 0; + + /*! + Get version from interface + @param pmajor Pointer to uint8_t that get major version of interface. + @param pminor Pointer to uint8_t that get minor version of interface. + @param prelease Pointer to uint8_t that get release version of interface. + @param pbuild Pointer to uint8_t that get build version of interface. + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int getversion(uint8_t *pmajor, uint8_t *pminor, uint8_t *prelease, uint8_t *pbuild) = 0; + + /*! + Get interfaces + @param iflist Get a list of available interfaces + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int getinterfaces(std::deque &iflist) = 0; + + /*! + Get capabilities (wcyd) from remote interface + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int getwcyd(uint64_t &wcyd) = 0; + + /*! + Set (and enable) receive callback for events + @param LPFNDLL_EX_CALLBACK Callback to call when an event is received + @param pData User defined data to pass in callback call + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int setCallback(LPFNDLL_EV_CALLBACK evcallback, void *pData = nullptr); + + /*! + Set (and enable) receive callback ex events + @param LPFNDLL_EX_CALLBACK Callback to call when an event is received + @param pData User defined data to pass in callback call + @return Return VSCP_ERROR_SUCCESS of OK and error code else. + */ + virtual int setCallback(LPFNDLL_EX_CALLBACK excallback, void *pData = nullptr); + + /*! + Getter/setters for connection timeout + Time is in milliseconds + */ + virtual void setConnectionTimeout(uint32_t timeout) = 0; + virtual uint32_t getConnectionTimeout(void) = 0; + + /*! + Getter/setters for response timeout + Time is in milliseconds + */ + virtual void setResponseTimeout(uint32_t timeout) = 0; + virtual uint32_t getResponseTimeout(void) = 0; + + /*! + Check if ev callback is defined + @return true if callback is defined + */ + bool isEvCallback(void) { return (nullptr != m_evcallback); } + + /*! + Check if ex callback is defined + @return true if callback is defined + */ + bool isExCallback(void) { return (nullptr != m_excallback); } + + /*! + Return a JSON representation of connection + @return JSON representation as string + */ + virtual std::string getConfigAsJson(void) = 0; + + /*! + Set member variables from JSON representation of connection + @param config JSON representation as string + @return True on success, false on failure. + */ + virtual bool initFromJson(const std::string &config) = 0; + + // ------------------------------------------------------------------------ + + /*! + Get connection type + @return Type for the connection + */ + connType getType(void) { return m_type; }; + + /*! + Set name for communication object + */ + virtual void setName(const std::string &name) { m_name = name; }; + + /*! + Get name for communication object + */ + virtual std::string getName(void) { return m_name; }; - CVscpClient(); - ~CVscpClient(); - -/*! - vscp-client class types - ======================= - - NONE - Undefined - - LOCAL - No connection, can handle files, logs etc - - TCPIP - VSCP tcp/ip link protocol. - - CANAL - The CANAL protocol. This is the same as a VSCP level I driver. - - SOCKETCAN - VSCP events sent ovr socketcan. - - WS1 - VSCP websocket ws1 protocol. - - WS2 - VSCP websocket ws2 protocol. - - MQTT - VSCP over MQTT. - - UDP - VSCP over UDP. - - MULTICAST - VSCP multicast protocol. - - REST - VSCP REST interface. - - RS232 - VSCP over serial link. - - RS485 - VSCP over multidrop serial link. - - RAWCAN - Handle standard CAN and CANFD. - - RAWMQTT - Handle standard MQTT. -*/ - - typedef enum class connType { - NONE=0, - LOCAL, - TCPIP, - CANAL, - LEVEL2, - SOCKETCAN, - WS1, - WS2, - MQTT, - UDP, - MULTICAST, - REST, - RS232, - RS485, - RAWCAN, - RAWMQTT - } connType; - - /*! - Connect to remote host - @param bPoll If true polling is used. - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int connect(void) = 0; - - /*! - Disconnect from remote host - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int disconnect(void) = 0; - - /*! - Check if connected. - @return true if connected, false otherwise. - */ - virtual bool isConnected(void) = 0; - - /*! - Send VSCP event to remote host. - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int send(vscpEvent &ev) = 0; - - /*! - Send VSCP event to remote host. - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int send(vscpEventEx &ex) = 0; - - /*! - Receive VSCP event from remote host - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int receive(vscpEvent &ev) = 0; - - /*! - Receive VSCP event ex from remote host - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int receive(vscpEventEx &ex) = 0; - - /*! - Set interface filter - @param filter VSCP Filter to set. - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int setfilter(vscpEventFilter &filter) = 0; - - - /*! - Get number of events waiting to be received on remote - interface - @param pcount Pointer to an unsigned integer that get the count of events. - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int getcount(uint16_t *pcount) = 0; - - /*! - Clear the input queue - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int clear(void) = 0; - - /*! - Get version from interface - @param pmajor Pointer to uint8_t that get major version of interface. - @param pminor Pointer to uint8_t that get minor version of interface. - @param prelease Pointer to uint8_t that get release version of interface. - @param pbuild Pointer to uint8_t that get build version of interface. - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int getversion(uint8_t *pmajor, - uint8_t *pminor, - uint8_t *prelease, - uint8_t *pbuild) = 0; - - /*! - Get interfaces - @param iflist Get a list of available interfaces - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int getinterfaces(std::deque &iflist) = 0; - - /*! - Get capabilities (wcyd) from remote interface - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int getwcyd(uint64_t &wcyd) = 0; - - /*! - Set (and enable) receive callback for events - @param LPFNDLL_EX_CALLBACK Callback to call when an event is received - @param pData User defined data to pass in callback call - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int setCallback(LPFNDLL_EV_CALLBACK evcallback, void *pData=nullptr); - - /*! - Set (and enable) receive callback ex events - @param LPFNDLL_EX_CALLBACK Callback to call when an event is received - @param pData User defined data to pass in callback call - @return Return VSCP_ERROR_SUCCESS of OK and error code else. - */ - virtual int setCallback(LPFNDLL_EX_CALLBACK excallback, void *pData=nullptr); - - /*! - Getter/setters for connection timeout - Time is in milliseconds - */ - virtual void setConnectionTimeout(uint32_t timeout) = 0; - virtual uint32_t getConnectionTimeout(void) = 0; - - /*! - Getter/setters for response timeout - Time is in milliseconds - */ - virtual void setResponseTimeout(uint32_t timeout) = 0; - virtual uint32_t getResponseTimeout(void) = 0; - - /*! - Check if ev callback is defined - @return true if callback is defined - */ - bool isEvCallback(void) {return (nullptr != m_evcallback); } - - /*! - Check if ex callback is defined - @return true if callback is defined - */ - bool isExCallback(void) {return (nullptr != m_excallback); } - - /*! - Return a JSON representation of connection - @return JSON representation as string - */ - virtual std::string getConfigAsJson(void) = 0; - - /*! - Set member variables from JSON representation of connection - @param config JSON representation as string - @return True on success, false on failure. - */ - virtual bool initFromJson(const std::string& config) = 0; - - // ------------------------------------------------------------------------ - - /*! - Get connection type - @return Type for the connection - */ - connType getType(void) {return m_type; }; - - /*! - Set name for communication object - */ - virtual void setName(const std::string& name) { m_name = name; }; - - /*! - Get name for communication object - */ - virtual std::string getName(void) { return m_name; }; - - public: - - /*! - Callback for events - */ - LPFNDLL_EV_CALLBACK m_evcallback; - - /*! - Callback for ex events - */ - LPFNDLL_EX_CALLBACK m_excallback; - - /*! - This data pointer is set by the callback - setter and is sent with the callback call - */ - void *m_callbackObject; - - // Type of connection object - connType m_type = CVscpClient::connType::NONE; - - // Name for connection object - std::string m_name; +public: + /*! + Callback for events + */ + LPFNDLL_EV_CALLBACK m_evcallback; + + /*! + Callback for ex events + */ + LPFNDLL_EX_CALLBACK m_excallback; + + /*! + This data pointer is set by the callback + setter and is sent with the callback call + */ + void *m_callbackObject; + + // Type of connection object + connType m_type = CVscpClient::connType::NONE; + + // Name for connection object + std::string m_name; }; #endif diff --git a/src/vscp/common/vscp_client_socketcan.cpp b/src/vscp/common/vscp_client_socketcan.cpp index 297ea8d4b..923c5160b 100644 --- a/src/vscp/common/vscp_client_socketcan.cpp +++ b/src/vscp/common/vscp_client_socketcan.cpp @@ -9,8 +9,8 @@ // // This file is part of the VSCP (https://www.vscp.org) // -// Copyright: (C) 2007-2023 -// Ake Hedman, the VSCP project, +// Copyright © 2000-2024 Ake Hedman, Grodans Paradis AB +// // // This file is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,42 +26,40 @@ // !!! Only Linux !!! #ifndef WIN32 -#include -#include -#include -#include +#include +#include +#include #include +#include +#include +#include #include #include -#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include #include +#include #include -#include -#include +#include #include +#include #include #include -#include #include #include +#include "vscp_client_socketcan.h" +#include #include #include #include #include -#include -#include "vscp_client_socketcan.h" #include #include @@ -69,8 +67,8 @@ #include #include -#include // Needs C++11 -std=c++11 #include +#include // Needs C++11 -std=c++11 #include #include @@ -82,152 +80,151 @@ using json = nlohmann::json; using namespace kainjow::mustache; // Forward declaration -static void *workerThread(void *pObj); +static void * +workerThread(void *pObj); -// CAN DLC to real data length conversion helpers -static const unsigned char canal_tbldlc2len[] = { - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 12, 16, 20, 24, 32, 48, 64 }; +// CAN DLC to real data length conversion helpers +static const unsigned char canal_tbldlc2len[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 }; -// get data length from can_dlc with sanitized can_dlc -unsigned char canal_dlc2len(unsigned char can_dlc) +// get data length from can_dlc with sanitized can_dlc +unsigned char +canal_dlc2len(unsigned char can_dlc) { - return canal_tbldlc2len[can_dlc & 0x0F]; + return canal_tbldlc2len[can_dlc & 0x0F]; } -static const unsigned char canal_tbllen2dlc[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */ - 9, 9, 9, 9, /* 9 - 12 */ - 10, 10, 10, 10, /* 13 - 16 */ - 11, 11, 11, 11, /* 17 - 20 */ - 12, 12, 12, 12, /* 21 - 24 */ - 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */ - 14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */ - 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */ - 15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */ - 15, 15, 15, 15, 15, 15, 15, 15 }; /* 57 - 64 */ - -// map the sanitized data length to an appropriate data length code -unsigned char canal_len2dlc(unsigned char len) +static const unsigned char canal_tbllen2dlc[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */ + 9, 9, 9, 9, /* 9 - 12 */ + 10, 10, 10, 10, /* 13 - 16 */ + 11, 11, 11, 11, /* 17 - 20 */ + 12, 12, 12, 12, /* 21 - 24 */ + 13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* 49 - 56 */ + 15, 15, 15, 15, 15, 15, 15, 15 }; /* 57 - 64 */ + +// map the sanitized data length to an appropriate data length code +unsigned char +canal_len2dlc(unsigned char len) { - if (len > 64) { - return 0xF; + if (len > 64) { + return 0xF; } - return canal_tbllen2dlc[len]; + return canal_tbllen2dlc[len]; } /////////////////////////////////////////////////////////////////////////////// // C-tor // -vscpClientSocketCan::vscpClientSocketCan() +vscpClientSocketCan::vscpClientSocketCan() { - m_type = CVscpClient::connType::SOCKETCAN; - m_bDebug = false; - m_bConnected = false; // Not connected - m_threadWork = 0; - m_bRun = true; - m_interface = "vcan0"; - m_guid.getFromString("00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"); - m_flags = 0; - m_socket = -1; - m_mode = CAN_MTU; - - setResponseTimeout(3); // Response timeout 3 ms - pthread_mutex_init(&m_mutexSocket, NULL); - - vscp_clearVSCPFilter(&m_filterIn); // Accept all events - vscp_clearVSCPFilter(&m_filterOut); // Send all events - - sem_init(&m_semSendQueue, 0, 0); - sem_init(&m_semReceiveQueue, 0, 0); - - pthread_mutex_init(&m_mutexSendQueue, NULL); - pthread_mutex_init(&m_mutexReceiveQueue, NULL); - - /* - // Init pool - spdlog::init_thread_pool(8192, 1); - - // Flush log every five seconds - spdlog::flush_every(std::chrono::seconds(5)); - - auto console = spdlog::stdout_color_mt("console"); - // Start out with level=info. Config may change this - console->set_level(spdlog::level::debug); - console->set_pattern("[vscp-client-socketcan] [%^%l%$] %v"); - spdlog::set_default_logger(console); - - console->debug("Starting the vscp-client-socketcan..."); - - m_bConsoleLogEnable = true; - m_consoleLogLevel = spdlog::level::info; - m_consoleLogPattern = "[vscp-client-socketcan %c] [%^%l%$] %v"; - - m_bEnableFileLog = true; - m_fileLogLevel = spdlog::level::info; - m_fileLogPattern = "[vscp-client-socketcan %c] [%^%l%$] %v"; - m_path_to_log_file = "/var/log/vscp/vscp-client-socketcan.log"; - m_max_log_size = 5242880; - m_max_log_files = 7; -*/ + m_type = CVscpClient::connType::SOCKETCAN; + m_bDebug = false; + m_bConnected = false; // Not connected + m_threadWork = 0; + m_bRun = true; + m_interface = "vcan0"; + m_guid.getFromString("00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"); + m_flags = 0; + m_socket = -1; + m_mode = CAN_MTU; + + setResponseTimeout(3); // Response timeout 3 ms + pthread_mutex_init(&m_mutexSocket, NULL); + + vscp_clearVSCPFilter(&m_filterIn); // Accept all events + vscp_clearVSCPFilter(&m_filterOut); // Send all events + + sem_init(&m_semSendQueue, 0, 0); + sem_init(&m_semReceiveQueue, 0, 0); + + pthread_mutex_init(&m_mutexSendQueue, NULL); + pthread_mutex_init(&m_mutexReceiveQueue, NULL); + + /* + // Init pool + spdlog::init_thread_pool(8192, 1); + + // Flush log every five seconds + spdlog::flush_every(std::chrono::seconds(5)); + + auto console = spdlog::stdout_color_mt("console"); + // Start out with level=info. Config may change this + console->set_level(spdlog::level::debug); + console->set_pattern("[vscp-client-socketcan] [%^%l%$] %v"); + spdlog::set_default_logger(console); + + console->debug("Starting the vscp-client-socketcan..."); + + m_bConsoleLogEnable = true; + m_consoleLogLevel = spdlog::level::info; + m_consoleLogPattern = "[vscp-client-socketcan %c] [%^%l%$] %v"; + + m_bEnableFileLog = true; + m_fileLogLevel = spdlog::level::info; + m_fileLogPattern = "[vscp-client-socketcan %c] [%^%l%$] %v"; + m_path_to_log_file = "/var/log/vscp/vscp-client-socketcan.log"; + m_max_log_size = 5242880; + m_max_log_files = 7; + */ } /////////////////////////////////////////////////////////////////////////////// // D-tor // -vscpClientSocketCan::~vscpClientSocketCan() +vscpClientSocketCan::~vscpClientSocketCan() { - disconnect(); - pthread_mutex_destroy(&m_mutexSocket); + disconnect(); + pthread_mutex_destroy(&m_mutexSocket); - sem_destroy(&m_semSendQueue); - sem_destroy(&m_semReceiveQueue); + sem_destroy(&m_semSendQueue); + sem_destroy(&m_semReceiveQueue); - pthread_mutex_destroy(&m_mutexSendQueue); - pthread_mutex_destroy(&m_mutexReceiveQueue); + pthread_mutex_destroy(&m_mutexSendQueue); + pthread_mutex_destroy(&m_mutexReceiveQueue); } /////////////////////////////////////////////////////////////////////////////// // init // -int vscpClientSocketCan::init(const std::string &interface, - const std::string &guid, - unsigned long flags, - uint32_t timeout) +int +vscpClientSocketCan::init(const std::string &interface, const std::string &guid, unsigned long flags, uint32_t timeout) { - m_interface = interface; - m_guid.getFromString(guid); - m_flags = flags; - setResponseTimeout(DEAULT_RESPONSE_TIMEOUT); // Response timeout 3 ms - return VSCP_ERROR_SUCCESS; + m_interface = interface; + m_guid.getFromString(guid); + m_flags = flags; + setResponseTimeout(DEAULT_RESPONSE_TIMEOUT); // Response timeout 3 ms + return VSCP_ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// // getConfigAsJson // -std::string vscpClientSocketCan::getConfigAsJson(void) +std::string +vscpClientSocketCan::getConfigAsJson(void) { - json j; - std::string rv; - - j["interface"] = m_interface; - j["flags"] = m_flags; - j["response-timeout"] = getResponseTimeout(); + json j; + std::string rv; - return rv; -} + j["interface"] = m_interface; + j["flags"] = m_flags; + j["response-timeout"] = getResponseTimeout(); + return rv; +} /////////////////////////////////////////////////////////////////////////////// // initFromJson // -bool vscpClientSocketCan::initFromJson(const std::string& config) +bool +vscpClientSocketCan::initFromJson(const std::string &config) { json j; @@ -252,264 +249,264 @@ bool vscpClientSocketCan::initFromJson(const std::string& config) uint32_t val = m_j_config["response-timeout"].get(); setResponseTimeout(val); spdlog::debug("json socket init: Response Timeout set to {}.", val); - } -/* - // Logging - if (m_j_config.contains("logging") && m_j_config["logging"].is_object()) { + /* + // Logging + if (m_j_config.contains("logging") && m_j_config["logging"].is_object()) { - json j = m_j_config["logging"]; + json j = m_j_config["logging"]; - // * * * CONSOLE * * * + // * * * CONSOLE * * * - // Logging: console-log-enable - if (j.contains("console-enable")) { - try { - m_bConsoleLogEnable = j["console-enable"].get(); - } - catch (const std::exception &ex) { - spdlog::error("Failed to read 'console-enable' Error='{}'", ex.what()); - } - catch (...) { - spdlog::error("Failed to read 'console-enable' due to unknown error."); - } - } - else { - spdlog::debug("Failed to read LOGGING 'console-enable' Defaults will be used."); - } + // Logging: console-log-enable + if (j.contains("console-enable")) { + try { + m_bConsoleLogEnable = j["console-enable"].get(); + } + catch (const std::exception &ex) { + spdlog::error("Failed to read 'console-enable' Error='{}'", ex.what()); + } + catch (...) { + spdlog::error("Failed to read 'console-enable' due to unknown error."); + } + } + else { + spdlog::debug("Failed to read LOGGING 'console-enable' Defaults will be used."); + } - // Logging: console-log-level - if (j.contains("console-level")) { - std::string str; - try { - str = j["console-level"].get(); - } - catch (const std::exception &ex) { - spdlog::error("Failed to read 'console-level' Error='{}'", ex.what()); - } - catch (...) { - spdlog::error("Failed to read 'console-level' due to unknown error."); - } - vscp_makeLower(str); - if (std::string::npos != str.find("off")) { - m_consoleLogLevel = spdlog::level::off; - } - else if (std::string::npos != str.find("critical")) { - m_consoleLogLevel = spdlog::level::critical; - } - else if (std::string::npos != str.find("err")) { - m_consoleLogLevel = spdlog::level::err; - } - else if (std::string::npos != str.find("warn")) { - m_consoleLogLevel = spdlog::level::warn; - } - else if (std::string::npos != str.find("info")) { - m_consoleLogLevel = spdlog::level::info; - } - else if (std::string::npos != str.find("debug")) { - m_consoleLogLevel = spdlog::level::debug; - } - else if (std::string::npos != str.find("trace")) { - m_consoleLogLevel = spdlog::level::trace; - } - else { - spdlog::error("Failed to read LOGGING 'console-level' has invalid " - "value [{}]. Default value used.", - str); - } - } - else { - spdlog::error("Failed to read LOGGING 'console-level' Defaults will be used."); - } + // Logging: console-log-level + if (j.contains("console-level")) { + std::string str; + try { + str = j["console-level"].get(); + } + catch (const std::exception &ex) { + spdlog::error("Failed to read 'console-level' Error='{}'", ex.what()); + } + catch (...) { + spdlog::error("Failed to read 'console-level' due to unknown error."); + } + vscp_makeLower(str); + if (std::string::npos != str.find("off")) { + m_consoleLogLevel = spdlog::level::off; + } + else if (std::string::npos != str.find("critical")) { + m_consoleLogLevel = spdlog::level::critical; + } + else if (std::string::npos != str.find("err")) { + m_consoleLogLevel = spdlog::level::err; + } + else if (std::string::npos != str.find("warn")) { + m_consoleLogLevel = spdlog::level::warn; + } + else if (std::string::npos != str.find("info")) { + m_consoleLogLevel = spdlog::level::info; + } + else if (std::string::npos != str.find("debug")) { + m_consoleLogLevel = spdlog::level::debug; + } + else if (std::string::npos != str.find("trace")) { + m_consoleLogLevel = spdlog::level::trace; + } + else { + spdlog::error("Failed to read LOGGING 'console-level' has invalid " + "value [{}]. Default value used.", + str); + } + } + else { + spdlog::error("Failed to read LOGGING 'console-level' Defaults will be used."); + } - // Logging: console-log-pattern - if (j.contains("console-pattern")) { - try { - m_consoleLogPattern = j["console-pattern"].get(); - } - catch (const std::exception &ex) { - spdlog::error("Failed to read 'console-pattern' Error='{}'", ex.what()); - } - catch (...) { - spdlog::error("Failed to read 'console-pattern' due to unknown error."); - } - } - else { - spdlog::debug("Failed to read LOGGING 'console-pattern' Defaults will be used."); - } + // Logging: console-log-pattern + if (j.contains("console-pattern")) { + try { + m_consoleLogPattern = j["console-pattern"].get(); + } + catch (const std::exception &ex) { + spdlog::error("Failed to read 'console-pattern' Error='{}'", ex.what()); + } + catch (...) { + spdlog::error("Failed to read 'console-pattern' due to unknown error."); + } + } + else { + spdlog::debug("Failed to read LOGGING 'console-pattern' Defaults will be used."); + } - // * * * FILE * * * + // * * * FILE * * * - // Logging: file-log-enable - if (j.contains("file-enable")) { - try { - m_bEnableFileLog = j["file-enable"].get(); - } - catch (const std::exception &ex) { - spdlog::error("Failed to read 'file-enable' Error='{}'", ex.what()); - } - catch (...) { - spdlog::error("Failed to read 'file-enable' due to unknown error."); - } - } - else { - spdlog::debug("Failed to read LOGGING 'file-enable' Defaults will be used."); - } + // Logging: file-log-enable + if (j.contains("file-enable")) { + try { + m_bEnableFileLog = j["file-enable"].get(); + } + catch (const std::exception &ex) { + spdlog::error("Failed to read 'file-enable' Error='{}'", ex.what()); + } + catch (...) { + spdlog::error("Failed to read 'file-enable' due to unknown error."); + } + } + else { + spdlog::debug("Failed to read LOGGING 'file-enable' Defaults will be used."); + } - // Logging: file-log-level - if (j.contains("file-log-level")) { - std::string str; - try { - str = j["file-log-level"].get(); - } - catch (const std::exception &ex) { - spdlog::error("Failed to read 'file-log-level' Error='{}'", ex.what()); - } - catch (...) { - spdlog::error("Failed to read 'file-log-level' due to unknown error."); - } - vscp_makeLower(str); - if (std::string::npos != str.find("off")) { - m_fileLogLevel = spdlog::level::off; - } - else if (std::string::npos != str.find("critical")) { - m_fileLogLevel = spdlog::level::critical; - } - else if (std::string::npos != str.find("err")) { - m_fileLogLevel = spdlog::level::err; - } - else if (std::string::npos != str.find("warn")) { - m_fileLogLevel = spdlog::level::warn; - } - else if (std::string::npos != str.find("info")) { - m_fileLogLevel = spdlog::level::info; - } - else if (std::string::npos != str.find("debug")) { - m_fileLogLevel = spdlog::level::debug; - } - else if (std::string::npos != str.find("trace")) { - m_fileLogLevel = spdlog::level::trace; - } + // Logging: file-log-level + if (j.contains("file-log-level")) { + std::string str; + try { + str = j["file-log-level"].get(); + } + catch (const std::exception &ex) { + spdlog::error("Failed to read 'file-log-level' Error='{}'", ex.what()); + } + catch (...) { + spdlog::error("Failed to read 'file-log-level' due to unknown error."); + } + vscp_makeLower(str); + if (std::string::npos != str.find("off")) { + m_fileLogLevel = spdlog::level::off; + } + else if (std::string::npos != str.find("critical")) { + m_fileLogLevel = spdlog::level::critical; + } + else if (std::string::npos != str.find("err")) { + m_fileLogLevel = spdlog::level::err; + } + else if (std::string::npos != str.find("warn")) { + m_fileLogLevel = spdlog::level::warn; + } + else if (std::string::npos != str.find("info")) { + m_fileLogLevel = spdlog::level::info; + } + else if (std::string::npos != str.find("debug")) { + m_fileLogLevel = spdlog::level::debug; + } + else if (std::string::npos != str.find("trace")) { + m_fileLogLevel = spdlog::level::trace; + } + else { + spdlog::error("Failed to read LOGGING 'file-log-level' has invalid value " + "[{}]. Default value used.", + str); + } + } + else { + spdlog::error("Failed to read LOGGING 'file-log-level' Defaults will be used."); + } + + // Logging: file-log-pattern + if (j.contains("file-log-pattern")) { + try { + m_fileLogPattern = j["file-log-pattern"].get(); + } + catch (const std::exception &ex) { + spdlog::error("Failed to read 'file-log-pattern' Error='{}'", ex.what()); + } + catch (...) { + spdlog::error("Failed to read 'file-log-pattern' due to unknown error."); + } + } + else { + spdlog::debug("Failed to read LOGGING 'file-log-pattern' Defaults will be used."); + } + + // Logging: file-log-path + if (j.contains("file-log-path")) { + try { + m_path_to_log_file = j["file-log-path"].get(); + } + catch (const std::exception &ex) { + spdlog::error("Failed to read 'file-log-path' Error='{}'", ex.what()); + } + catch (...) { + spdlog::error("Failed to read 'file-log-path' due to unknown error."); + } + } + else { + spdlog::error(" Failed to read LOGGING 'file-log-path' Defaults will be used."); + } + + // Logging: file-log-max-size + if (j.contains("file-log-max-size")) { + try { + m_max_log_size = j["file-log-max-size"].get(); + } + catch (const std::exception &ex) { + spdlog::error("Failed to read 'file-log-max-size' Error='{}'", ex.what()); + } + catch (...) { + spdlog::error("Failed to read 'file-log-max-size' due to unknown error."); + } + } + else { + spdlog::error("Failed to read LOGGING 'file-log-max-size' Defaults will be used."); + } + + // Logging: file-log-max-files + if (j.contains("file-log-max-files")) { + try { + m_max_log_files = j["file-log-max-files"].get(); + } + catch (const std::exception &ex) { + spdlog::error("Failed to read 'file-log-max-files' Error='{}'", ex.what()); + } + catch (...) { + spdlog::error("Failed to read 'file-log-max-files' due to unknown error."); + } + } + else { + spdlog::error("Failed to read LOGGING 'file-log-max-files' Defaults will be used."); + } + + } // Logging else { - spdlog::error("Failed to read LOGGING 'file-log-level' has invalid value " - "[{}]. Default value used.", - str); + spdlog::error("No logging has been setup."); } - } - else { - spdlog::error("Failed to read LOGGING 'file-log-level' Defaults will be used."); - } - // Logging: file-log-pattern - if (j.contains("file-log-pattern")) { - try { - m_fileLogPattern = j["file-log-pattern"].get(); - } - catch (const std::exception &ex) { - spdlog::error("Failed to read 'file-log-pattern' Error='{}'", ex.what()); - } - catch (...) { - spdlog::error("Failed to read 'file-log-pattern' due to unknown error."); - } - } - else { - spdlog::debug("Failed to read LOGGING 'file-log-pattern' Defaults will be used."); - } + /////////////////////////////////////////////////////////////////////////// + // Setup logger + /////////////////////////////////////////////////////////////////////////// - // Logging: file-log-path - if (j.contains("file-log-path")) { - try { - m_path_to_log_file = j["file-log-path"].get(); - } - catch (const std::exception &ex) { - spdlog::error("Failed to read 'file-log-path' Error='{}'", ex.what()); + // Console log + auto console_sink = std::make_shared(); + if (m_bConsoleLogEnable) { + console_sink->set_level(m_consoleLogLevel); + console_sink->set_pattern(m_consoleLogPattern); } - catch (...) { - spdlog::error("Failed to read 'file-log-path' due to unknown error."); + else { + // If disabled set to off + console_sink->set_level(spdlog::level::off); } - } - else { - spdlog::error(" Failed to read LOGGING 'file-log-path' Defaults will be used."); - } - // Logging: file-log-max-size - if (j.contains("file-log-max-size")) { - try { - m_max_log_size = j["file-log-max-size"].get(); - } - catch (const std::exception &ex) { - spdlog::error("Failed to read 'file-log-max-size' Error='{}'", ex.what()); - } - catch (...) { - spdlog::error("Failed to read 'file-log-max-size' due to unknown error."); - } - } - else { - spdlog::error("Failed to read LOGGING 'file-log-max-size' Defaults will be used."); - } + // auto rotating = + // std::make_shared("log_filename", + // 1024*1024, 5, false); + auto rotating_file_sink = + std::make_shared(m_path_to_log_file.c_str(), m_max_log_size, + m_max_log_files); - // Logging: file-log-max-files - if (j.contains("file-log-max-files")) { - try { - m_max_log_files = j["file-log-max-files"].get(); - } - catch (const std::exception &ex) { - spdlog::error("Failed to read 'file-log-max-files' Error='{}'", ex.what()); + if (m_bEnableFileLog) { + rotating_file_sink->set_level(m_fileLogLevel); + rotating_file_sink->set_pattern(m_fileLogPattern); } - catch (...) { - spdlog::error("Failed to read 'file-log-max-files' due to unknown error."); + else { + // If disabled set to off + rotating_file_sink->set_level(spdlog::level::off); } - } - else { - spdlog::error("Failed to read LOGGING 'file-log-max-files' Defaults will be used."); - } - - } // Logging - else { - spdlog::error("No logging has been setup."); - } - /////////////////////////////////////////////////////////////////////////// - // Setup logger - /////////////////////////////////////////////////////////////////////////// - - // Console log - auto console_sink = std::make_shared(); - if (m_bConsoleLogEnable) { - console_sink->set_level(m_consoleLogLevel); - console_sink->set_pattern(m_consoleLogPattern); - } - else { - // If disabled set to off - console_sink->set_level(spdlog::level::off); - } - - // auto rotating = - // std::make_shared("log_filename", - // 1024*1024, 5, false); - auto rotating_file_sink = - std::make_shared(m_path_to_log_file.c_str(), m_max_log_size, m_max_log_files); - - if (m_bEnableFileLog) { - rotating_file_sink->set_level(m_fileLogLevel); - rotating_file_sink->set_pattern(m_fileLogPattern); - } - else { - // If disabled set to off - rotating_file_sink->set_level(spdlog::level::off); - } - - std::vector sinks{ console_sink, rotating_file_sink }; - auto logger = std::make_shared("logger", - sinks.begin(), - sinks.end(), - spdlog::thread_pool(), - spdlog::async_overflow_policy::block); - // The separate sub loggers will handle trace levels - logger->set_level(spdlog::level::trace); - spdlog::register_logger(logger); -*/ + std::vector sinks{ console_sink, rotating_file_sink }; + auto logger = std::make_shared("logger", + sinks.begin(), + sinks.end(), + spdlog::thread_pool(), + spdlog::async_overflow_policy::block); + // The separate sub loggers will handle trace levels + logger->set_level(spdlog::level::trace); + spdlog::register_logger(logger); + */ // Filter if (m_j_config.contains("filter") && m_j_config["filter"].is_object()) { @@ -584,9 +581,8 @@ bool vscpClientSocketCan::initFromJson(const std::string& config) spdlog::debug(" Failed to read 'out-mask' Defaults will be used."); } } - } - catch (const std::exception& ex) { + catch (const std::exception &ex) { spdlog::error("json socketcan init: Failed to parse json: {}", ex.what()); return false; } @@ -594,395 +590,420 @@ bool vscpClientSocketCan::initFromJson(const std::string& config) return true; } - /////////////////////////////////////////////////////////////////////////////// - // connect - // +/////////////////////////////////////////////////////////////////////////////// +// connect +// - int vscpClientSocketCan::connect(void) - { - int rv = VSCP_ERROR_SUCCESS; +int +vscpClientSocketCan::connect(void) +{ + int rv = VSCP_ERROR_SUCCESS; -/* - // open the socket - if ( (m_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0 ) { - return CANAL_ERROR_SOCKET_CREATE; - } + /* + // open the socket + if ( (m_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0 ) { + return CANAL_ERROR_SOCKET_CREATE; + } - int mtu, enable_canfd = 1; - struct sockaddr_can addr; - struct ifreq ifr; + int mtu, enable_canfd = 1; + struct sockaddr_can addr; + struct ifreq ifr; - strncpy(ifr.ifr_name, m_interface.c_str(), IFNAMSIZ - 1); - ifr.ifr_name[IFNAMSIZ - 1] = '\0'; - ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name); - if (!ifr.ifr_ifindex) { - spdlog::error("Cant get socketcan index from {0}", m_interface); - return VSCP_ERROR_ERROR; - } + strncpy(ifr.ifr_name, m_interface.c_str(), IFNAMSIZ - 1); + ifr.ifr_name[IFNAMSIZ - 1] = '\0'; + ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name); + if (!ifr.ifr_ifindex) { + spdlog::error("Cant get socketcan index from {0}", m_interface); + return VSCP_ERROR_ERROR; + } - addr.can_family = AF_CAN; - addr.can_ifindex = ifr.ifr_ifindex; + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; - if (CANFD_MTU == m_mode) { - // check if the frame fits into the CAN netdevice - if (ioctl(m_socket, SIOCGIFMTU, &ifr) < 0) { - spdlog::error("FD MTU does not fit for {0}", m_interface); - return VSCP_TYPE_ERROR_FIFO_SIZE; - } + if (CANFD_MTU == m_mode) { + // check if the frame fits into the CAN netdevice + if (ioctl(m_socket, SIOCGIFMTU, &ifr) < 0) { + spdlog::error("FD MTU does not fit for {0}", m_interface); + return VSCP_TYPE_ERROR_FIFO_SIZE; + } - mtu = ifr.ifr_mtu; + mtu = ifr.ifr_mtu; - if (mtu != CANFD_MTU) { - spdlog::error("CAN FD mode is not supported for {0}", m_interface); - return VSCP_ERROR_NOT_SUPPORTED; - } + if (mtu != CANFD_MTU) { + spdlog::error("CAN FD mode is not supported for {0}", m_interface); + return VSCP_ERROR_NOT_SUPPORTED; + } - // interface is ok - try to switch the socket into CAN FD mode - if (setsockopt(m_socket, - SOL_CAN_RAW, - CAN_RAW_FD_FRAMES, - &enable_canfd, - sizeof(enable_canfd))) - { - spdlog::error("Failed to switch socket to FD mode {0}", m_interface); - return VSCP_ERROR_NOT_SUPPORTED; - } + // interface is ok - try to switch the socket into CAN FD mode + if (setsockopt(m_socket, + SOL_CAN_RAW, + CAN_RAW_FD_FRAMES, + &enable_canfd, + sizeof(enable_canfd))) + { + spdlog::error("Failed to switch socket to FD mode {0}", m_interface); + return VSCP_ERROR_NOT_SUPPORTED; + } - } -*/ - //const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE | \ + } + */ + //const int timestamping_flags = (SOF_TIMESTAMPING_SOFTWARE | \ // SOF_TIMESTAMPING_RX_SOFTWARE | \ // SOF_TIMESTAMPING_RAW_HARDWARE); - //if (setsockopt(m_socket, SOL_SOCKET, SO_TIMESTAMPING, - // ×tamping_flags, sizeof(timestamping_flags)) < 0) { - // perror("setsockopt SO_TIMESTAMPING is not supported by your Linux kernel"); - //} - - // disable default receive filter on this RAW socket - // This is obsolete as we do not read from the socket at all, but for - // this reason we can remove the receive list in the Kernel to save a - // little (really a very little!) CPU usage. - //setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); - -/* - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = getResponseTimeout() * 1000; // Not init'ing this can cause strange errors - setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval)); - - if (bind(m_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - return CANAL_ERROR_SOCKET_BIND; - } -*/ - // start the workerthread - m_bRun = true; // Workerthread should run, run, run... - if (pthread_create(&m_threadWork, NULL, workerThread, this)) { - spdlog::critical("Failed to start workerthread"); - return false; - } + // if (setsockopt(m_socket, SOL_SOCKET, SO_TIMESTAMPING, + // ×tamping_flags, sizeof(timestamping_flags)) < 0) { + // perror("setsockopt SO_TIMESTAMPING is not supported by your Linux kernel"); + // } + + // disable default receive filter on this RAW socket + // This is obsolete as we do not read from the socket at all, but for + // this reason we can remove the receive list in the Kernel to save a + // little (really a very little!) CPU usage. + // setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); + + /* + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = getResponseTimeout() * 1000; // Not init'ing this can cause strange errors + setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval)); + + if (bind(m_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return CANAL_ERROR_SOCKET_BIND; + } + */ + // start the workerthread + m_bRun = true; // Workerthread should run, run, run... + if (pthread_create(&m_threadWork, NULL, workerThread, this)) { + spdlog::critical("Failed to start workerthread"); + return false; + } - return rv; + return rv; } /////////////////////////////////////////////////////////////////////////////// // disconnect // -int vscpClientSocketCan::disconnect(void) +int +vscpClientSocketCan::disconnect(void) { - // Do nothing if already terminated - if (!m_bRun) { - return VSCP_ERROR_SUCCESS; - } + // Do nothing if already terminated + if (!m_bRun) { + return VSCP_ERROR_SUCCESS; + } + + m_bRun = false; // terminate the thread + // Wait for workerthread to to terminate + pthread_join(m_threadWork, NULL); - m_bRun = false; // terminate the thread - // Wait for workerthread to to terminate - pthread_join(m_threadWork, NULL); - - //::close(m_socket); - m_bConnected = false; - return CANAL_ERROR_SUCCESS; + //::close(m_socket); + m_bConnected = false; + return CANAL_ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// // isConnected // -bool vscpClientSocketCan::isConnected(void) +bool +vscpClientSocketCan::isConnected(void) { - return m_bConnected; + return m_bConnected; } /////////////////////////////////////////////////////////////////////////////// // send // -int vscpClientSocketCan::send(vscpEvent &ev) +int +vscpClientSocketCan::send(vscpEvent &ev) { - if (m_socket <= 0) { - return VSCP_ERROR_WRITE_ERROR; - } + if (m_socket <= 0) { + return VSCP_ERROR_WRITE_ERROR; + } - canalMsg canalMsg; - if ( !vscp_convertEventToCanal(&canalMsg, &ev ) ) { - return VSCP_ERROR_PARAMETER; - } + canalMsg canalMsg; + if (!vscp_convertEventToCanal(&canalMsg, &ev)) { + return VSCP_ERROR_PARAMETER; + } - struct canfd_frame frame; - memset(&frame, 0, sizeof(frame)); // init CAN FD frame, e.g. LEN = 0 - - // convert CanFrame to canfd_frame - frame.can_id = canalMsg.id; - frame.can_id |= CAN_EFF_FLAG; - frame.len = canalMsg.sizeData; - frame.flags = canalMsg.flags; - memcpy(frame.data, canalMsg.data, canalMsg.sizeData); - - if (m_flags & FLAG_FD_MODE) { - // ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 - frame.len = canal_dlc2len(canal_tbllen2dlc[frame.len]); - } + struct canfd_frame frame; + memset(&frame, 0, sizeof(frame)); // init CAN FD frame, e.g. LEN = 0 + + // convert CanFrame to canfd_frame + frame.can_id = canalMsg.id; + frame.can_id |= CAN_EFF_FLAG; + frame.len = canalMsg.sizeData; + frame.flags = canalMsg.flags; + memcpy(frame.data, canalMsg.data, canalMsg.sizeData); + + if (m_flags & FLAG_FD_MODE) { + // ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 + frame.len = canal_dlc2len(canal_tbllen2dlc[frame.len]); + } - // send the frame - pthread_mutex_lock(&m_mutexSocket); - if ( -1 == write(m_socket, &frame, sizeof(struct can_frame)) ) { - pthread_mutex_unlock(&m_mutexSocket); - return VSCP_ERROR_WRITE_ERROR; - } + // send the frame + pthread_mutex_lock(&m_mutexSocket); + if (-1 == write(m_socket, &frame, sizeof(struct can_frame))) { pthread_mutex_unlock(&m_mutexSocket); + return VSCP_ERROR_WRITE_ERROR; + } + pthread_mutex_unlock(&m_mutexSocket); - return VSCP_ERROR_SUCCESS; + return VSCP_ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// // send // -int vscpClientSocketCan::send(vscpEventEx &ex) +int +vscpClientSocketCan::send(vscpEventEx &ex) { - if (m_socket <= 0) { - return VSCP_ERROR_WRITE_ERROR; - } - - canalMsg canalMsg; - if ( !vscp_convertEventExToCanal(&canalMsg, &ex ) ) { - return VSCP_ERROR_PARAMETER; - } - - struct canfd_frame frame; - memset(&frame, 0, sizeof(frame)); // init CAN FD frame, e.g. LEN = 0 + if (m_socket <= 0) { + return VSCP_ERROR_WRITE_ERROR; + } - // convert CanFrame to canfd_frame - frame.can_id = canalMsg.id; - frame.can_id |= CAN_EFF_FLAG; - frame.len = canalMsg.sizeData; - frame.flags = canalMsg.flags; - memcpy(frame.data, canalMsg.data, canalMsg.sizeData); + canalMsg canalMsg; + if (!vscp_convertEventExToCanal(&canalMsg, &ex)) { + return VSCP_ERROR_PARAMETER; + } - if (m_flags & FLAG_FD_MODE) { - // ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 - frame.len = canal_dlc2len(canal_tbllen2dlc[frame.len]); - } + struct canfd_frame frame; + memset(&frame, 0, sizeof(frame)); // init CAN FD frame, e.g. LEN = 0 + + // convert CanFrame to canfd_frame + frame.can_id = canalMsg.id; + frame.can_id |= CAN_EFF_FLAG; + frame.len = canalMsg.sizeData; + frame.flags = canalMsg.flags; + memcpy(frame.data, canalMsg.data, canalMsg.sizeData); + + if (m_flags & FLAG_FD_MODE) { + // ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 + frame.len = canal_dlc2len(canal_tbllen2dlc[frame.len]); + } - // send the frame - pthread_mutex_lock(&m_mutexSocket); - if ( -1 == write(m_socket, &frame, sizeof(struct can_frame)) ) { - pthread_mutex_unlock(&m_mutexSocket); - return VSCP_ERROR_WRITE_ERROR; - } + // send the frame + pthread_mutex_lock(&m_mutexSocket); + if (-1 == write(m_socket, &frame, sizeof(struct can_frame))) { pthread_mutex_unlock(&m_mutexSocket); + return VSCP_ERROR_WRITE_ERROR; + } + pthread_mutex_unlock(&m_mutexSocket); - return VSCP_ERROR_SUCCESS; + return VSCP_ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// // receive // -int vscpClientSocketCan::receive(vscpEvent &ev) +int +vscpClientSocketCan::receive(vscpEvent &ev) { - int rv; - canalMsg canalMsg; - uint8_t guid[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - - //if ( CANAL_ERROR_SUCCESS != (rv = m_canalif.CanalReceive(&canalMsg) ) ) { - // return rv; - //} - - return 0; //vscp_convertCanalToEvent(&ev, &canalMsg, guid); + int rv; + + // Check if there are any events waiting + if (!m_receiveList.size()) { + return VSCP_ERROR_FIFO_EMPTY; + } + printf("receive\n"); + const vscpEvent *pev = m_receiveList.front(); + if (nullptr == pev) { + return VSCP_ERROR_INVALID_POINTER; + } + vscp_copyEvent(&ev, pev); + m_receiveList.pop_front(); + delete pev; + printf("RRRRR receive\n"); + return VSCP_ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// // receive // -int vscpClientSocketCan::receive(vscpEventEx &ex) +int +vscpClientSocketCan::receive(vscpEventEx &ex) { - int rv; - canalMsg canalMsg; - uint8_t guid[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - - //if ( CANAL_ERROR_SUCCESS != (rv = m_canalif.CanalReceive(&canalMsg) ) ) { - // return rv; - //} - - return vscp_convertCanalToEventEx(&ex, - &canalMsg, - guid); + int rv; + vscpEvent ev; + + if (VSCP_ERROR_SUCCESS != (rv = receive(ev))) { + return rv; + } + + return (vscp_convertEventToEventEx(&ex, &ev) ? VSCP_ERROR_SUCCESS : VSCP_ERROR_ERROR); } /////////////////////////////////////////////////////////////////////////////// // setfilter // -int vscpClientSocketCan::setfilter(vscpEventFilter &filter) +int +vscpClientSocketCan::setfilter(vscpEventFilter &filter) { - int rv; - - uint32_t _filter = ((unsigned long)filter.filter_priority << 26) | - ((unsigned long)filter.filter_class << 16) | - ((unsigned long)filter.filter_type << 8) | filter.filter_GUID[0]; - //if ( CANAL_ERROR_SUCCESS == (rv = m_canalif.CanalSetFilter(_filter))) { - // return rv; - //} - - uint32_t _mask = ((unsigned long)filter.mask_priority << 26) | - ((unsigned long)filter.mask_class << 16) | - ((unsigned long)filter.mask_type << 8) | filter.mask_GUID[0]; - return 0; //m_canalif.CanalSetMask(_mask); + int rv; + + uint32_t _filter = ((unsigned long) filter.filter_priority << 26) | ((unsigned long) filter.filter_class << 16) | + ((unsigned long) filter.filter_type << 8) | filter.filter_GUID[0]; + // if ( CANAL_ERROR_SUCCESS == (rv = m_canalif.CanalSetFilter(_filter))) { + // return rv; + // } + + uint32_t _mask = ((unsigned long) filter.mask_priority << 26) | ((unsigned long) filter.mask_class << 16) | + ((unsigned long) filter.mask_type << 8) | filter.mask_GUID[0]; + return 0; // m_canalif.CanalSetMask(_mask); } /////////////////////////////////////////////////////////////////////////////// // getcount // -int vscpClientSocketCan::getcount(uint16_t *pcount) +int +vscpClientSocketCan::getcount(uint16_t *pcount) { - return 0; + *pcount = m_receiveList.size(); + return VSCP_ERROR_SUCCESS; } ////////////////////////////////////////////////////////////////////////////// // clear // -int vscpClientSocketCan::clear() +int +vscpClientSocketCan::clear() { - return VSCP_ERROR_SUCCESS; + return VSCP_ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// // getversion // -int vscpClientSocketCan::getversion(uint8_t *pmajor, - uint8_t *pminor, - uint8_t *prelease, - uint8_t *pbuild) +int +vscpClientSocketCan::getversion(uint8_t *pmajor, uint8_t *pminor, uint8_t *prelease, uint8_t *pbuild) { - //uint32_t ver = m_canalif.CanalGetDllVersion(); + // uint32_t ver = m_canalif.CanalGetDllVersion(); - return VSCP_ERROR_SUCCESS; + return VSCP_ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// // getinterfaces // -int vscpClientSocketCan::getinterfaces(std::deque &iflist) +int +vscpClientSocketCan::getinterfaces(std::deque &iflist) { - // No interfaces available - return VSCP_ERROR_SUCCESS; + // No interfaces available + return VSCP_ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// // getwcyd // -int vscpClientSocketCan::getwcyd(uint64_t &wcyd) +int +vscpClientSocketCan::getwcyd(uint64_t &wcyd) { - wcyd = VSCP_SERVER_CAPABILITY_NONE; // No capabilities - return VSCP_ERROR_SUCCESS; + wcyd = VSCP_SERVER_CAPABILITY_NONE; // No capabilities + return VSCP_ERROR_SUCCESS; } ////////////////////////////////////////////////////////////////////////////// // setConnectionTimeout // -void vscpClientSocketCan::setConnectionTimeout(uint32_t timeout) +void +vscpClientSocketCan::setConnectionTimeout(uint32_t timeout) { - ; + ; } ////////////////////////////////////////////////////////////////////////////// // getConnectionTimeout // -uint32_t vscpClientSocketCan::getConnectionTimeout(void) +uint32_t +vscpClientSocketCan::getConnectionTimeout(void) { - return 0; + return 0; } ////////////////////////////////////////////////////////////////////////////// // setResponseTimeout // -void vscpClientSocketCan::setResponseTimeout(uint32_t timeout) +void +vscpClientSocketCan::setResponseTimeout(uint32_t timeout) { - ; + ; } ////////////////////////////////////////////////////////////////////////////// // getResponseTimeout // -uint32_t vscpClientSocketCan::getResponseTimeout(void) +uint32_t +vscpClientSocketCan::getResponseTimeout(void) { - return 0; + return 0; } /////////////////////////////////////////////////////////////////////////////// // sendToCallbacks // -void vscpClientSocketCan::sendToCallbacks(vscpEvent *pev) +void +vscpClientSocketCan::sendToCallbacks(vscpEvent *pev) { - if (nullptr != m_evcallback) { - m_evcallback(pev, m_callbackObject); - } + printf("sendToCallbacks\n"); + if (nullptr != m_evcallback) { + printf("----->\n"); + m_evcallback(pev, m_callbackObject); + } - if (nullptr != m_excallback) { - vscpEventEx ex; - vscp_convertEventToEventEx(&ex, pev); - m_excallback(&ex, m_callbackObject); - } + if (nullptr != m_excallback) { + vscpEventEx ex; + vscp_convertEventToEventEx(&ex, pev); + m_excallback(&ex, m_callbackObject); + } } /////////////////////////////////////////////////////////////////////////////// // setCallback // -int vscpClientSocketCan::setCallback(LPFNDLL_EV_CALLBACK m_evcallback) +int +vscpClientSocketCan::setCallback(LPFNDLL_EV_CALLBACK m_evcallback) { - // Can not be called when connected - if ( m_bConnected ) return VSCP_ERROR_ERROR; - m_evcallback = m_evcallback; - return VSCP_ERROR_SUCCESS; + // Can not be called when connected + if (m_bConnected) { + return VSCP_ERROR_ERROR; + } + m_evcallback = m_evcallback; + return VSCP_ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////// // setCallback // -int vscpClientSocketCan::setCallback(LPFNDLL_EX_CALLBACK m_excallback) +int +vscpClientSocketCan::setCallback(LPFNDLL_EX_CALLBACK m_excallback) { - // Can not be called when connected - if ( m_bConnected ) return VSCP_ERROR_ERROR; - m_excallback = m_excallback; - return VSCP_ERROR_SUCCESS; + // Can not be called when connected + if (m_bConnected) { + return VSCP_ERROR_ERROR; + } + m_excallback = m_excallback; + return VSCP_ERROR_SUCCESS; } - ////////////////////////////////////////////////////////////////////// // Workerthread - Read ////////////////////////////////////////////////////////////////////// @@ -1000,7 +1021,7 @@ workerThread(void *pData) char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))]; const int canfd_on = 1; - vscpClientSocketCan *pObj = (vscpClientSocketCan *)pData; + vscpClientSocketCan *pObj = (vscpClientSocketCan *) pData; if (NULL == pObj) { spdlog::error("No object data object supplied for worker thread"); return NULL; @@ -1015,7 +1036,7 @@ workerThread(void *pData) if (ENETDOWN == errno) { pthread_mutex_unlock(&pObj->m_mutexSocket); sleep(1); - continue; // Try again + continue; // Try again } spdlog::error("wrkthread socketcan client: Error while opening socket. Terminating!"); @@ -1024,13 +1045,13 @@ workerThread(void *pData) strncpy(ifr.ifr_name, pObj->m_interface.c_str(), IFNAMSIZ - 1); ifr.ifr_name[IFNAMSIZ - 1] = '\0'; - ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name); + ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name); if (!ifr.ifr_ifindex) { - pthread_mutex_unlock(&pObj->m_mutexSocket); - spdlog::error("Cant get socketcan index from {0}", pObj->m_interface); - return NULL; + pthread_mutex_unlock(&pObj->m_mutexSocket); + spdlog::error("Cant get socketcan index from {0}", pObj->m_interface); + return NULL; } - //ioctl(pObj->m_socket, SIOCGIFINDEX, &ifr); + // ioctl(pObj->m_socket, SIOCGIFINDEX, &ifr); addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; @@ -1040,53 +1061,48 @@ workerThread(void *pData) } // try to switch the socket into CAN FD mode - //setsockopt(pObj->m_socket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); + // setsockopt(pObj->m_socket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); if (CANFD_MTU == pObj->m_mode) { // check if the frame fits into the CAN netdevice if (ioctl(pObj->m_socket, SIOCGIFMTU, &ifr) < 0) { - pthread_mutex_unlock(&pObj->m_mutexSocket); - spdlog::error("FD MTU does not fit for {0}", pObj->m_interface); - //return VSCP_TYPE_ERROR_FIFO_SIZE; - return NULL; + pthread_mutex_unlock(&pObj->m_mutexSocket); + spdlog::error("FD MTU does not fit for {0}", pObj->m_interface); + // return VSCP_TYPE_ERROR_FIFO_SIZE; + return NULL; } mtu = ifr.ifr_mtu; if (mtu != CANFD_MTU) { - pthread_mutex_unlock(&pObj->m_mutexSocket); - spdlog::error("CAN FD mode is not supported for {0}", pObj->m_interface); - //return VSCP_ERROR_NOT_SUPPORTED; - return NULL; + pthread_mutex_unlock(&pObj->m_mutexSocket); + spdlog::error("CAN FD mode is not supported for {0}", pObj->m_interface); + // return VSCP_ERROR_NOT_SUPPORTED; + return NULL; } // interface is ok - try to switch the socket into CAN FD mode - if (setsockopt(pObj->m_socket, - SOL_CAN_RAW, - CAN_RAW_FD_FRAMES, - &enable_canfd, - sizeof(enable_canfd))) { - pthread_mutex_unlock(&pObj->m_mutexSocket); - spdlog::error("Failed to switch socket to FD mode {0}", pObj->m_interface); - //return VSCP_ERROR_NOT_SUPPORTED; - return NULL; + if (setsockopt(pObj->m_socket, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd))) { + pthread_mutex_unlock(&pObj->m_mutexSocket); + spdlog::error("Failed to switch socket to FD mode {0}", pObj->m_interface); + // return VSCP_ERROR_NOT_SUPPORTED; + return NULL; } - } pthread_mutex_unlock(&pObj->m_mutexSocket); struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = pObj->getResponseTimeout() * 1000; // Not init'ing this can cause strange errors - setsockopt(pObj->m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval)); + tv.tv_sec = 0; + tv.tv_usec = pObj->getResponseTimeout() * 1000; // Not init'ing this can cause strange errors + setsockopt(pObj->m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char *) &tv, sizeof(struct timeval)); if (bind(pObj->m_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0) { spdlog::error("wrkthread socketcan client: Error in socket bind. Terminating!"); close(pObj->m_socket); sleep(2); - //continue; + // continue; return NULL; } @@ -1146,7 +1162,7 @@ workerThread(void *pData) vscpEvent *pEvent = new vscpEvent(); if (nullptr != pEvent) { - + // This can lead to level I frames having to // much data. Later code will handel this case. pEvent->pdata = new uint8_t[frame.len]; @@ -1157,7 +1173,7 @@ workerThread(void *pData) // GUID will be set to GUID of interface // by driver interface with LSB set to nickname - //memcpy(pEvent->GUID, pObj->m_guid.getGUID(), 16); + // memcpy(pEvent->GUID, pObj->m_guid.getGUID(), 16); pEvent->GUID[VSCP_GUID_LSB] = frame.can_id & 0xff; // Set VSCP class @@ -1168,29 +1184,34 @@ workerThread(void *pData) // Copy data if any pEvent->sizeData = frame.len; - if (frame.len) { + if (frame.len) { memcpy(pEvent->pdata, frame.data, frame.len); } if (vscp_doLevel2Filter(pEvent, &pObj->m_filterIn)) { if (nullptr != pObj->m_evcallback) { - pObj->m_evcallback(pEvent, pObj->m_callbackObject); + pObj->m_evcallback(pEvent, pObj->m_callbackObject); } if (nullptr != pObj->m_excallback) { - vscpEventEx ex; - if (vscp_convertEventToEventEx(&ex, pEvent) ) { - pObj->m_excallback(&ex, pObj->m_callbackObject); - } + vscpEventEx ex; + if (vscp_convertEventToEventEx(&ex, pEvent)) { + pObj->m_excallback(&ex, pObj->m_callbackObject); + } } - if ((nullptr != pObj->m_evcallback) && (nullptr != pObj->m_excallback)) { - pthread_mutex_lock(&pObj->m_mutexReceiveQueue); - pObj->m_receiveList.push_back(pEvent); - sem_post(&pObj->m_semReceiveQueue); - pthread_mutex_unlock(&pObj->m_mutexReceiveQueue); + printf("Socketcan event: %X:%X\n", pEvent->vscp_class, pEvent->vscp_type); + + // Add to input queue only if no callback set + if ((nullptr == pObj->m_evcallback) && (nullptr == pObj->m_excallback)) { + std::cout << "add to receive queue" << std::endl; + pthread_mutex_lock(&pObj->m_mutexReceiveQueue); + pObj->m_receiveList.push_back(pEvent); + sem_post(&pObj->m_semReceiveQueue); + pthread_mutex_unlock(&pObj->m_mutexReceiveQueue); } + } else { vscp_deleteEvent(pEvent); @@ -1256,5 +1277,4 @@ workerThread(void *pData) return NULL; } -#endif // not windows - +#endif // not windows diff --git a/src/vscp/common/vscp_client_socketcan.h b/src/vscp/common/vscp_client_socketcan.h index f74587908..897fb61dc 100644 --- a/src/vscp/common/vscp_client_socketcan.h +++ b/src/vscp/common/vscp_client_socketcan.h @@ -9,8 +9,8 @@ // // This file is part of the VSCP (https://www.vscp.org) // -// Copyright: (C) 2007-2023 -// Ake Hedman, the VSCP project, +// Copyright © 2000-2024 Ake Hedman, Grodans Paradis AB +// // // This file is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of