// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include #include #include #include #include namespace hal::battery { namespace { constexpr auto batteryFIFO = "/tmp/fifoBattKeys"; constexpr auto fifoFileAccessRights = 0666; constexpr auto fifoBuffSize = 10; constexpr auto queueTimeoutTicks = 100; constexpr auto taskDelay = 50; constexpr auto dummyBatteryVoltageLevel = 3700; constexpr auto chargerPlugStateChange = 'p'; constexpr auto batteryLevelUp = ']'; constexpr auto batteryLevelDown = '['; constexpr auto chargerTypeDcdSDP = 'l'; constexpr auto chargerTypeDcdCDP = ';'; constexpr auto chargerTypeDcdDCP = '\''; } // namespace class BatteryCharger : public AbstractBatteryCharger { public: explicit BatteryCharger(xQueueHandle irqQueueHandle); ~BatteryCharger(); Voltage getBatteryVoltage() const final; std::optional getSOC() const final; ChargingStatus getChargingStatus() const final; private: void worker(); xQueueHandle notificationChannel = nullptr; TaskHandle_t batteryWorkerHandle = nullptr; unsigned batteryLevel = 100; bool isPlugged = false; bool shouldRun = true; }; BatteryCharger::BatteryCharger(xQueueHandle irqQueueHandle) { notificationChannel = irqQueueHandle; xTaskCreate( [](void *pvp) { BatteryCharger *inst = static_cast(pvp); inst->worker(); }, "battery", 512, this, 0, &batteryWorkerHandle); } BatteryCharger::~BatteryCharger() { shouldRun = false; /// The worker operates in taskDelay intervals. Give it at least taskDelay to handle the close procedure. vTaskDelay(taskDelay * 2); } AbstractBatteryCharger::Voltage BatteryCharger::getBatteryVoltage() const { return dummyBatteryVoltageLevel; } std::optional BatteryCharger::getSOC() const { return batteryLevel; } AbstractBatteryCharger::ChargingStatus BatteryCharger::getChargingStatus() const { if (isPlugged && batteryLevel >= 100) { return ChargingStatus::ChargingDone; } else if (isPlugged && batteryLevel < 100) { return ChargingStatus::Charging; } else { return ChargingStatus::Discharging; } } void BatteryCharger::worker() { mkfifo(batteryFIFO, fifoFileAccessRights); // Open FIFO for write only int fd = open(batteryFIFO, O_RDONLY | O_NONBLOCK); while (shouldRun) { std::uint8_t buff[fifoBuffSize]; std::int32_t readBytes = read(fd, buff, fifoBuffSize); if (readBytes > 0) { Events evt{}; switch (static_cast(buff[0])) { case chargerPlugStateChange: isPlugged = !isPlugged; evt = Events::Charger; break; case batteryLevelUp: batteryLevel++; evt = Events::SOC; break; case batteryLevelDown: batteryLevel--; evt = Events::SOC; break; case chargerTypeDcdSDP: case chargerTypeDcdCDP: case chargerTypeDcdDCP: evt = Events::Charger; break; default: continue; } xQueueSend(notificationChannel, &evt, queueTimeoutTicks); } vTaskDelay(taskDelay); } close(fd); vTaskDelete(nullptr); } std::unique_ptr AbstractBatteryCharger::Factory::create(xQueueHandle irqQueueHandle) { return std::make_unique(irqQueueHandle); } } // namespace hal::battery