livoxGen/Proto1: Refine auto-detection vs heuristic logic
This commit is contained in:
@@ -81,7 +81,7 @@ Device::Device(const std::string &deviceIdentifier,
|
||||
""),
|
||||
componentThread(componentThread),
|
||||
handshakeTimeoutMs(handshakeTimeoutMs), retryDelayMs(retryDelayMs),
|
||||
smoIp(smoIp), smoSubnetNbits(smoSubnetNbits),
|
||||
smoIp(smoIp), detectedSmoListeningIp(""), smoSubnetNbits(smoSubnetNbits),
|
||||
dataPort(dataPort), cmdPort(cmdPort), imuPort(imuPort),
|
||||
heartbeatFd(-1),
|
||||
heartbeatActive(false)
|
||||
@@ -136,8 +136,8 @@ public:
|
||||
context->device.heartbeatFd = fd;
|
||||
context->device.startHeartbeat();
|
||||
context->originalCbFn(true);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
@@ -145,7 +145,7 @@ public:
|
||||
<< "identifier" << "\n";
|
||||
}
|
||||
|
||||
// Try direct connect by device identifier
|
||||
// Try direct connect by device identifier
|
||||
context->device.connectByDeviceIdentifierReq(
|
||||
std::bind(&ConnectReq::connectReq2, context.get(), context,
|
||||
std::placeholders::_1, std::placeholders::_2,
|
||||
@@ -286,7 +286,8 @@ void Device::connectToKnownDeviceReq(
|
||||
)
|
||||
{
|
||||
// Create the connection request object to hold state and callbacks
|
||||
auto request = std::make_shared<ConnectToKnownDeviceReq>(*this, std::move(callback));
|
||||
auto request = std::make_shared<ConnectToKnownDeviceReq>(
|
||||
*this, std::move(callback));
|
||||
|
||||
auto& protoState = livoxProto1::getProtoState();
|
||||
if (!protoState.deviceManager)
|
||||
@@ -314,6 +315,30 @@ void Device::connectToKnownDeviceReq(
|
||||
// Use the IP address from the broadcast message
|
||||
request->deviceIP = request->deviceInfo->ipAddr;
|
||||
|
||||
// Determine the final listening IP address
|
||||
auto smoIpResult = request->device.getSmoIp(request->deviceIP);
|
||||
if (!smoIpResult.has_value())
|
||||
{
|
||||
// Auto-detection failed, fail early
|
||||
std::cerr << __func__ << ": Failed to detect SMO listening IP for "
|
||||
<< "known device ("
|
||||
<< request->device.discoveredDevice.deviceIdentifier << ")"
|
||||
<< " @(" << request->deviceIP << ").\n";
|
||||
|
||||
request->callOriginalCallbackWithFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": Detected SMO listening IP for known device "
|
||||
<< request->device.discoveredDevice.deviceIdentifier
|
||||
<< " @(" << request->deviceIP << ") is "
|
||||
<< smoIpResult.value() << ". About to try to handshake.\n";
|
||||
}
|
||||
|
||||
request->device.detectedSmoListeningIp = smoIpResult.value();
|
||||
|
||||
// Execute handshake with the known device using async method
|
||||
request->device.executeHandshakeReq(
|
||||
request->deviceIP,
|
||||
@@ -358,6 +383,24 @@ void Device::connectByDeviceIdentifierReq(
|
||||
Device::connectByDeviceIdentifierReqCbFn callback
|
||||
)
|
||||
{
|
||||
/** EXPLANATION:
|
||||
* This method uses heuristic device IP construction from the serial number.
|
||||
* This requires smoIp to be provided because:
|
||||
* 1. We need the network prefix to generate a valid device IP address
|
||||
* 2. Without a target device IP, we cannot detect which interface faces the device
|
||||
* 3. Therefore, if smoIp is omitted, heuristic construction is impossible
|
||||
*
|
||||
* If smoIp is not provided, the driver must rely only on broadcast advertisements
|
||||
* from the device (handled by connectToKnownDeviceReq).
|
||||
*/
|
||||
|
||||
// Check if smoIp is provided - required for heuristic construction
|
||||
if (smoIp.empty())
|
||||
{
|
||||
callback(false, "", -1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the connection request object to hold state and callbacks
|
||||
auto request = std::make_shared<ConnectByDeviceIdentifierReq>(
|
||||
*this, std::move(callback));
|
||||
@@ -366,6 +409,16 @@ void Device::connectByDeviceIdentifierReq(
|
||||
request->deviceIP = generateClientDeviceIpFromSerialNumber(
|
||||
request->device.discoveredDevice.deviceIdentifier);
|
||||
|
||||
// For heuristic construction, always use the provided smoIp.
|
||||
request->device.detectedSmoListeningIp = request->device.smoIp;
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to try to connect to device by "
|
||||
<< "identifier (" << discoveredDevice.deviceIdentifier << ")"
|
||||
<< " at IP (" << smoIp << ").\n";
|
||||
}
|
||||
|
||||
// Execute handshake using async method
|
||||
request->device.executeHandshakeReq(
|
||||
request->deviceIP,
|
||||
@@ -508,9 +561,9 @@ private:
|
||||
/** EXPLANATION:
|
||||
* Prepare handshake request.
|
||||
*/
|
||||
std::string smoIp = device.getSmoIp(deviceIP);
|
||||
comms::HandshakeRequest handshakeReq(
|
||||
smoIp, device.dataPort, device.cmdPort, device.imuPort);
|
||||
device.detectedSmoListeningIp,
|
||||
device.dataPort, device.cmdPort, device.imuPort);
|
||||
handshakeReq.swapContentsToProtocolEndianness();
|
||||
handshakeReq.header.setCrc16FromRawBytes();
|
||||
handshakeReq.header.swapCrc16ToProtocolEndianness();
|
||||
@@ -764,6 +817,14 @@ void Device::executeHandshakeReq(
|
||||
auto request = std::make_shared<ExecuteHandshakeReq>(
|
||||
*this, deviceIP, std::move(callback));
|
||||
|
||||
// Check if detectedSmoListeningIp is empty - this should not happen
|
||||
if (detectedSmoListeningIp.empty())
|
||||
{
|
||||
// This should not happen as it should be set by the calling method
|
||||
request->callOriginalCallbackWithFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!request->setupSocket())
|
||||
{
|
||||
@@ -1143,25 +1204,42 @@ std::optional<std::string> Device::detectSmoIp(const std::string& deviceIP)
|
||||
}
|
||||
}
|
||||
|
||||
std::string Device::getSmoIp(const std::string& deviceIP)
|
||||
std::optional<std::string> Device::getSmoIp(const std::string& deviceIP)
|
||||
{
|
||||
/** EXPLANATION:
|
||||
* If smo-ip was provided, return it.
|
||||
* Otherwise, try to detect it based on the client device's IP address.
|
||||
* If detection failed, throw an exception.
|
||||
* This is only used when connecting to a device that's already known to
|
||||
* the broadcastListener.
|
||||
* It is NOT and SHOULD not be used when connecting by heuristic IP
|
||||
* construction using the client device's serial number.
|
||||
*
|
||||
* Determines the SMO listening IP address for this device.
|
||||
* If smoIp is provided, validate it against detected IP and return it.
|
||||
* If smoIp is empty, attempt auto-detection based on device IP.
|
||||
* Returns std::optional<std::string> - empty if detection fails.
|
||||
*/
|
||||
if (!smoIp.empty()) {
|
||||
auto detectedIp = detectSmoIp(deviceIP);
|
||||
|
||||
if (!smoIp.empty())
|
||||
{
|
||||
// smoIp was provided, validate it against detected IP
|
||||
if (detectedIp.has_value() && detectedIp.value() != smoIp)
|
||||
{
|
||||
// Print warning if provided smoIp doesn't match detected IP
|
||||
std::cerr << "Warning: Provided smo-ip (" << smoIp
|
||||
<< ") doesn't match detected IP (" << detectedIp.value()
|
||||
<< ") for device " << discoveredDevice.deviceIdentifier
|
||||
<< " @(" << deviceIP << ")"
|
||||
<< ". Using provided smo-ip anyway." << std::endl;
|
||||
}
|
||||
return smoIp;
|
||||
}
|
||||
|
||||
auto detectedIp = detectSmoIp(deviceIP);
|
||||
if (detectedIp.has_value()) {
|
||||
return detectedIp.value();
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
std::string(__func__) + ": Failed to detect SMO IP address for device "
|
||||
+ deviceIP + " with subnet mask /" + std::to_string(smoSubnetNbits));
|
||||
// Auto-detection failed
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace livoxProto1
|
||||
|
||||
Reference in New Issue
Block a user