Update MediaClient

This commit is contained in:
2026-03-28 11:39:04 +11:00
parent 24dc6c7cd0
commit f3266566eb
1284 changed files with 462406 additions and 0 deletions

BIN
IOBox/Backup/iobox_api.zip Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -0,0 +1,729 @@
#include "iobox_api.h"
namespace ANSCENTER {
iobox_api::iobox_api(std::string ipmcast, int port_mcast)
{
this->ip_mcast = ipmcast;
this->port_mcast = port_mcast;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed with error: " << WSAGetLastError() << std::endl;
return;
}
}
iobox_api::~iobox_api()
{
WSACleanup();
}
bool isStringExistInVectorString(const std::vector<std::string>& vec, const std::string& str) {
for (const auto& item : vec) {
if (item == str) {
std::cout << "Found duplicate: " << str << std::endl;
return true;
}
}
return false;
// return std::find(vec.begin(), vec.end(), str) != vec.end();
}
void printBufferAsHex(const char* buffer, size_t length) {
for (size_t i = 0; i < length; ++i) {
printf("%02X ", static_cast<unsigned char>(buffer[i]));
if ((i + 1) % 16 == 0) {
printf("\n");
}
}
printf("\n");
}
void printStringAsHex(const std::string& str) {
for (size_t i = 0; i < str.size(); ++i) {
printf("%02X ", static_cast<unsigned char>(str[i]));
if ((i + 1) % 16 == 0) {
printf("\n");
}
}
printf("\n");
}
iobox_info_t parseIoboxResponse(const std::string& response) {
iobox_info_t info;
size_t ipPos = response.find("IOBOX_RESPONSE:");
size_t modbusPos = response.find("modbus_address:");
if (ipPos != std::string::npos && modbusPos != std::string::npos) {
ipPos += strlen("IOBOX_RESPONSE:");
modbusPos += strlen("modbus_address:");
size_t ipEnd = response.find(',', ipPos);
if (ipEnd != std::string::npos) {
info.ip_address = response.substr(ipPos, ipEnd - ipPos);
}
std::string modbusStr = response.substr(modbusPos);
info.modbus_address = std::stoi(modbusStr);
}
return info;
}
void show_info_iobox(iobox_info_t iobox_info) {
std::cout << " IP Address: " << iobox_info.ip_address << std::endl;
std::cout << " Modbus Address: " << (int)iobox_info.modbus_address << std::endl;
}
void iobox_api::show_profile_iobox(std::string ip) {
iobox_profile_t* profile = findProfileByIp(ip);
if (profile == nullptr) {
std::cerr << "IP address not found: " << ip << std::endl;
return;
}
show_profile_iobox(*profile);
}
void iobox_api::show_profile_iobox(iobox_profile_t profile) {
// std::cout << "Profile ioboxs: " << this->iobox_profiles.size() << std::endl;
// for (const iobox_profile_t& profile : this->iobox_profiles) {
// std::cout << "* Index: " << &profile - &this->iobox_profiles[0] << std::endl;
show_info_iobox(profile.iobox_info);
std::cout << " Counting get: " << profile.counting_get << std::endl;
std::cout << " Is connected: " << profile.is_connected << std::endl;
if (profile.counting_get)
{
std::cout << " Modbus address: " << profile.iobox_data.modbus_address << std::endl;
std::cout << " Serial number: " << reinterpret_cast<const char*>(profile.iobox_data.serial_number) << std::endl;
uint8_t hw_version = (profile.iobox_data.version >> 8) & 0xFF;
uint8_t fw_version = profile.iobox_data.version & 0xFF;
std::cout << " HW Version: " << static_cast<int>(hw_version) << std::endl;
std::cout << " FW Version: " << static_cast<int>(fw_version) << std::endl;
std::cout << " Channel DO: ";
std::cout << profile.iobox_data.channel_DO[0] << " ";
std::cout << profile.iobox_data.channel_DO[1] << " ";
std::cout << profile.iobox_data.channel_DO[2] << " ";
std::cout << profile.iobox_data.channel_DO[3] << std::endl;
std::cout << " Channel DI: ";
std::cout << profile.iobox_data.channel_DI[0] << " ";
std::cout << profile.iobox_data.channel_DI[1] << " ";
std::cout << profile.iobox_data.channel_DI[2] << " ";
std::cout << profile.iobox_data.channel_DI[3] << std::endl;
std::cout << " Channel AI: ";
std::cout << profile.iobox_data.channel_AI[0] << " ";
std::cout << profile.iobox_data.channel_AI[1] << std::endl;
}
// }
}
void iobox_api::show_profile_ioboxs() {
if (this->iobox_profiles.size() == 0) {
std::cout << "No iobox profiles" << std::endl;
return;
}
for (const auto& profile : this->iobox_profiles) {
std::cout << "* Index: " << &profile - &this->iobox_profiles[0] << std::endl;
show_profile_iobox(profile);
}
}
//void iobox_api::save_info_iobox(iobox_info_t iobox_info) {
// iobox_profile_t profile = {
// .counting_get = 0,
// .is_connected = false,
// .sock_tcp = INVALID_SOCKET,
// };
// profile.iobox_info = iobox_info;
// this->iobox_profiles.push_back(profile);
//}
void iobox_api::save_info_iobox(iobox_info_t iobox_info) {
iobox_profile_t profile;
profile.counting_get = 0;
profile.is_connected = false;
profile.sock_tcp = INVALID_SOCKET;
profile.iobox_info = iobox_info;
this->iobox_profiles.push_back(profile);
}
bool iobox_api::sendTcpMessage(const std::string& ip, const char* buffer, size_t length) {
for (auto& profile : this->iobox_profiles) {
if (profile.iobox_info.ip_address == ip && profile.is_connected && profile.sock_tcp != INVALID_SOCKET) {
int result = send(profile.sock_tcp, buffer, length, 0);
if (result == SOCKET_ERROR) {
std::cerr << "send failed with error: " << WSAGetLastError() << std::endl;
return false;
}
std::cout << "Sent " << length << " bytes message to " << ip << std::endl;
printBufferAsHex(buffer, length);
return true;
}
}
std::cerr << "IP address not found or not connected: " << ip << std::endl;
return false;
}
bool iobox_api::receiveTcpMessage(const std::string& ip, char* buffer, size_t& length) {
for (auto& profile : this->iobox_profiles) {
if (profile.iobox_info.ip_address == ip && profile.is_connected && profile.sock_tcp != INVALID_SOCKET) {
setSocketTimeout(profile.sock_tcp, 3000);
int recvLen = recv(profile.sock_tcp, buffer, length, 0);
if (recvLen > 0) {
length = recvLen;
std::cout << "Received message: " << length << " bytes" << std::endl;
printBufferAsHex(buffer, recvLen);
return true;
}
else {
std::cerr << "recv failed with error: " << WSAGetLastError() << std::endl;
return false;
}
}
}
std::cerr << "IP address not found or not connected: " << ip << std::endl;
return false;
}
void iobox_api::sendMulticastMessage(const std::string& message) {
SOCKET sock = INVALID_SOCKET;
struct sockaddr_in multicastAddr;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) {
std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl;
WSACleanup();
return;
}
memset(&multicastAddr, 0, sizeof(multicastAddr));
multicastAddr.sin_family = AF_INET;
multicastAddr.sin_addr.s_addr = inet_addr(this->ip_mcast.c_str());
multicastAddr.sin_port = htons(this->port_mcast);
if (sendto(sock, message.c_str(), message.length(), 0, (struct sockaddr*)&multicastAddr, sizeof(multicastAddr)) == SOCKET_ERROR) {
std::cerr << "sendto failed with error: " << WSAGetLastError() << std::endl;
}
else {
std::cout << "Sent message: " << message << std::endl;
}
closesocket(sock);
}
void iobox_api::setSocketTimeout(SOCKET sock, int timeout) {
struct timeval tv;
tv.tv_sec = timeout;
tv.tv_usec = 0;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) < 0) {
std::cerr << "setsockopt failed with error: " << WSAGetLastError() << std::endl;
}
}
std::vector<std::string> iobox_api::scanNetworkDevicesMulticast(int timeout) {
std::vector<std::string> devices;
for (const auto& item : this->iobox_profiles) {
if (item.is_connected || item.sock_tcp != INVALID_SOCKET) {
std::cout << "Please close connection to " << item.iobox_info.ip_address << "befor new scan" << std::endl;
return devices;
}
}
//remove all elements from iobox_profiles before and we start with new scan
this->iobox_profiles.clear();
// WSADATA wsaData;
SOCKET sock = INVALID_SOCKET;
struct sockaddr_in multicastAddr;
struct ip_mreq multicastRequest;
char recvBuf[1024];
struct sockaddr_in recvAddr;
int recvAddrLen = sizeof(recvAddr);
std::string message = "IOBOX_DISCOVERY";
// if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
// std::cerr << "WSAStartup failed with error: " << WSAGetLastError() << std::endl;
// return devices;
// }
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) {
std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl;
// WSACleanup();
return devices;
}
memset(&multicastAddr, 0, sizeof(multicastAddr));
multicastAddr.sin_family = AF_INET;
multicastAddr.sin_addr.s_addr = htonl(INADDR_ANY);
multicastAddr.sin_port = htons(this->port_mcast);
if (bind(sock, (struct sockaddr*)&multicastAddr, sizeof(multicastAddr)) == SOCKET_ERROR) {
std::cerr << "bind failed with error: " << WSAGetLastError() << std::endl;
closesocket(sock);
// WSACleanup();
return devices;
}
multicastRequest.imr_multiaddr.s_addr = inet_addr(this->ip_mcast.c_str());
multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
#ifndef TEST_FIX_IP
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multicastRequest, sizeof(multicastRequest)) < 0) {
std::cerr << "setsockopt failed with error: " << WSAGetLastError() << std::endl;
closesocket(sock);
// WSACleanup();
return devices;
}
#endif
setSocketTimeout(sock, 3000);
auto start = std::chrono::steady_clock::now();
// sendMulticastMessage(message);
while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout)) {
int recvLen = recvfrom(sock, recvBuf, sizeof(recvBuf) - 1, 0, (struct sockaddr*)&recvAddr, &recvAddrLen);
if (recvLen > 0) {
recvBuf[recvLen] = '\0';
std::string message_rsp(recvBuf);
std::string senderIp = inet_ntoa(recvAddr.sin_addr);
std::cout << "Received message: \"" << message_rsp << "\" from " << senderIp << std::endl;
iobox_info_t info = parseIoboxResponse(message_rsp);
if (info.ip_address == senderIp && info.ip_address != "" && !isStringExistInVectorString(devices, senderIp)) {
std::string deviceInfo;
std::string deviceAlias = "ANSDAQ1";
std::string deviceSN = "SN123456";
std::string deviceModel = "ANSIOBOX";
deviceInfo = deviceAlias + "-"
+ deviceModel + "-"
+ deviceSN + "-"+ senderIp;
devices.push_back(deviceInfo);
save_info_iobox(info);
}
}
else {
//std::cerr << "recvfrom failed with error: " << WSAGetLastError() << std::endl;
sendMulticastMessage(message);
}
}
#ifndef TEST_FIX_IP
setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char*)&multicastRequest, sizeof(multicastRequest));
#endif
closesocket(sock);
// WSACleanup();
return devices;
}
bool iobox_api::connectToIobox(const std::string& ip, int port, const std::string& username, const std::string& password) {
// check ip is already in iobox_profiles
bool is_exist = false;
iobox_profile_t* item = nullptr;
for (auto& profile : this->iobox_profiles) {
if (profile.iobox_info.ip_address == ip) {
is_exist = true;
item = &profile;
if (item->is_connected) {
std::cout << "Ip is already connected: " << ip << std::endl;
return true;
}
break;
}
}
if (is_exist == false) {
std::cout << "Ip is not exist in list scan" << ip << std::endl;
return false;
}
// WSADATA wsaData;
SOCKET sock = INVALID_SOCKET;
struct sockaddr_in serverAddr;
//char recvBuf[1024];
int recvLen = 0;
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
// Initialize Winsock
// int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
// if (result != 0) {
// std::cerr << "WSAStartup failed: " << result << std::endl;
// return false;
// }
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
std::cerr << "socket failed with error: " << WSAGetLastError() << std::endl;
// WSACleanup();
return false;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(ip.c_str());
serverAddr.sin_port = htons(port);
if (connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
std::cerr << "connect failed with error: " << WSAGetLastError() << std::endl;
closesocket(sock);
// WSACleanup();
return false;
}
// setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
// recvLen = recv(sock, recvBuf, sizeof(recvBuf) - 1, 0);
// if (recvLen > 0) {
// recvBuf[recvLen] = '\0';
// std::cout << "Received message: " << recvBuf << std::endl;
// } else {
// std::cerr << "recv failed with error: " << WSAGetLastError() << std::endl;
// }
// closesocket(sock);
// WSACleanup();
item->sock_tcp = sock;
item->is_connected = true;
return true;
}
bool iobox_api::disconnectToIobox(const std::string& ip) {
// check ip is already in iobox_profiles
bool is_exist = false;
iobox_profile_t* item = nullptr;
for (auto& profile : this->iobox_profiles) {
if (profile.iobox_info.ip_address == ip) {
item = &profile;
is_exist = true;
if (item->is_connected) {
std::cout << "Ip is already connected: " << ip << std::endl;
}
break;
}
}
if (is_exist == false) {
std::cout << "Ip is not exist in list scan" << ip << std::endl;
return false;
}
item->counting_get = 0;
item->is_connected = false;
closesocket(item->sock_tcp);
item->sock_tcp = INVALID_SOCKET;
// WSACleanup();
return true;
}
uint16_t calculateCRC(const uint8_t* data, size_t length) {
uint16_t crc = 0xFFFF;
for (size_t i = 0; i < length; ++i) {
crc ^= data[i];
for (int j = 0; j < 8; ++j) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= 0xA001;
}
else {
crc >>= 1;
}
}
}
return crc;
}
std::vector<uint8_t> createModbusWriteSingleRegisterRequest(uint8_t slaveAddress, uint16_t address, uint16_t value) {
std::vector<uint8_t> request(8);
request[0] = slaveAddress; // Slave address
request[1] = 0x06; // Function code for Write Single Register
request[2] = (address >> 8) & 0xFF; // Register address high byte
request[3] = address & 0xFF; // Register address low byte
request[4] = (value >> 8) & 0xFF; // Value high byte
request[5] = value & 0xFF; // Value low byte
// Calculate CRC
uint16_t crc = calculateCRC(request.data(), 6);
request[6] = crc & 0xFF; // CRC low byte
request[7] = (crc >> 8) & 0xFF; // CRC high byte
return request;
}
std::vector<uint8_t> createModbusReadHoldingRegistersRequest(uint8_t slaveAddress, uint16_t startAddress, uint16_t quantity) {
std::vector<uint8_t> request(8);
request[0] = slaveAddress; // Slave address
request[1] = 0x03; // Function code for Read Holding Registers
request[2] = (startAddress >> 8) & 0xFF; // Starting address high byte
request[3] = startAddress & 0xFF; // Starting address low byte
request[4] = (quantity >> 8) & 0xFF; // Quantity of registers high byte
request[5] = quantity & 0xFF; // Quantity of registers low byte
// Calculate CRC
uint16_t crc = calculateCRC(request.data(), 6);
request[6] = crc & 0xFF; // CRC low byte
request[7] = (crc >> 8) & 0xFF; // CRC high byte
return request;
}
std::vector<uint16_t> parseModbusReadHoldingRegistersResponse(const std::vector<uint8_t>& response) {
std::vector<uint16_t> data;
if (response.size() < 5) {
return data;
}
// Verify CRC
uint16_t receivedCrc = (response[response.size() - 1] << 8) | response[response.size() - 2];
uint16_t calculatedCrc = calculateCRC(response.data(), response.size() - 2);
if (receivedCrc != calculatedCrc) {
std::cerr << "CRC check failed" << std::endl;
return data;
}
if (response[1] & 0x80) {
std::cerr << "Error code received: " << static_cast<int>(response[2]) << std::endl;
return data;
}
uint8_t byteCount = response[2];
if (response.size() < 5 + byteCount) {
return data;
}
for (size_t i = 0; i < byteCount / 2; ++i) {
uint16_t value = (response[3 + i * 2] << 8) | response[4 + i * 2];
data.push_back(value);
}
return data;
}
iobox_profile_t* iobox_api::findProfileByIp(const std::string& ip) {
iobox_profile_t* profile = nullptr;
for (auto& item : this->iobox_profiles) {
if (item.iobox_info.ip_address == ip) {
profile = &item;
}
}
return profile;
}
bool iobox_api::getAllDataFromIobox(const std::string& ip) {
iobox_profile_t* profile = findProfileByIp(ip);
if (profile == nullptr) {
std::cerr << "IP address not found: " << ip << std::endl;
return false;
}
std::vector<uint8_t> request = createModbusReadHoldingRegistersRequest(profile->iobox_info.modbus_address, DEVICE_DATA_ADDRESS, DEVICE_DATA_LENGTH);
if (!sendTcpMessage(ip, reinterpret_cast<const char*>(request.data()), request.size())) {
return false;
}
char response[256];
size_t responseLength = sizeof(response);
if (!receiveTcpMessage(ip, response, responseLength)) {
return false;
}
std::vector<uint8_t> responseVec(response, response + responseLength);
std::vector<uint16_t> registers = parseModbusReadHoldingRegistersResponse(responseVec);
if (registers.empty()) {
std::cerr << "Failed to parse Modbus response" << std::endl;
return false;
}
// Process the registers as needed
// for (size_t i = 0; i < registers.size(); ++i) {
// std::cout << "Register " << i << ": " << registers[i] << std::endl;
// }
if (registers.size() == DEVICE_DATA_LENGTH) {
memcpy(&profile->iobox_data, registers.data(), sizeof(profile->iobox_data));
}
if (profile->iobox_data.modbus_address != (uint16_t)profile->iobox_info.modbus_address) {
std::cout << "Modbus address changed to " << profile->iobox_data.modbus_address << std::endl;
profile->iobox_info.modbus_address = profile->iobox_data.modbus_address;
}
profile->counting_get++;
return true;
}
bool iobox_api::setValueDataToIobox(const std::string& ip, uint16_t address, uint16_t value) {
iobox_profile_t* profile = findProfileByIp(ip);
if (profile == nullptr) {
std::cerr << "IP address not found: " << ip << std::endl;
return false;
}
std::vector<uint8_t> request = createModbusWriteSingleRegisterRequest(profile->iobox_info.modbus_address, address, value);
if (!sendTcpMessage(ip, reinterpret_cast<const char*>(request.data()), request.size())) {
return false;
}
char response[256];
size_t responseLength = sizeof(response);
if (!receiveTcpMessage(ip, response, responseLength)) {
return false;
}
// Process the response as needed
std::vector<uint8_t> responseVec(response, response + responseLength);
if (responseVec.size() < 8) {
std::cerr << "Invalid response length" << std::endl;
return false;
}
// Verify CRC
uint16_t receivedCrc = (responseVec[7] << 8) | responseVec[6];
uint16_t calculatedCrc = calculateCRC(responseVec.data(), 6);
if (receivedCrc != calculatedCrc) {
std::cerr << "CRC check failed" << std::endl;
return false;
}
// Check if the response matches the request
if (responseVec[0] != request[0] || responseVec[1] != request[1] ||
responseVec[2] != request[2] || responseVec[3] != request[3] ||
responseVec[4] != request[4] || responseVec[5] != request[5]) {
std::cerr << "Response does not match the request" << std::endl;
return false;
}
std::cout << "Write single register succeeded" << std::endl;
return true;
}
bool iobox_api::isValidChannelName(const std::string& channelName) {
for (const std::string& name : this->channel_name) {
if (name == channelName) {
return true;
}
}
return false;
}
bool iobox_api::getAllValueIobox(const std::string& ip)
{
iobox_profile_t* profile = findProfileByIp(ip);
if (profile == nullptr) {
std::cerr << "IP address not found: " << ip << std::endl;
return false;
}
if (!getAllDataFromIobox(ip)) {
std::cerr << "Failed to get data from IOBox: " << ip << std::endl;
return false;
}
return true;
}
std::string iobox_api::getValueDataStringIoboxFromChannelName(const std::string& ip, const std::string& channelName) {
if (!isValidChannelName(channelName)) {
std::cerr << "Invalid channel name: " << channelName << std::endl;
return "";
}
if (!getAllValueIobox(ip)) {
std::cerr << "Failed to get all data from IOBox: " << ip << std::endl;
return "";
}
int16_t value_int = 0;
iobox_profile_t* profile = findProfileByIp(ip);
if (profile == nullptr) {
std::cerr << "IP address not found: " << ip << std::endl;
return "";
}
if (channelName == "DO1") {
value_int = profile->iobox_data.channel_DO[0];
}
else if (channelName == "DO2") {
value_int = profile->iobox_data.channel_DO[1];
}
else if (channelName == "DO3") {
value_int = profile->iobox_data.channel_DO[2];
}
else if (channelName == "DO4") {
value_int = profile->iobox_data.channel_DO[3];
}
else if (channelName == "DI1") {
value_int = profile->iobox_data.channel_DI[0];
}
else if (channelName == "DI2") {
value_int = profile->iobox_data.channel_DI[1];
}
else if (channelName == "DI3") {
value_int = profile->iobox_data.channel_DI[2];
}
else if (channelName == "DI4") {
value_int = profile->iobox_data.channel_DI[3];
}
else if (channelName == "AI1") {
value_int = profile->iobox_data.channel_AI[0];
}
else if (channelName == "AI2") {
value_int = profile->iobox_data.channel_AI[1];
}
else {
std::cerr << "Invalid channel name: " << channelName << std::endl;
return "";
}
return std::to_string(value_int);
}
bool iobox_api::setValueDataStringIoboxFromChannelName(const std::string& ip, const std::string& channelName, const std::string& value) {
iobox_profile_t* profile = findProfileByIp(ip);
if (profile == nullptr) {
std::cerr << "IP address not found: " << ip << std::endl;
return false;
}
if (!isValidChannelName(channelName)) {
std::cerr << "Invalid channel name: " << channelName << std::endl;
return false;
}
int channelIndex = -1;
for (channelIndex = 0; channelIndex < IOBOX_CHANNEL_NUM; channelIndex++) {
if (this->channel_name[channelIndex] == channelName) {
break;
}
}
if (channelIndex == -1) {
std::cerr << "Invalid channel name: " << channelName << std::endl;
return false;
}
int16_t value_int = std::stoi(value);
if (!setValueDataToIobox(ip, this->iobox_channel_address[channelIndex], value_int)) {
std::cerr << "Failed to set data to IOBox: " << ip << std::endl;
return false;
}
if (channelName == "DO1") {
profile->iobox_data.channel_DO[0] = value_int;
}
else if (channelName == "DO2") {
profile->iobox_data.channel_DO[1] = value_int;
}
else if (channelName == "DO3") {
profile->iobox_data.channel_DO[2] = value_int;
}
else if (channelName == "DO4") {
profile->iobox_data.channel_DO[3] = value_int;
}
else if (channelName == "DI1") {
profile->iobox_data.channel_DI[0] = value_int;
}
else if (channelName == "DI2") {
profile->iobox_data.channel_DI[1] = value_int;
}
else if (channelName == "DI3") {
profile->iobox_data.channel_DI[2] = value_int;
}
else if (channelName == "DI4") {
profile->iobox_data.channel_DI[3] = value_int;
}
else if (channelName == "AI1") {
profile->iobox_data.channel_AI[0] = value_int;
}
else if (channelName == "AI2") {
profile->iobox_data.channel_AI[1] = value_int;
}
else {
std::cerr << "Invalid channel name: " << channelName << std::endl;
return false;
}
return true;
}
void testGetAllValueFromChannelName(iobox_api& api, const std::string& ip) {
std::vector<std::string> channelNames = { "DO1", "DO2", "DO3", "DO4", "DI1", "DI2", "DI3", "DI4", "AI1", "AI2" };
for (const std::string& channelName : channelNames) {
std::string value = api.getValueDataStringIoboxFromChannelName(ip, channelName);
std::cout << "Channel " << channelName << ": " << value << std::endl;
}
}
bool iobox_api::setAuthenticationIobox(const std::string& ip, const std::string& username, const std::string& password) {
// Todo
// Override default username and password
return true;
}
std::vector<std::string> iobox_api::getDeviceChannelNames(const std::string& ip, int timeout) {
// To do
// Get channel names from IOBox (if available)
std::vector<std::string> channelNames = { "DO1", "DO2", "DO3", "DO4", "DI1", "DI2", "DI3", "DI4", "AI1", "AI2" };
return channelNames;
}
}

View File

@@ -0,0 +1,124 @@
#ifndef _IO_BOX_API_H
#define _IO_BOX_API_H
#define ANSIO_API __declspec(dllexport)
#pragma once
#include "extcode.h"
#include <vector>
#include <string>
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <chrono>
#pragma comment(lib,"WS2_32")
// #pragma comment(lib, "Ws2_32.lib")
// #define TEST_FIX_IP
#define DEVICE_TCP_PORT 502
#define DEVICE_DATA_ADDRESS 100
#define DEVICE_DATA_LENGTH 17
namespace ANSCENTER {
typedef struct {
std::string ip_address;
uint8_t modbus_address;
} iobox_info_t;
typedef union {
/* data */
uint16_t raw_data[DEVICE_DATA_LENGTH];
struct
{
uint16_t modbus_address;
uint8_t serial_number[10];
uint16_t version;
int16_t channel_DO[4];
int16_t channel_DI[4];
int16_t channel_AI[2];
};
} iobox_data_t;
typedef enum {
IOBOX_CHANNEL_DO1 = 0,
IOBOX_CHANNEL_DO2,
IOBOX_CHANNEL_DO3,
IOBOX_CHANNEL_DO4,
IOBOX_CHANNEL_DI1,
IOBOX_CHANNEL_DI2,
IOBOX_CHANNEL_DI3,
IOBOX_CHANNEL_DI4,
IOBOX_CHANNEL_AI1,
IOBOX_CHANNEL_AI2,
IOBOX_CHANNEL_NUM
} iobox_channel_t;
typedef struct {
int counting_get;
bool is_connected;
SOCKET sock_tcp;
iobox_info_t iobox_info;
iobox_data_t iobox_data;
} iobox_profile_t;
class ANSIO_API iobox_api
{
private:
std::string ip_mcast; //ip multicast
int port_mcast; //port multicast
std::string channel_name[IOBOX_CHANNEL_NUM] = {
"DO1", "DO2", "DO3", "DO4",
"DI1", "DI2", "DI3", "DI4",
"AI1", "AI2"
};
uint16_t iobox_channel_address[IOBOX_CHANNEL_NUM] = {
107, 108, 109, 110, 111, 112, 113, 114, 115, 116
};
std::vector<iobox_profile_t> iobox_profiles;
iobox_profile_t* findProfileByIp(const std::string& ip);
void save_info_iobox(iobox_info_t iobox_info);
void setSocketTimeout(SOCKET sock, int timeout);
void sendMulticastMessage(const std::string& message);
bool sendTcpMessage(const std::string& ip, const char* buffer, size_t length);
bool receiveTcpMessage(const std::string& ip, char* buffer, size_t& length);
bool getAllDataFromIobox(const std::string& ip);
bool setValueDataToIobox(const std::string& ip, uint16_t address, uint16_t value);
bool isValidChannelName(const std::string& channelName);
void show_profile_iobox(iobox_profile_t profile);
public:
iobox_api(std::string ip_mcast, int port_mcast);
~iobox_api();
void show_profile_iobox(std::string ip);
void show_profile_ioboxs();
std::vector<std::string> scanNetworkDevicesMulticast(int timeout);
bool setAuthenticationIobox(const std::string& ip, const std::string& username, const std::string& password);
bool resetAuthenticationIobox(const std::string& ip, const std::string& token) { return true; }
bool resetIobox(const std::string& ip, const std::string& token) { return true; }
bool connectToIobox(const std::string& ip, int port, const std::string& username, const std::string& password);
bool disconnectToIobox(const std::string& ip);
std::vector<std::string> getDeviceChannelNames(const std::string& ip,int timeout);
std::string getValueDataStringIoboxFromChannelName(const std::string& ip, const std::string& channelName);
bool setValueDataStringIoboxFromChannelName(const std::string& ip, const std::string& channelName, const std::string& value);
bool getAllValueIobox(const std::string& ip);
};
}
extern "C" ANSIO_API int CreateANSIOHandle(ANSCENTER::iobox_api** Handle, const char* multicastIPAddress, int multicastPort);
extern "C" ANSIO_API int ScanANSIOHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle ipAddresses);
extern "C" ANSIO_API int ConnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord);
extern "C" ANSIO_API int DisconnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP);
extern "C" ANSIO_API int GetChannelNamesANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP,int timeout, LStrHandle channelNames);
extern "C" ANSIO_API int SetValueANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, const char* value);
extern "C" ANSIO_API int GetValueANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, LStrHandle lStrValue);
extern "C" ANSIO_API int SetAuthenticationANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* userName, const char* passWord);
extern "C" ANSIO_API int ReleaseANSIOHandle(ANSCENTER::iobox_api** Handle);
extern "C" ANSIO_API int ResetAuthenticationANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* token);
extern "C" ANSIO_API int ResetANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* token);
// C++ interface
extern "C" ANSIO_API int ScanANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& ipAddresses);
extern "C" ANSIO_API int GetChannelNamesANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int timeout, std::string& channelNames);
extern "C" ANSIO_API int GetValueANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, std::string& lStrValue);
#endif

View File

@@ -0,0 +1,91 @@
#include "iobox_api.h"
#include <thread>
iobox_api ioBoxApp((char*)"239.255.255.250", 12345);
void userInputThread(iobox_api* api) {
std::string current_ip;
while (true) {
std::string input;
std::cout << std::endl;
std::cout << "Enter command followed by Enter: exit, scan, setip, connect, disconnect, show, get, set" << std::endl;
// std::cin >> input; // This will only get the first word
std::getline(std::cin, input);
if (input == "exit") {
break;
}
else if(input == "scan") {
std::vector<std::string> devices = api->scanNetworkDevicesMulticast(5);
std::cout << "Found devices: " << devices.size() << std::endl;
for (const std::string& device : devices) {
std::cout << device << std::endl;
}
continue;
}
else if(input == "setip") {
std::cout << "Enter IP: ";
std::getline(std::cin, current_ip);
continue;
}
else if(input == "connect") {
if(current_ip == "") {
std::cout << "Please setip address first" << std::endl;
continue;
}
bool connect = api->connectToIobox(current_ip, DEVICE_TCP_PORT);
std::cout << "Connection to " << current_ip << (connect ? " succeeded." : " failed.") << std::endl;
continue;
}
else if(input == "disconnect") {
bool disconnect = api->disconnectToIobox(current_ip);
std::cout << "Disconnect to " << current_ip << (disconnect ? " succeeded." : " failed.") << std::endl;
// current_ip = "";
continue;
}
else if(input == "show") {
api->show_profile_ioboxs();
continue;
}
else if(input == "get") {
std::string channel;
std::cout << "Enter channel (\"all\" for get all): ";
std::cin >> channel;
if(channel == "all") {
bool get = api->getAllValueIobox(current_ip);
api->show_profile_iobox(current_ip);
std::cout << "Get all value from " << current_ip << (get ? " succeeded." : " failed.") << std::endl;
} else {
std::string value = api->getValueDataStringIoboxFromChannelName(current_ip, channel);
std::cout << "Value of " << channel << ": " << value << std::endl;
}
continue;
}
else if(input == "set") {
std::string value;
std::string channel;
std::cout << "Enter channel: ";
std::cin >> channel;
std::cout << "Enter value: ";
std::cin >> value;
bool set = api->setValueDataStringIoboxFromChannelName(current_ip, channel, value);
std::cout << "Set value to " << current_ip << (set ? " succeeded." : " failed.") << std::endl;
}
else {
std::cout << "Invalid command" << std::endl;
}
}
}
int main() {
std::thread userThread(userInputThread, &ioBoxApp);
userThread.join();
std::cout << "Main thread is done" << std::endl;
return 0;
}

View File

@@ -0,0 +1,54 @@
### IOBOX API USAGE GUIDE
This document provides an overview and usage instructions for the APIs available in `iobox_api.h`.
#### 1. Api name and features
* Scan
`std::vector<std::string> scanNetworkDevicesMulticast(int timeout);`
API need to be passed a timeout in second unit. The API will return a list of IPs as a vector string.
* Connect
`bool connectToIobox(const std::string& ip, int port); `
Connect to a specific IP device from list of IPs above. Default port is 502.
* Disconnect
`bool disconnectToIobox(const std::string& ip);`
Disconnect to a specific IP device that is connected before
* Get value of channel
`std::string getValueDataStringIoboxFromChannelName(const std::string& ip, const std::string& channelName);`
Get value of specific channel name from a IP device that is connected before.
List of channel name is included in `channel_name` array.
* Set value of channel
`bool setValueDataStringIoboxFromChannelName(const std::string& ip, const std::string& channelName, const std::string& value);`
Set a value of specific channel name from a IP device that is connected before. List of channel name is included in `channel_name` array.
#### 2. How to using example test in main.cpp
You need build this project before run by using g++ compiler
`g++ .\*.cpp -lws2_32 -o main.exe`
Then you need only running `main.exe`.
Start application, it will show
`Enter command followed by Enter: exit, scan, setip, connect, disconnect, show, get, set`
* You type `scan`, it will scan all device iobox on local network then it will list them on terminal attach their IP address if they is found.
* Then type `setip` to setup IP of iobox you need to connect
Then you will be required to input of specific IP address and you need type IP you want.
* Next you type `connect` to connect to this IP device
* Then you can use `get` or `set` command to continue get or set value to any channel.

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

File diff suppressed because one or more lines are too long

3143
IOBox/Backup/v1.1.0/cJSON.c Normal file

File diff suppressed because it is too large Load Diff

300
IOBox/Backup/v1.1.0/cJSON.h Normal file
View File

@@ -0,0 +1,300 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
#endif
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
#define CJSON_CDECL __cdecl
#define CJSON_STDCALL __stdcall
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type CJSON_STDCALL
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
#endif
#else /* !__WINDOWS__ */
#define CJSON_CDECL
#define CJSON_STDCALL
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 18
#include <stddef.h>
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw (1 << 7) /* raw json */
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* The cJSON structure: */
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON *child;
/* The type of the item, as above. */
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string;
} cJSON;
typedef struct cJSON_Hooks
{
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
void *(CJSON_CDECL *malloc_fn)(size_t sz);
void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT
#define CJSON_NESTING_LIMIT 1000
#endif
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
/* Supply malloc, realloc and free functions to cJSON */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
/* These calls create a cJSON item of the appropriate type. */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* Create a string where valuestring references a string so
* it will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
/* Create an object/array that only references it's elements so
* they will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
/* These utilities create an Array of count items.
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
/* Append item to the specified array/object. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
/* Remove/Detach items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
/* Update array items. */
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
* The item->next and ->prev pointers are always zero on return from Duplicate. */
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
* The input pointer json cannot point to a read-only address area, such as a string constant,
* but should point to a readable and writable address area. */
CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Helper functions for creating and adding items to an object at the same time.
* They return the added item or NULL on failure. */
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
#define cJSON_SetBoolValue(object, boolValue) ( \
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
cJSON_Invalid\
)
/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON_Utils__h
#define cJSON_Utils__h
#ifdef __cplusplus
extern "C"
{
#endif
#include "cJSON.h"
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer);
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer);
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to);
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to);
/* Utility for generating patch array entries. */
CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value);
/* Returns 0 for success. */
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches);
CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches);
/*
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
//int cJSONUtils_AtomicApplyPatches(cJSON **object, cJSON *patches)
//{
// cJSON *modme = cJSON_Duplicate(*object, 1);
// int error = cJSONUtils_ApplyPatches(modme, patches);
// if (!error)
// {
// cJSON_Delete(*object);
// *object = modme;
// }
// else
// {
// cJSON_Delete(modme);
// }
//
// return error;
//}
// Code not added to library since this strategy is a LOT slower.
*/
/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
/* target will be modified by patch. return value is new ptr for target. */
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch);
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch);
/* generates a patch to move from -> to */
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to);
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to);
/* Given a root object and a target object, construct a pointer from one to the other. */
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target);
/* Sorts the members of the object into alphabetical order. */
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object);
CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object);
#ifdef __cplusplus
}
#endif
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,101 @@
#ifndef _IO_BOX_API_H_
#define _IO_BOX_API_H_
#define ANSIO_API __declspec(dllexport)
#include "extcode.h"
#include <vector>
#include <string>
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <chrono>
#include <mutex>
#pragma comment(lib,"WS2_32")
// #pragma comment(lib, "Ws2_32.lib")
// #define TEST_FIX_IP
#define DEVICE_TCP_PORT 502
#define DEVICE_DATA_ADDRESS 100
#define DEVICE_DATA_LENGTH 17
namespace ANSCENTER {
typedef struct {
std::string model;
std::string ip_address;
std::string ip_public_address; //public ip
std::string mac_address;
std::string serial_number;
std::string firmware_version;
std::string hardware_version;
std::vector<std::string> channelNameList;
} iobox_info_t;
typedef struct {
int counting_get;
bool is_connected;
bool is_anthenticated;
SOCKET sock_tcp;
iobox_info_t iobox_info;
} iobox_profile_t;
class ANSIO_API iobox_api
{
private:
std::recursive_mutex _mutex;
std::string ip_mcast; //ip multicast
int port_mcast; //port multicast
std::vector<iobox_profile_t> iobox_profiles;
iobox_profile_t* findProfileByIp(const std::string& ip);
void save_info_iobox(iobox_info_t iobox_info);
void setSocketTimeout(SOCKET sock, int timeout);
void sendMulticastMessage(const std::string& message);
bool sendTcpMessage(const std::string& ip, const char* buffer, size_t length, bool needCheckAuthen);
bool receiveTcpMessage(const std::string& ip, char* buffer, size_t& length);
void show_profile_iobox(iobox_profile_t profile);
bool connectToIoboxWithoutAuthen(const std::string& ip, int port);
void remove_last_info_iobox();
uint16_t getIndexIoboxFromIp(const std::string& ip);
public:
iobox_api(std::string ip_mcast, int port_mcast);
~iobox_api();
void show_profile_iobox(std::string ip);
void show_profile_ioboxs();
std::string generateToken(const std::string& ip);
std::vector<std::string> scanNetworkDevicesMulticast(int timeout);
bool setAuthenticationIobox(const std::string& ip, const std::string& username, const std::string& password);
bool resetAuthenticationIobox(const std::string& ip, const std::string& token);
bool resetIobox(const std::string& ip, const std::string& token);
std::string connectToIobox(const std::string& ip, int port, const std::string& username, const std::string& password);
bool disconnectToIobox(const std::string& ip);
std::vector<std::string> getDeviceChannelNames(const std::string& ip);
std::string getValueDataStringIoboxFromChannelName(const std::string& ip, const std::string& channelName);
bool setValueDataStringIoboxFromChannelName(const std::string& ip, const std::string& channelName, const std::string& value);
// RS232
bool openRS232(const std::string& ip, const std::string& port, int baudrate, int databits, int stopbits, int parity);
bool closeRS232(const std::string& ip);
bool writeRS232(const std::string& ip, std::string dataToSend, int timeout);
bool readRS232(const std::string& ip, std::string &receivedData, const std::string& terminateString,int timeout);
bool readRS232Bytes(const std::string& ip, std::string& receivedData, int numBytes, int timeout);
};
}
extern "C" ANSIO_API int CreateANSIOHandle(ANSCENTER::iobox_api** Handle, const char* multicastIPAddress, int multicastPort);
extern "C" ANSIO_API int ScanANSIOHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle ipAddresses);
extern "C" ANSIO_API int ConnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord, LStrHandle deviceStr);
extern "C" ANSIO_API int DisconnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP);
extern "C" ANSIO_API int GetChannelNamesANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int timeout, LStrHandle channelNames);
extern "C" ANSIO_API int SetValueANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, const char* value);
extern "C" ANSIO_API int GetValueANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, LStrHandle lStrValue);
extern "C" ANSIO_API int SetAuthenticationANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* userName, const char* passWord);
extern "C" ANSIO_API int ReleaseANSIOHandle(ANSCENTER::iobox_api** Handle);
extern "C" ANSIO_API int ResetAuthenticationANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* token);
extern "C" ANSIO_API int ResetANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* token);
extern "C" ANSIO_API int GenerateANSIOTokenHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, LStrHandle tokenStr);
// C++ interface
extern "C" ANSIO_API int ScanANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& ipAddresses);
extern "C" ANSIO_API int GetChannelNamesANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int timeout, std::string& channelNames);
extern "C" ANSIO_API int GetValueANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, std::string& lStrValue);
extern "C" ANSIO_API int GenerateANSIOTokenHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, std::string& tokenStr);
extern "C" ANSIO_API int ConnectANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord, std::string& deviceStr);
#endif

View File

@@ -0,0 +1,111 @@
#include "iobox_api.h"
#include <thread>
iobox_api ioBoxApp((char*)"239.255.255.250", 12345);
void userInputThread(iobox_api* api) {
std::string current_ip;
while (true) {
std::string input;
std::cout << std::endl;
std::cout << "Enter command followed by Enter: exit, scan, setip, connect, channels, disconnect, show, get, set, restart, setauthen, resetauthen" << std::endl;
// std::cin >> input; // This will only get the first word
std::getline(std::cin, input);
if (input == "exit") {
break;
}
else if(input == "scan") {
std::vector<std::string> devices = api->scanNetworkDevicesMulticast(5);
std::cout << "Found devices: " << devices.size() << std::endl;
for (const std::string& device : devices) {
std::cout << device << std::endl;
}
continue;
}
else if(input == "setip") {
std::cout << "Enter IP: ";
std::getline(std::cin, current_ip);
continue;
}
else if(input == "connect") {
if(current_ip == "") {
std::cout << "Please setip address first" << std::endl;
continue;
}
std::string username, password;
std::cout << "Enter username: ";
std::cin >> username;
std::cout << "Enter password: ";
std::cin >> password;
bool connect = api->connectToIobox(current_ip, DEVICE_TCP_PORT, username, password);
std::cout << "Connection to " << current_ip << (connect ? " succeeded." : " failed.") << std::endl;
continue;
}
else if(input == "disconnect") {
bool disconnect = api->disconnectToIobox(current_ip);
std::cout << "Disconnect to " << current_ip << (disconnect ? " succeeded." : " failed.") << std::endl;
// current_ip = "";
continue;
}
else if(input == "show") {
api->show_profile_ioboxs();
continue;
}
else if(input == "get") {
std::string channel;
std::cout << "Enter channel: ";
std::cin >> channel;
std::string value = api->getValueDataStringIoboxFromChannelName(current_ip, channel);
std::cout << "Value of " << channel << ": " << value << std::endl;
continue;
}
else if(input == "set") {
std::string value;
std::string channel;
std::cout << "Enter channel: ";
std::cin >> channel;
std::cout << "Enter value: ";
std::cin >> value;
bool set = api->setValueDataStringIoboxFromChannelName(current_ip, channel, value);
std::cout << "Set value to " << current_ip << (set ? " succeeded." : " failed.") << std::endl;
}
else if(input == "restart") {
std::string token = api->generateToken(current_ip);
bool reset = api->resetIobox(current_ip, token);
std::cout << "Restart " << current_ip << (reset ? " succeeded." : " failed.") << std::endl;
}
else if(input == "setauthen") {
std::string username, password;
std::cout << "Enter username: ";
std::cin >> username;
std::cout << "Enter password: ";
std::cin >> password;
bool set = api->setAuthenticationIobox(current_ip, username, password);
std::cout << "Set authentication to " << current_ip << (set ? " succeeded." : " failed.") << std::endl;
}
else if(input == "resetauthen") {
std::string token = api->generateToken(current_ip);
bool reset = api->resetAuthenticationIobox(current_ip, token);
std::cout << "Reset authentication to " << current_ip << (reset ? " succeeded." : " failed.") << std::endl;
}
else if(input == "channels") {
std::vector<std::string> channels = api->getDeviceChannelNames(current_ip);
std::cout << "Channels of " << current_ip << std::endl;
for(const std::string& channel : channels) {
std::cout << channel << std::endl;
}
}
else {
// std::cout << "Invalid command" << std::endl;
}
}
}
int main() {
std::thread userThread(userInputThread, &ioBoxApp);
userThread.join();
std::cout << "Main thread is done" << std::endl;
return 0;
}

View File

@@ -0,0 +1,68 @@
### IOBOX API USAGE GUIDE
This document provides an overview and usage instructions for the APIs available in `iobox_api.h`.
#### 1. Api name and features
* Scan
`std::vector<std::string> scanNetworkDevicesMulticast(int timeout);`
API need to be passed a timeout in second unit. The API will return a list of IPs as a vector string.
* Connect
`bool connectToIobox(const std::string& ip, int port, const std::string& username, const std::string& password);`
Connect to a specific IP device from list of IPs above. Default port is 502
Username and password are param to anthenticate device
* Disconnect
`bool disconnectToIobox(const std::string& ip);`
Disconnect to a specific IP device that is connected before
* Get value of channel
`std::string getValueDataStringIoboxFromChannelName(const std::string& ip, const std::string& channelName);`
Get value of specific channel name from a IP device that is connected before.
List of channel name is obtained from `getDeviceChannelNames` api
* Set value of channel
`bool setValueDataStringIoboxFromChannelName(const std::string& ip, const std::string& channelName, const std::string& value);`
Set a value of specific channel name from a IP device that is connected before. List of channel name is included in `channel_name` array.
* Other api
`bool setAuthenticationIobox(const std::string& ip, const std::string& username, const std::string& password);`
This api to change username and password, this can be only called after a connection to device
`bool resetAuthenticationIobox(const std::string& ip, const std::string& token);`
This api to reset username and password to default
`bool resetIobox(const std::string& ip, const std::string& token);`
This api to restart device
`token` is generated default by using `generateToken` api
#### 2. How to using example test in main.cpp
You need build this project before run by using g++ compiler
`g++ .\*.cpp .\*.c -lws2_32 -o main.exe`
Then you need only running `main.exe`.
Start application, it will show
`Enter command followed by Enter: exit, scan, setip, connect, channels, disconnect, show, get, set, restart, setauthen, resetauthen`
* You type `scan`, it will scan all device iobox on local network then it will list them on terminal attach their IP address if they is found.
* You type `channels` to get name of all of channels that device supports
* Then type `setip` to setup IP of iobox you need to connect
Then you will be required to input of specific IP address and you need type IP you want.
* Next you type `connect` to connect to this IP device
* Then you can use `get` or `set` command to continue get or set value to any channel.
* You can use `setauthen` and `resetauthen` to change usename/password to connect device, and reset usename/password to default (now default in device is: admin/1234)
* You can use `restart` to restart devcie