Loading automotive/can/1.0/tools/libprotocan/Android.bp 0 → 100644 +42 −0 Original line number Diff line number Diff line // // Copyright (C) 2020 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package { // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "hardware_interfaces_license" // to get the below license kinds: // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["hardware_interfaces_license"], } cc_library_static { name: "libprotocan", defaults: ["android.hardware.automotive.vehicle@2.0-protocan-defaults"], vendor: true, srcs: [ "Checksum.cpp", "MessageCounter.cpp", "MessageDef.cpp", "MessageInjector.cpp", "Signal.cpp", ], export_include_dirs: ["include"], shared_libs: [ "android.hardware.automotive.can@1.0", ], } automotive/can/1.0/tools/libprotocan/Checksum.cpp 0 → 100644 +28 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <libprotocan/Checksum.h> namespace android::hardware::automotive::protocan { Checksum::Checksum(Signal signal, formula f) : mSignal(signal), mFormula(f) {} void Checksum::update(can::V1_0::CanMessage& msg) const { mSignal.set(msg, 0); mSignal.set(msg, mFormula(msg) % (mSignal.maxValue + 1)); } } // namespace android::hardware::automotive::protocan automotive/can/1.0/tools/libprotocan/MessageCounter.cpp 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <libprotocan/MessageCounter.h> #include <android-base/logging.h> namespace android::hardware::automotive::protocan { /** Whether to log counter state messages. */ static constexpr bool kSuperVerbose = false; MessageCounter::MessageCounter(Signal signal) : upperBound(signal.maxValue + 1), mSignal(signal) {} Signal::value MessageCounter::next() const { CHECK(mCurrent.has_value()) << "Counter not initialized. Did you call isReady?"; return (*mCurrent + 1) % upperBound; } void MessageCounter::read(const can::V1_0::CanMessage& msg) { auto val = mSignal.get(msg); if (!mCurrent.has_value()) { LOG(VERBOSE) << "Got first counter val of " << val; mCurrent = val; return; } auto nextVal = next(); if (nextVal == val) { if constexpr (kSuperVerbose) { LOG(VERBOSE) << "Got next counter val of " << nextVal; } mCurrent = nextVal; } else { LOG(DEBUG) << "Ignoring next counter val of " << val << ", waiting for " << nextVal; } } bool MessageCounter::isReady() const { return mCurrent.has_value(); } void MessageCounter::increment(can::V1_0::CanMessage& msg) { auto newVal = next(); mCurrent = newVal; mSignal.set(msg, newVal); } } // namespace android::hardware::automotive::protocan automotive/can/1.0/tools/libprotocan/MessageDef.cpp 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <libprotocan/MessageDef.h> #include <android-base/logging.h> namespace android::hardware::automotive::protocan { using can::V1_0::CanMessage; using can::V1_0::CanMessageId; MessageDef::MessageDef(CanMessageId id, uint16_t len, std::map<std::string, Signal> signals, std::optional<Signal> counter, std::optional<Checksum> checksum) : id(id), kLen(len), kSignals(std::move(signals)), kCounter(counter), kChecksum(checksum) {} const Signal& MessageDef::operator[](const std::string& signalName) const { auto it = kSignals.find(signalName); CHECK(it != kSignals.end()) << "Signal " << signalName << " doesn't exist"; return it->second; } CanMessage MessageDef::makeDefault() const { CanMessage msg = {}; msg.id = id; msg.payload.resize(kLen); for (auto const& [name, signal] : kSignals) { signal.setDefault(msg); } return msg; } MessageCounter MessageDef::makeCounter() const { CHECK(kCounter.has_value()) << "Can't build a counter for message without such signal"; return MessageCounter(*kCounter); } void MessageDef::updateChecksum(can::V1_0::CanMessage& msg) const { if (!kChecksum.has_value()) return; kChecksum->update(msg); } bool MessageDef::validate(const can::V1_0::CanMessage& msg) const { return msg.payload.size() >= kLen; } } // namespace android::hardware::automotive::protocan automotive/can/1.0/tools/libprotocan/MessageInjector.cpp 0 → 100644 +110 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <libprotocan/MessageInjector.h> #include <android-base/logging.h> #include <thread> namespace android::hardware::automotive::protocan { /** Whether to log injected messages. */ static constexpr bool kSuperVerbose = true; using namespace std::literals::chrono_literals; using can::V1_0::CanMessage; using can::V1_0::CanMessageId; using can::V1_0::ICanBus; using can::V1_0::Result; MessageInjector::MessageInjector(MessageDef msgDef, std::optional<std::chrono::milliseconds> interMessageDelay) : kMsgDef(std::move(msgDef)), kInterMessageDelay(interMessageDelay), mCounter(msgDef.makeCounter()) {} void MessageInjector::inject(const CanMessage& msg) { inject({msg}); } void MessageInjector::inject(const std::initializer_list<can::V1_0::CanMessage> msgs) { std::lock_guard<std::mutex> lock(mMessagesGuard); for (const auto& msg : msgs) { if constexpr (kSuperVerbose) { LOG(VERBOSE) << "Message scheduled for injection: " << toString(msg); } mMessages.push(msg); } } void MessageInjector::processQueueLocked(can::V1_0::ICanBus& bus) { if (mMessages.empty() || !mCounter.isReady()) return; auto paddingMessagesCount = mCounter.upperBound - (mMessages.size() % mCounter.upperBound); auto padMessage = kMsgDef.makeDefault(); for (unsigned i = 0; i < paddingMessagesCount; i++) { mMessages.push(padMessage); } while (!mMessages.empty()) { auto&& outMsg = mMessages.front(); mCounter.increment(outMsg); kMsgDef.updateChecksum(outMsg); if constexpr (kSuperVerbose) { LOG(VERBOSE) << "Injecting message: " << toString(outMsg); } auto result = bus.send(outMsg); if (result != Result::OK) { LOG(ERROR) << "Message injection failed: " << toString(result); } mMessages.pop(); // This would block onReceive, but the class is not supposed to be used in production anyway // (see MessageInjector docstring). if (kInterMessageDelay.has_value()) { std::this_thread::sleep_for(*kInterMessageDelay); } } } void MessageInjector::onReceive(ICanBus& bus, const CanMessage& msg) { if (!kMsgDef.validate(msg)) return; std::lock_guard<std::mutex> lock(mMessagesGuard); mCounter.read(msg); processQueueLocked(bus); } MessageInjectorManager::MessageInjectorManager( std::initializer_list<std::shared_ptr<MessageInjector>> injectors) { std::transform(injectors.begin(), injectors.end(), std::inserter(mInjectors, mInjectors.end()), [](const std::shared_ptr<MessageInjector>& injector) { return std::make_pair(injector->kMsgDef.id, std::move(injector)); }); } void MessageInjectorManager::onReceive(sp<ICanBus> bus, const CanMessage& msg) { auto it = mInjectors.find(msg.id); if (it == mInjectors.end()) return; it->second->onReceive(*bus, msg); } } // namespace android::hardware::automotive::protocan Loading
automotive/can/1.0/tools/libprotocan/Android.bp 0 → 100644 +42 −0 Original line number Diff line number Diff line // // Copyright (C) 2020 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // package { // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "hardware_interfaces_license" // to get the below license kinds: // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["hardware_interfaces_license"], } cc_library_static { name: "libprotocan", defaults: ["android.hardware.automotive.vehicle@2.0-protocan-defaults"], vendor: true, srcs: [ "Checksum.cpp", "MessageCounter.cpp", "MessageDef.cpp", "MessageInjector.cpp", "Signal.cpp", ], export_include_dirs: ["include"], shared_libs: [ "android.hardware.automotive.can@1.0", ], }
automotive/can/1.0/tools/libprotocan/Checksum.cpp 0 → 100644 +28 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <libprotocan/Checksum.h> namespace android::hardware::automotive::protocan { Checksum::Checksum(Signal signal, formula f) : mSignal(signal), mFormula(f) {} void Checksum::update(can::V1_0::CanMessage& msg) const { mSignal.set(msg, 0); mSignal.set(msg, mFormula(msg) % (mSignal.maxValue + 1)); } } // namespace android::hardware::automotive::protocan
automotive/can/1.0/tools/libprotocan/MessageCounter.cpp 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <libprotocan/MessageCounter.h> #include <android-base/logging.h> namespace android::hardware::automotive::protocan { /** Whether to log counter state messages. */ static constexpr bool kSuperVerbose = false; MessageCounter::MessageCounter(Signal signal) : upperBound(signal.maxValue + 1), mSignal(signal) {} Signal::value MessageCounter::next() const { CHECK(mCurrent.has_value()) << "Counter not initialized. Did you call isReady?"; return (*mCurrent + 1) % upperBound; } void MessageCounter::read(const can::V1_0::CanMessage& msg) { auto val = mSignal.get(msg); if (!mCurrent.has_value()) { LOG(VERBOSE) << "Got first counter val of " << val; mCurrent = val; return; } auto nextVal = next(); if (nextVal == val) { if constexpr (kSuperVerbose) { LOG(VERBOSE) << "Got next counter val of " << nextVal; } mCurrent = nextVal; } else { LOG(DEBUG) << "Ignoring next counter val of " << val << ", waiting for " << nextVal; } } bool MessageCounter::isReady() const { return mCurrent.has_value(); } void MessageCounter::increment(can::V1_0::CanMessage& msg) { auto newVal = next(); mCurrent = newVal; mSignal.set(msg, newVal); } } // namespace android::hardware::automotive::protocan
automotive/can/1.0/tools/libprotocan/MessageDef.cpp 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <libprotocan/MessageDef.h> #include <android-base/logging.h> namespace android::hardware::automotive::protocan { using can::V1_0::CanMessage; using can::V1_0::CanMessageId; MessageDef::MessageDef(CanMessageId id, uint16_t len, std::map<std::string, Signal> signals, std::optional<Signal> counter, std::optional<Checksum> checksum) : id(id), kLen(len), kSignals(std::move(signals)), kCounter(counter), kChecksum(checksum) {} const Signal& MessageDef::operator[](const std::string& signalName) const { auto it = kSignals.find(signalName); CHECK(it != kSignals.end()) << "Signal " << signalName << " doesn't exist"; return it->second; } CanMessage MessageDef::makeDefault() const { CanMessage msg = {}; msg.id = id; msg.payload.resize(kLen); for (auto const& [name, signal] : kSignals) { signal.setDefault(msg); } return msg; } MessageCounter MessageDef::makeCounter() const { CHECK(kCounter.has_value()) << "Can't build a counter for message without such signal"; return MessageCounter(*kCounter); } void MessageDef::updateChecksum(can::V1_0::CanMessage& msg) const { if (!kChecksum.has_value()) return; kChecksum->update(msg); } bool MessageDef::validate(const can::V1_0::CanMessage& msg) const { return msg.payload.size() >= kLen; } } // namespace android::hardware::automotive::protocan
automotive/can/1.0/tools/libprotocan/MessageInjector.cpp 0 → 100644 +110 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <libprotocan/MessageInjector.h> #include <android-base/logging.h> #include <thread> namespace android::hardware::automotive::protocan { /** Whether to log injected messages. */ static constexpr bool kSuperVerbose = true; using namespace std::literals::chrono_literals; using can::V1_0::CanMessage; using can::V1_0::CanMessageId; using can::V1_0::ICanBus; using can::V1_0::Result; MessageInjector::MessageInjector(MessageDef msgDef, std::optional<std::chrono::milliseconds> interMessageDelay) : kMsgDef(std::move(msgDef)), kInterMessageDelay(interMessageDelay), mCounter(msgDef.makeCounter()) {} void MessageInjector::inject(const CanMessage& msg) { inject({msg}); } void MessageInjector::inject(const std::initializer_list<can::V1_0::CanMessage> msgs) { std::lock_guard<std::mutex> lock(mMessagesGuard); for (const auto& msg : msgs) { if constexpr (kSuperVerbose) { LOG(VERBOSE) << "Message scheduled for injection: " << toString(msg); } mMessages.push(msg); } } void MessageInjector::processQueueLocked(can::V1_0::ICanBus& bus) { if (mMessages.empty() || !mCounter.isReady()) return; auto paddingMessagesCount = mCounter.upperBound - (mMessages.size() % mCounter.upperBound); auto padMessage = kMsgDef.makeDefault(); for (unsigned i = 0; i < paddingMessagesCount; i++) { mMessages.push(padMessage); } while (!mMessages.empty()) { auto&& outMsg = mMessages.front(); mCounter.increment(outMsg); kMsgDef.updateChecksum(outMsg); if constexpr (kSuperVerbose) { LOG(VERBOSE) << "Injecting message: " << toString(outMsg); } auto result = bus.send(outMsg); if (result != Result::OK) { LOG(ERROR) << "Message injection failed: " << toString(result); } mMessages.pop(); // This would block onReceive, but the class is not supposed to be used in production anyway // (see MessageInjector docstring). if (kInterMessageDelay.has_value()) { std::this_thread::sleep_for(*kInterMessageDelay); } } } void MessageInjector::onReceive(ICanBus& bus, const CanMessage& msg) { if (!kMsgDef.validate(msg)) return; std::lock_guard<std::mutex> lock(mMessagesGuard); mCounter.read(msg); processQueueLocked(bus); } MessageInjectorManager::MessageInjectorManager( std::initializer_list<std::shared_ptr<MessageInjector>> injectors) { std::transform(injectors.begin(), injectors.end(), std::inserter(mInjectors, mInjectors.end()), [](const std::shared_ptr<MessageInjector>& injector) { return std::make_pair(injector->kMsgDef.id, std::move(injector)); }); } void MessageInjectorManager::onReceive(sp<ICanBus> bus, const CanMessage& msg) { auto it = mInjectors.find(msg.id); if (it == mInjectors.end()) return; it->second->onReceive(*bus, msg); } } // namespace android::hardware::automotive::protocan