CLSH1001-Firmware/main/main.cpp

495 lines
16 KiB
C++
Raw Normal View History

2024-03-06 06:09:49 +08:00
// I2C设置
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C0_NUM I2C_NUM_0
#define I2C0_SCL_IO 42
#define I2C0_SDA_IO 41
#define I2C0_FREQ_HZ 40000
#define I2C_MASTER_TIMEOUT_MS 14000
#define SW7203_ADDR 0x3C
#include <cstdlib>
#include <iostream>
#include <string>
#include "driver/i2c.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "bq4050.h"
#include "gpio_cxx.hpp"
#include "driver/gpio.h"
#include <thread>
using namespace std;
using namespace idf;
#define SetBitTrue(a, b) a |= (1 << b)
#define SetBitFalse(a, b) a &= ~(1 << b)
#define GetBit(a, b) a & (1 << b)
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_INOUT_DESC_LEN)
#define ITF_NUM_TOTAL 1
static esp_err_t bq4050_i2c_master_init()
{
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = BQ4050_I2C_MASTER_SDA_IO,
.scl_io_num = BQ4050_I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master{
.clk_speed = BQ4050_I2C_MASTER_FREQ_HZ},
};
BQ4050::I2C_MASTER = BQ4050_I2C_MASTER_NUM;
BQ4050::I2C_MASTER_TIMEOUT = BQ4050_I2C_MASTER_TIMEOUT_MS;
i2c_param_config(BQ4050_I2C_MASTER_NUM, &conf);
return i2c_driver_install(BQ4050_I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
static esp_err_t sw7203_i2c_master_init()
{
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = SW7203_I2C_MASTER_SDA_IO,
.scl_io_num = SW7203_I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master{
.clk_speed = SW7203_I2C_MASTER_FREQ_HZ},
};
i2c_param_config(SW7203_I2C_MASTER_NUM, &conf);
return i2c_driver_install(SW7203_I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
esp_err_t sw7203_register_read(uint8_t reg_addr, uint8_t *data)
{
return i2c_master_write_read_device(SW7203_I2C_MASTER_NUM, SW7203_ADDR, &reg_addr, 1, data, 1, SW7203_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}
esp_err_t sw7203_register_write(uint8_t *data)
{
return i2c_master_write_to_device(SW7203_I2C_MASTER_NUM, SW7203_ADDR, data, 2, SW7203_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
}
void sw7203_check_error(esp_err_t errcode)
{
if (errcode != ESP_OK)
{
ESP_LOGI(TAG, "SW7203 I2C error\n:)");
ESP_ERROR_CHECK_WITHOUT_ABORT(err_code);
while (1)
{
ErrLED.set_high();
vTaskDelay(100 / portTICK_PERIOD_MS);
ErrLED.set_low();
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
}
#ifndef __SW7203_DEBUG__
void sw7203_start_charge()
{
unsigned int VBUS_Voltage = 0;
uint8_t data = 0;
sw7203_check_error(sw7203_register_read(0x11, &data));
VBUS_Voltage = data;
VBUS_Voltage = VBUS_Voltage << 4;
sw7203_check_error(sw7203_register_read(0x12, &data));
VBUS_Voltage &= (data & 0b00001111);
VBUS_Voltage *= 75;
VBUS_Voltage -= 7500;
VBUS_Voltage = (VBUS_Voltage - 40000) / 1000;
uint8_t VBUS_BitMask = 0b01111111, VBUS_Limit = VBUS_Voltage;
uint8_t cmd[3][2] = {{0x38, uint8_t(VBUS_Limit & VBUS_BitMask)}, {0x19, 0b00000100}, {0x0D, 0b00010000}};
sw7203_register_write(cmd[0]);
sw7203_register_write(cmd[1]);
sw7203_register_write(cmd[2]);
}
void sw7203_stop_charge()
{
uint8_t cmd[2][2] = {{0x04, 0b00000100}, {0x19, 0b00000000}};
sw7203_register_write(cmd[0]);
sw7203_register_write(cmd[1]);
}
void sw7203_irq_func(void *arg)
{
while (1)
{
if (gpio_get_level(GPIO_NUM_47) == 1)
{
ESP_LOGI(TAG, "SW 7203 INT ARG");
uint8_t data = 0;
sw7203_check_error(sw7203_register_read(0x04, &data));
if (data & 0x40)
{
ESP_LOGI(TAG, "VSYS voltage limit exceeded");
}
if (data & 0x20)
{
ESP_LOGI(TAG, "Battery charge time limit exceeded");
}
if (data & 0x10)
{
ESP_LOGI(TAG, "Battery fullcharged");
}
if (data & 0x08)
{
ESP_LOGI(TAG, "DCIN moved in");
AC_IN = true;
vTaskDelay(100 / portTICK_PERIOD_MS);
sw7203_start_charge();
}
if (data & 0x04)
{
ESP_LOGI(TAG, "DCIN moved out");
AC_IN = false;
sw7203_stop_charge();
}
sw7203_check_error(sw7203_register_read(0x05, &data));
if (data & 0x80)
{
ESP_LOGI(TAG, "SW7203 over temperature");
}
if (data & 0x10)
{
ESP_LOGI(TAG, "VBAT voltage limit exceeded");
}
if (data & 0x08)
{
ESP_LOGI(TAG, "VBAT voltage limit subceeded");
}
if (data & 0x01)
{
ESP_LOGI(TAG, "VBUS power limit exceeded");
}
sw7203_check_error(sw7203_register_read(0x06, &data));
if (data & 0x02)
{
NVDC_BAT_charge = true;
}
else
{
NVDC_BAT_charge = false;
}
uint8_t cmd[2][2] = {{0x04, 0b11111111}, {0x05, 0b11111111}};
sw7203_register_write(cmd[0]);
sw7203_register_write(cmd[1]);
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
#endif
extern "C" void app_main()
{
ErrLED.set_high();
#ifdef __USB_HID_ENABLE__
ESP_LOGI(TAG, "USB initialization");
const tinyusb_config_t tusb_cfg = {
.device_descriptor = &descriptor_config,
.string_descriptor = string_descriptor,
.string_descriptor_count = sizeof(string_descriptor) / sizeof(string_descriptor[0]),
.external_phy = false,
.configuration_descriptor = desc_configuration,
.self_powered = false,
};
if ((err_code = tinyusb_driver_install(&tusb_cfg)) != ESP_OK)
{
ESP_LOGI(TAG, "TinyUSB driver error\n:)");
ESP_ERROR_CHECK_WITHOUT_ABORT(err_code);
while (1)
{
ErrLED.set_high();
vTaskDelay(1000 / portTICK_PERIOD_MS);
ErrLED.set_low();
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
ESP_LOGI(TAG, "USB initialization DONE");
#endif
uint8_t sw7203_config_data[][2] = {
{0x02, 0b00000011},
// 中断使能1 0使能 1禁止 7:NULL 6:VSYS过压中断 5:充电超时中断 4:充电充满中断
// 3: 适配器插入中断 2:适配器移出中断 1:A2负载接入中断 0:A1负载接入中断
{0x03, 0b01000110},
// {0x04, 0b11111111},
// {0x05, 0b11111111},
{0x0D, 0b00000000},
{0x0F, 0b00000001},
{0x10, 0b01000001},
{0x18, 0b00000011},
{0x19, 0b00000000},
{0x20, 0b10000100},
{0x21, 0b11111111},
{0x22, 0b10100000},
{0x26, 0b01011001},
{0x27, 0b01010101},
{0x28, 0b00000100},
{0x30, 0b00000011},
{0x31, 0b00000000},
{0x32, 0b11010000},
{0x34, 0b10101010},
{0x35, 0b00000000},
{0x36, 0b01011111},
{0x37, 0b00001111},
{0x38, 0b00000100},
{0x39, 0b01111111},
{0x3A, 0b00010011},
#ifdef __SW7203_DEBUG__
{0x40, 0b01000011},
#else
{0x40, 0b00000011},
#endif
{0x41, 0b00000100},
{0x42, 0b00100101}};
if ((err_code = bq4050_i2c_master_init()) != ESP_OK)
{
ESP_LOGI(TAG, "BQ4050 driver error\n:)");
ESP_ERROR_CHECK_WITHOUT_ABORT(err_code);
while (1)
{
ErrLED.set_high();
vTaskDelay(1000 / portTICK_PERIOD_MS);
ErrLED.set_low();
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
BatteryVoltage = bq_GetVoltage();
BatteryCurrentCapacity = bq_GetRSOC();
BatteryRunTimeToEmpty = bq_GetT2E();
BatteryRunTimeToFull = bq_GetT2F();
ESP_LOGI(TAG, "BQ4050 initialization DONE!\n:)");
if ((err_code = sw7203_i2c_master_init()) != ESP_OK)
{
ESP_LOGI(TAG, "SW7203 driver error\n:)");
ESP_ERROR_CHECK_WITHOUT_ABORT(err_code);
while (1)
{
ErrLED.set_high();
vTaskDelay(1000 / portTICK_PERIOD_MS);
ErrLED.set_low();
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
for (int i = 0; i < 27; i++)
{
if ((err_code = sw7203_register_write(sw7203_config_data[i])) != ESP_OK)
{
ESP_LOGI(TAG, "SW7203 I2C error\n:)");
ESP_ERROR_CHECK_WITHOUT_ABORT(err_code);
while (1)
{
ErrLED.set_high();
vTaskDelay(100 / portTICK_PERIOD_MS);
ErrLED.set_low();
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
}
ESP_LOGI(TAG, "SW7203 initialization DONE!\n:)");
#ifndef __SW7203_DEBUG__
gpio_config_t SW7203_IRQ_gpio_config = {
.pin_bit_mask = 1ull << 47,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
};
gpio_config(&SW7203_IRQ_gpio_config);
xTaskCreate(sw7203_irq_func, "SW7203IRQ", 10240, NULL, 20, NULL);
ESP_LOGI(TAG, "SW7203 intrupt initialization DONE!\n:)");
#endif
ESP_LOGI(TAG, "initialization DONE!\n:)");
ErrLED.set_low();
while (1)
{
BatteryCurrentCapacity = bq_GetRSOC();
BatteryRunTimeToEmpty = bq_GetT2E();
BatteryCurrentStatus = bq_BattState_u16(AC_IN, NVDC_BAT_charge);
#ifdef __USB_HID_ENABLE__
if ((BatteryCurrentCapacity != BatteryPrevCapacity) || (BatteryCurrentStatus != BatteryPrevStatus))
{
tud_hid_report(HID_PD_REMAININGCAPACITY, &BatteryCurrentCapacity, sizeof(BatteryCurrentCapacity));
tud_hid_report(HID_PD_PRESENTSTATUS, &BatteryCurrentStatus, sizeof(BatteryCurrentStatus));
if (BatteryCurrentStatus & (1 << PRESENTSTATUS_DISCHARGING))
tud_hid_report(HID_PD_RUNTIMETOEMPTY, &BatteryRunTimeToEmpty, sizeof(BatteryRunTimeToEmpty));
BatteryPrevCapacity = BatteryCurrentCapacity;
BatteryPrevStatus = BatteryCurrentStatus;
}
#endif
if (BatteryCurrentCapacity < 10)
PowerlossLED.set_high();
else
PowerlossLED.set_low();
if (BatteryCurrentStatus & (1 << PRESENTSTATUS_CHARGING))
ChargingLED.set_high();
else
ChargingLED.set_low();
ESP_LOGI(TAG, "Battery Current Capacity :%d\nBattery Current Status :%d\nBattery RunTime To Empty :%d\n", BatteryCurrentCapacity, BatteryCurrentStatus, BatteryRunTimeToEmpty);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
#ifdef __USB_HID_ENABLE__
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
switch (int(report_type))
{
case HID_REPORT_TYPE_FEATURE:
{
switch (report_id)
{
case HID_PD_PRESENTSTATUS:
{
#ifdef __SK_BQ4050_HID__
BatteryCurrentStatus = bq_BattState_u16(AC_IN, NVDC_BAT_charge);
buffer[0] = BatteryCurrentStatus & 0x00ff;
buffer[1] = BatteryCurrentStatus >> 8 & 0x00ff;
return 2;
#else
buffer[0] = BatteryCurrentStatus & 0x00ff;
buffer[1] = BatteryCurrentStatus >> 8 & 0x00ff;
return 2;
#endif
}
case HID_PD_VOLTAGE:
{
#ifdef __SK_BQ4050_HID__
BatteryVoltage = bq_GetVoltage();
buffer[0] = BatteryVoltage & 0x00ff;
buffer[1] = BatteryVoltage >> 8 & 0x00ff;
return 2;
#else
buffer[0] = BatteryVoltage & 0x00ff;
buffer[1] = BatteryVoltage >> 8 & 0x00ff;
return 2;
#endif
}
case HID_PD_DESIGNCAPACITY:
{
buffer[0] = BatteryDesignCapacity;
return 1;
}
case HID_PD_IDEVICECHEMISTRY:
{
buffer[0] = BatteryDeviceChemistry;
return 1;
}
case HID_PD_SERIAL:
{
buffer[0] = 3;
return 1;
}
case HID_PD_IOEMINFORMATION:
{
buffer[0] = BatteryOEMVendor;
return 1;
}
case HID_PD_IPRODUCT:
{
buffer[0] = IPRODUCT;
return 1;
}
case HID_PD_MANUFACTURER:
{
buffer[0] = IMANUFACTURER;
return 1;
}
case HID_PD_MANUFACTUREDATE:
{
buffer[0] = ManufactureDate & 0x00ff;
buffer[1] = ManufactureDate >> 8 & 0x00ff;
return 2;
}
case HID_PD_FULLCHRGECAPACITY:
{
buffer[0] = BatteryFullChargeCapacity;
return 1;
}
case HID_PD_WARNCAPACITYLIMIT:
{
buffer[0] = BatteryWarnCapacityLimit;
return 1;
}
case HID_PD_REMNCAPACITYLIMIT:
{
buffer[0] = BatteryRemnCapacityLimit;
return 1;
}
case HID_PD_REMAININGCAPACITY:
{
BatteryCurrentCapacity = bq_GetRSOC();
buffer[0] = BatteryCurrentCapacity;
return 1;
}
case HID_PD_RUNTIMETOEMPTY:
{
BatteryRunTimeToEmpty = bq_GetT2E();
buffer[0] = BatteryRunTimeToEmpty & 0x00ff;
buffer[1] = BatteryRunTimeToEmpty >> 8 & 0x00ff;
return 2;
}
case HID_PD_CPCTYGRANULARITY1:
{
buffer[0] = BatteryCapacityGranularity1;
return 1;
}
case HID_PD_CPCTYGRANULARITY2:
{
buffer[0] = BatteryCapacityGranularity2;
return 1;
}
case HID_PD_CAPACITYMODE:
{
buffer[0] = BatteryCapacityMode;
return 1;
}
}
}
}
ESP_LOGI(TAG, "Get_report Request: %d, type=%s , id: %d , len:%d\n",
instance,
(report_type == HID_REPORT_TYPE_INVALID ? "HID_REPORT_TYPE_INVALID" : (report_type == HID_REPORT_TYPE_INPUT ? "HID_REPORT_TYPE_INPUT" : (report_type == HID_REPORT_TYPE_OUTPUT ? "HID_REPORT_TYPE_OUTPUT" : "HID_REPORT_TYPE_FEATURE"))),
report_id,
reqlen);
for (int i = 0; i < reqlen; i++)
{
ESP_LOGI(TAG, "Report %d:%d\n", i, buffer[-i]);
}
ESP_LOGI(TAG, "end REQUSET\n");
return 0;
}
uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance)
{
// We use only one interface and one HID report descriptor, so we can ignore parameter 'instance'
return ESP32UPS::desc_hid_report;
}
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize)
{
// ESP_LOGI(TAG, "Get_report Request: %d, type=%s , id: %d , len:%d\n",
// instance,
// (report_type == HID_REPORT_TYPE_INVALID ? "HID_REPORT_TYPE_INVALID" : (report_type == HID_REPORT_TYPE_INPUT ? "HID_REPORT_TYPE_INPUT" : (report_type == HID_REPORT_TYPE_OUTPUT ? "HID_REPORT_TYPE_OUTPUT" : "HID_REPORT_TYPE_FEATURE"))),
// report_id,
// bufsize);
// for (int i = 0; i < bufsize; i++)
// {
// ESP_LOGI(TAG, "Report %d:%d\n", i, buffer[i]);
// }
// ESP_LOGI(TAG, "end REQUSET\n");
}
#endif