Device: WiVI: Add VIN support
parent
ec350b522a
commit
99a2ca4f0d
|
|
@ -31,24 +31,46 @@ std::shared_ptr<WiVI::ResponseMessage> WiVI::CommandPacket::DecodeToMessage(cons
|
|||
break;
|
||||
}
|
||||
case WiVI::Command::GetAll: {
|
||||
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAll))
|
||||
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAllHeader))
|
||||
return {};
|
||||
|
||||
const auto& getAll = *reinterpret_cast<const WiVI::CommandPacket::GetAll*>(bytestream.data());
|
||||
const auto& getAll = *reinterpret_cast<const WiVI::CommandPacket::GetAllHeader*>(bytestream.data());
|
||||
msg->responseTo = WiVI::Command::GetAll;
|
||||
msg->info.emplace();
|
||||
msg->info->sleepRequest = getAll.sleepRequest;
|
||||
msg->info->connectionTimeoutMinutes = getAll.connectionTimeoutMinutes;
|
||||
|
||||
// Check that we have enough data for the capture infos
|
||||
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAll) + (sizeof(WiVI::CaptureInfo) * getAll.numCaptureInfos))
|
||||
size_t captureInfosSize = sizeof(WiVI::CaptureInfo) * getAll.numCaptureInfos;
|
||||
if(bytestream.size() < sizeof(WiVI::CommandPacket::GetAllHeader) + captureInfosSize)
|
||||
return {};
|
||||
|
||||
const WiVI::CaptureInfo* const captureInfos = (const WiVI::CaptureInfo*)(bytestream.data() + sizeof(WiVI::CommandPacket::GetAllHeader));
|
||||
msg->info->captures.resize(getAll.numCaptureInfos);
|
||||
for(uint16_t i = 0; i < getAll.numCaptureInfos; i++)
|
||||
msg->info->captures[i] = getAll.captureInfos[i];
|
||||
msg->info->captures[i] = captureInfos[i];
|
||||
|
||||
|
||||
// New field vinAvail was added - check if it is present:
|
||||
if(bytestream.size() >= sizeof(WiVI::CommandPacket::GetAllHeader) + captureInfosSize + 2) {
|
||||
msg->info->vinAvailable = *(bytestream.data() + sizeof(WiVI::CommandPacket::GetAllHeader) + captureInfosSize);
|
||||
} else {
|
||||
msg->info->vinAvailable = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WiVI::Command::GetVIN: {
|
||||
if (bytestream.size() < sizeof(WiVI::CommandPacket::GetVIN))
|
||||
return {};
|
||||
|
||||
const auto& getVIN = *reinterpret_cast<const WiVI::CommandPacket::GetVIN*>(bytestream.data());
|
||||
msg->responseTo = WiVI::Command::GetVIN;
|
||||
msg->vin = getVIN.VIN;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: // Unknown command response
|
||||
return {};
|
||||
}
|
||||
|
|
@ -78,9 +100,9 @@ std::vector<uint8_t> WiVI::CommandPacket::SetSignal::Encode(WiVI::SignalType typ
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> WiVI::CommandPacket::GetAll::Encode() {
|
||||
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::GetAll));
|
||||
auto& frame = *reinterpret_cast<WiVI::CommandPacket::GetAll*>(ret.data());
|
||||
std::vector<uint8_t> WiVI::CommandPacket::GetAllHeader::Encode() {
|
||||
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::GetAllHeader));
|
||||
auto& frame = *reinterpret_cast<WiVI::CommandPacket::GetAllHeader*>(ret.data());
|
||||
|
||||
frame.header.cmd = WiVI::Command::GetAll;
|
||||
frame.header.length = sizeof(frame) - sizeof(frame.header);
|
||||
|
|
@ -98,3 +120,15 @@ std::vector<uint8_t> WiVI::CommandPacket::ClearUploads::Encode(const std::vector
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> WiVI::CommandPacket::GetVIN::Encode()
|
||||
{
|
||||
std::vector<uint8_t> ret(sizeof(WiVI::CommandPacket::GetVIN));
|
||||
auto& frame = *reinterpret_cast<WiVI::CommandPacket::GetVIN*>(ret.data());
|
||||
|
||||
frame.header.cmd = WiVI::Command::GetVIN;
|
||||
frame.header.length = sizeof(frame) - sizeof(frame.header);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1178,7 +1178,7 @@ void Device::wiviThreadBody() {
|
|||
|
||||
// Use the command GetAll to get a WiVI::Info structure from the device
|
||||
const auto generic = com->waitForMessageSync([this]() {
|
||||
return com->sendCommand(Command::WiVICommand, WiVI::CommandPacket::GetAll::Encode());
|
||||
return com->sendCommand(Command::WiVICommand, WiVI::CommandPacket::GetAllHeader::Encode());
|
||||
}, filter, std::chrono::milliseconds(1000));
|
||||
|
||||
if(!generic || generic->type != Message::Type::WiVICommandResponse) {
|
||||
|
|
@ -1290,6 +1290,22 @@ void Device::wiviThreadBody() {
|
|||
for(auto& cb : sleepRequestedCallbacks)
|
||||
cb.second = false;
|
||||
}
|
||||
|
||||
// Process vin available callbacks
|
||||
if (resp->info->vinAvailable & 1) {
|
||||
for (auto& cb : vinAvailableCallbacks) {
|
||||
if (!cb.second && cb.first) {
|
||||
cb.second = true;
|
||||
lk.unlock();
|
||||
try {
|
||||
cb.first();
|
||||
} catch(...) {
|
||||
report(APIEvent::Type::Unknown, APIEvent::Severity::Error);
|
||||
}
|
||||
lk.lock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1464,6 +1480,110 @@ bool Device::allowSleep(bool remoteWakeup) {
|
|||
return true;
|
||||
}
|
||||
|
||||
Lifetime Device::addVINAvailableCallback(VINAvailableCallback cb)
|
||||
{
|
||||
if(!isOpen()) {
|
||||
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||
return {};
|
||||
}
|
||||
|
||||
if(!supportsWiVI()) {
|
||||
report(APIEvent::Type::WiVINotSupported, APIEvent::Severity::Error);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lk(wiviMutex);
|
||||
if(!wiviThread.joinable()) {
|
||||
// Start the thread
|
||||
stopWiVIThread = false;
|
||||
wiviThread = std::thread([this]() { wiviThreadBody(); });
|
||||
}
|
||||
|
||||
size_t idx = 0;
|
||||
for(; idx < vinAvailableCallbacks.size(); idx++) {
|
||||
if(!vinAvailableCallbacks[idx].first) // Empty space (previously erased callback)
|
||||
break;
|
||||
}
|
||||
|
||||
if(idx == vinAvailableCallbacks.size()) // Create a new space
|
||||
vinAvailableCallbacks.emplace_back(std::move(cb), false);
|
||||
else
|
||||
vinAvailableCallbacks[idx] = { std::move(cb), false };
|
||||
|
||||
// Cleanup function to remove this sleep requested callback
|
||||
return Lifetime([this, idx]() {
|
||||
// TODO: Hold a weak ptr to the `this` instead of relying on the user to keep `this` valid
|
||||
std::unique_lock<std::mutex> lk2(wiviMutex);
|
||||
vinAvailableCallbacks[idx].first = VINAvailableCallback();
|
||||
stopWiVIThreadIfNecessary(std::move(lk2));
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<bool> Device::isVINEnabled() const
|
||||
{
|
||||
if(!isOpen()) {
|
||||
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(!supportsWiVI()) {
|
||||
report(APIEvent::Type::WiVINotSupported, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::WiVICommandResponse);
|
||||
// Hold this lock so the WiVI stack doesn't issue a WiVICommand at the same time as us
|
||||
std::lock_guard<std::mutex> lk(wiviMutex);
|
||||
const auto generic = com->waitForMessageSync([this]() {
|
||||
return com->sendCommand(Command::WiVICommand, WiVI::CommandPacket::GetSignal::Encode(WiVI::SignalType::VINEnabled));
|
||||
}, filter, std::chrono::milliseconds(1000));
|
||||
|
||||
if(!generic || generic->type != Message::Type::WiVICommandResponse) {
|
||||
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto resp = std::static_pointer_cast<WiVI::ResponseMessage>(generic);
|
||||
if(!resp->success || !resp->value.has_value()) {
|
||||
report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *resp->value;
|
||||
}
|
||||
|
||||
std::optional<std::string> Device::getVIN() const
|
||||
{
|
||||
if(!isOpen()) {
|
||||
report(APIEvent::Type::DeviceCurrentlyClosed, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(!supportsWiVI()) {
|
||||
report(APIEvent::Type::WiVINotSupported, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static std::shared_ptr<MessageFilter> filter = std::make_shared<MessageFilter>(Message::Type::WiVICommandResponse);
|
||||
std::lock_guard<std::mutex> lk(wiviMutex);
|
||||
const auto generic = com->waitForMessageSync([this]() {
|
||||
return com->sendCommand(Command::WiVICommand, WiVI::CommandPacket::GetVIN::Encode());
|
||||
}, filter, std::chrono::milliseconds(1000));
|
||||
|
||||
if(!generic || generic->type != Message::Type::WiVICommandResponse) {
|
||||
report(APIEvent::Type::NoDeviceResponse, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto resp = std::static_pointer_cast<WiVI::ResponseMessage>(generic);
|
||||
if(!resp->success || !resp->vin.has_value()) {
|
||||
report(APIEvent::Type::ValueNotYetPresent, APIEvent::Severity::Error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *resp->vin;
|
||||
}
|
||||
|
||||
void Device::scriptStatusThreadBody()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(scriptStatusMutex);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ struct Info {
|
|||
uint8_t sleepRequest;
|
||||
uint16_t connectionTimeoutMinutes;
|
||||
std::vector<CaptureInfo> captures;
|
||||
uint8_t vinAvailable;
|
||||
};
|
||||
|
||||
// The response for Command::WiVICommand
|
||||
|
|
@ -27,6 +28,7 @@ public:
|
|||
std::optional<Command> responseTo;
|
||||
std::optional<int32_t> value;
|
||||
std::optional<Info> info;
|
||||
std::optional<std::string> vin;
|
||||
};
|
||||
|
||||
} // namespace WiVI
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ enum class Command : uint16_t {
|
|||
GetSignal = 0x0013,
|
||||
Result = 0x0014,
|
||||
GetPhysicalSignal = 0x0015,
|
||||
GetVIN = 0x0016,
|
||||
};
|
||||
|
||||
enum class SignalType : uint16_t { // enumCoreMiniValueMiscValueType
|
||||
|
|
@ -66,6 +67,7 @@ enum class SignalType : uint16_t { // enumCoreMiniValueMiscValueType
|
|||
ConnectionTimeout = 0x006e,
|
||||
TimeSinceLastMessageMs = 0x006f,
|
||||
UploadsPending = 0x0077,
|
||||
VINEnabled = 0x007D,
|
||||
};
|
||||
|
||||
struct Upload {
|
||||
|
|
@ -125,7 +127,7 @@ struct CommandPacket {
|
|||
CoreMiniFixedPointValue value;
|
||||
};
|
||||
|
||||
struct GetAll {
|
||||
struct GetAllHeader {
|
||||
static std::vector<uint8_t> Encode();
|
||||
|
||||
Header header;
|
||||
|
|
@ -133,7 +135,6 @@ struct CommandPacket {
|
|||
uint8_t sleepRequest;
|
||||
uint16_t connectionTimeoutMinutes;
|
||||
uint16_t numCaptureInfos;
|
||||
CaptureInfo captureInfos[0];
|
||||
};
|
||||
|
||||
struct ClearUploads {
|
||||
|
|
@ -142,6 +143,13 @@ struct CommandPacket {
|
|||
Header header;
|
||||
uint8_t bitmask[0];
|
||||
};
|
||||
|
||||
struct GetVIN {
|
||||
static std::vector<uint8_t> Encode();
|
||||
|
||||
Header header;
|
||||
char VIN[17];
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace WiVI
|
||||
|
|
|
|||
|
|
@ -568,6 +568,12 @@ public:
|
|||
NODISCARD("If the Lifetime is not held, the callback will be immediately removed")
|
||||
Lifetime addLoggingCallback(ScriptStatusCallback cb) { return addScriptStatusCallback(ScriptStatus::Logging, std::move(cb)); }
|
||||
|
||||
typedef std::function<void(void)> VINAvailableCallback;
|
||||
NODISCARD("If the Lifetime is not held, the callback will be immediately removed")
|
||||
Lifetime addVINAvailableCallback(VINAvailableCallback cb);
|
||||
std::optional<bool> isVINEnabled() const;
|
||||
std::optional<std::string> getVIN() const;
|
||||
|
||||
virtual std::vector<std::shared_ptr<FlexRay::Controller>> getFlexRayControllers() const { return {}; }
|
||||
|
||||
void addExtension(std::shared_ptr<DeviceExtension>&& extension);
|
||||
|
|
@ -931,6 +937,7 @@ private:
|
|||
std::atomic<bool> wiviSleepRequested{false};
|
||||
std::vector<NewCaptureCallback> newCaptureCallbacks;
|
||||
std::vector< std::pair<SleepRequestedCallback, bool /* notified */> > sleepRequestedCallbacks;
|
||||
std::vector<std::pair<VINAvailableCallback, bool /* notified */>> vinAvailableCallbacks;
|
||||
void wiviThreadBody();
|
||||
void stopWiVIThreadIfNecessary(std::unique_lock<std::mutex> lk);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue