mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 02:36:35 +00:00
Add Support for AP33772S USB PD Sink Controller as used in CentyLab RotoPD
This commit is contained in:
parent
04302414c8
commit
692cf547cb
@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Berry `introspect.module` option to not cache module entry (#23451)
|
||||
- Berry `webserver.remove_route` to revert `webserver.on` (#23452)
|
||||
- Berry `compile` and `tasmota.compile` option to compile in local context (#23457)
|
||||
- Support for AP33772S USB PD Sink Controller as used in CentyLab RotoPD
|
||||
|
||||
### Breaking Changed
|
||||
|
||||
|
@ -91,7 +91,7 @@ In addition to @arendst the following code is mainly owned by:
|
||||
| xdrv_77_wizmote | @arendst
|
||||
| xdrv_78_telnet | @arendst
|
||||
| xdrv_79_esp32_ble | @staars, @btsimonh
|
||||
| xdrv_80 |
|
||||
| xdrv_80_wireguard_client | @s-hadinger
|
||||
| xdrv_81_esp32_webcam | @gemu, @philrich
|
||||
| xdrv_82_esp32_ethernet | @arendst
|
||||
| xdrv_83_esp32_watch | @gemu
|
||||
@ -101,11 +101,12 @@ In addition to @arendst the following code is mainly owned by:
|
||||
| xdrv_88_esp32_shelly_pro | @arendst
|
||||
| xdrv_89_ |
|
||||
| xdrv_90_esp32_dingtian_relay | @barbudor
|
||||
| xdrv_91_ |
|
||||
| xdrv_91_esp32_twai | @arendst
|
||||
| xdrv_92_ |
|
||||
| xdrv_93_ |
|
||||
| xdrv_94_ |
|
||||
| |
|
||||
| xdrv_119_i2c_ap33772s | @arendst
|
||||
| xdrv_120_xyzmodem | @arendst
|
||||
| xdrv_121_gpioviewer | @arendst
|
||||
| xdrv_122_file_settings_demo | @arendst
|
||||
|
@ -130,6 +130,6 @@ Index | Define | Driver | Device | Address(es) | Bus2 | Descrip
|
||||
90 | USE_RX8010 | xdrv_56 | RX8010 | 0x32 | Yes | RX8010 RTC from IOTTIMER
|
||||
91 | USE_MS5837 | xsns_116 | MS5837 | 0x76 | | Pressure and temperature sensor
|
||||
92 | USE_PCF85063 | xdrv_56 | PCF85063 | 0x51 | | PCF85063 Real time clock
|
||||
93 | USE_AS33772S | xdrv_119 | AS33772S | 0x52 | | AS33772S USB PD Sink Controller
|
||||
93 | USE_AS33772S | xdrv_119 | AS33772S | 0x52 | Yes | AS33772S USB PD Sink Controller
|
||||
|
||||
NOTE: Bus2 supported on ESP32 only.
|
||||
|
@ -121,6 +121,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
|
||||
- Command `JsonPP <command>|backlog <command>;...` to enable JSON PP only once
|
||||
- Support for multi channel AU915-928 LoRaWanBridge by Rob Clark [#23372](https://github.com/arendst/Tasmota/issues/23372)
|
||||
- Support for LoRaWan Rx1 and Rx2 profiles [#23394](https://github.com/arendst/Tasmota/issues/23394)
|
||||
- Support for AP33772S USB PD Sink Controller as used in CentyLab RotoPD
|
||||
- Allow temporary change of DisplayDimmer [#23406](https://github.com/arendst/Tasmota/issues/23406)
|
||||
- WebUI status line for MQTT and TLS, added `FUNC_WEB_STATUS_LEFT` and `FUNC_WEB_STATUS_RIGHT` event [#23354](https://github.com/arendst/Tasmota/issues/23354)
|
||||
- WebUI heap status [#23356](https://github.com/arendst/Tasmota/issues/23356)
|
||||
|
@ -787,6 +787,7 @@
|
||||
// #define USE_SPL06_007 // [I2cDriver87] Enable SPL06_007 pressure and temperature sensor (I2C addresses 0x76) (+2k5 code)
|
||||
// #define USE_QMP6988 // [I2cDriver88] Enable QMP6988 pressure and temperature sensor (I2C address 0x56 or 0x70) (+2k9 code)
|
||||
// #define USE_MS5837 // [I2cDriver91] Enable MS5837 sensor (I2C address 0x76) (+2k7 code)
|
||||
// #define USE_AP33772S // [I2cDriver93] Enable AP33772S USB PD Sink Controller (I2C addresses 0x52) (+3k1 code)
|
||||
|
||||
// #define USE_RTC_CHIPS // Enable RTC chip support and NTP server - Select only one
|
||||
// #define USE_DS3231 // [I2cDriver26] Enable DS3231 RTC - used by Ulanzi TC001 (I2C address 0x68) (+1k2 code)
|
||||
|
@ -952,8 +952,12 @@ constexpr uint32_t feature[] = {
|
||||
#ifdef USE_XYZMODEM
|
||||
0x00010000 | // xdrv_120_xyzmodem.ino
|
||||
#endif
|
||||
// 0x00020000 | //
|
||||
// 0x00040000 | //
|
||||
#ifdef USE_WIREGUARD
|
||||
0x00020000 | // xdrv_80_wireguard_client
|
||||
#endif
|
||||
#if defined(USE_I2C) && defined(USE_AP33772S)
|
||||
0x00040000 | // xdrv_119_i2c_ap33772s
|
||||
#endif
|
||||
// 0x00080000 | //
|
||||
// 0x00100000 | //
|
||||
// 0x00200000 | //
|
||||
|
951
tasmota/tasmota_xdrv_driver/xdrv_119_i2c_ap33772s.ino
Normal file
951
tasmota/tasmota_xdrv_driver/xdrv_119_i2c_ap33772s.ino
Normal file
@ -0,0 +1,951 @@
|
||||
/*
|
||||
xdrv_119_i2c_ap33772s.ino - AP33772S USB PD Sink Controller support for Tasmota
|
||||
|
||||
SPDX-FileCopyrightText: 2025 Theo Arends
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
*/
|
||||
|
||||
#ifdef USE_I2C
|
||||
#ifdef USE_AP33772S
|
||||
/*********************************************************************************************\
|
||||
* AP33772S - USB Power Delivery (PD) Sink Controller
|
||||
*
|
||||
* SPR - Standard Power Range = PD3.0
|
||||
* Fixed 3A: 5V, 9V, 12V, 15V, 20V (15-60W) and 5A: 20V (60-100W)
|
||||
* PPS - Programmable Power Supply (3V3 to 21V in steps of 20mV (AP33772S = 100mV))
|
||||
* EPR - Extended Power Range = PD3.1
|
||||
* Fixed 5A: 28V, 36V, 48V (100-240W)
|
||||
* AVS - Adjustable Voltage Supply (15V to 28V or 48V (AP33772S = 28V) in steps of 100mV (AP33772S = 200mV))
|
||||
* PDO - Power Delivery Object or Power Data Object
|
||||
*
|
||||
* Datasheet https://www.diodes.com/datasheet/download/AP33772S.pdf
|
||||
* Library https://github.com/CentyLab/AP33772S-Cpp
|
||||
* Hardware https://github.com/CentyLab/RotoPD
|
||||
*
|
||||
* Tested using:
|
||||
* UGreen CD226 100W 4-Port USB GaN Fast Charger (PPS only)
|
||||
* Novoo NCEU120D-255C2 120W 3-Port USB GaN Fast Charger (PPS only)
|
||||
*
|
||||
* KOWSI KWS-X1 USB type C Voltage and Current monitor (PPS and AVS)
|
||||
*
|
||||
* I2C Address: 0x52
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XDRV_119 119
|
||||
#define XI2C_93 93 // See I2CDEVICES.md
|
||||
|
||||
//#define AP33772S_DEBUG
|
||||
|
||||
#define AP33772S_I2C_ADDR 0x52
|
||||
#define AP33772S_MAX_PDO_ENTRIES 13 // Maximum number of PDO entries
|
||||
|
||||
#define AP33772S_CMD_STATUS 0x01 // Reset to 0 after every Read
|
||||
#define AP33772S_CMD_MASK 0x02
|
||||
#define AP33772S_CMD_OPMODE 0x03
|
||||
#define AP33772S_CMD_CONFIG 0x04
|
||||
#define AP33772S_CMD_PDCONFIG 0x05
|
||||
#define AP33772S_CMD_SYSTEM 0x06
|
||||
|
||||
// Temperature setting register
|
||||
#define AP33772S_CMD_TR25 0x0C
|
||||
#define AP33772S_CMD_TR50 0x0D
|
||||
#define AP33772S_CMD_TR75 0x0E
|
||||
#define AP33772S_CMD_TR100 0x0F
|
||||
|
||||
// Power reading related
|
||||
#define AP33772S_CMD_VOLTAGE 0x11
|
||||
#define AP33772S_CMD_CURRENT 0x12
|
||||
#define AP33772S_CMD_TEMP 0x13
|
||||
#define AP33772S_CMD_VREQ 0x14
|
||||
#define AP33772S_CMD_IREQ 0x15
|
||||
|
||||
#define AP33772S_CMD_VSELMIN 0x16 // Minimum Selection Voltage
|
||||
#define AP33772S_CMD_UVPTHR 0x17
|
||||
#define AP33772S_CMD_OVPTHR 0x18
|
||||
#define AP33772S_CMD_OCPTHR 0x19
|
||||
#define AP33772S_CMD_OTPTHR 0x1A
|
||||
#define AP33772S_CMD_DRTHR 0x1B
|
||||
|
||||
#define AP33772S_CMD_SRCPDO 0x20
|
||||
|
||||
#define AP33772S_CMD_PD_REQMSG 0x31
|
||||
#define AP33772S_CMD_PD_CMDMSG 0x32
|
||||
#define AP33772S_CMD_PD_MSGRLT 0x33
|
||||
|
||||
typedef struct RDO_DATA_t {
|
||||
union {
|
||||
struct {
|
||||
unsigned int VOLTAGE_SEL: 8; // Bits 7:0, Output Voltage Select
|
||||
unsigned int CURRENT_SEL: 4; // Bits 11:8, Operating Current Select
|
||||
unsigned int PDO_INDEX: 4; // Bits 15:12, Source PDO index select
|
||||
} REQMSG_Fields;
|
||||
struct {
|
||||
byte byte0;
|
||||
byte byte1;
|
||||
};
|
||||
unsigned long data;
|
||||
};
|
||||
} RDO_DATA_t;
|
||||
|
||||
typedef struct SRC_SPRandEPR_PDO_Fields_t {
|
||||
union {
|
||||
struct {
|
||||
unsigned int voltage_max: 8; // Bits 7:0, VOLTAGE_MAX field
|
||||
unsigned int peak_current: 2; // Bits 9:8, PEAK_CURRENT field
|
||||
unsigned int current_max: 4; // Bits 13:10, CURRENT_MAX field
|
||||
unsigned int type: 1; // Bit 14, TYPE field
|
||||
unsigned int detect: 1; // Bit 15, DETECT field
|
||||
} fixed;
|
||||
struct {
|
||||
unsigned int voltage_max: 8; // Bits 7:0, VOLTAGE_MAX field
|
||||
unsigned int voltage_min: 2; // Bits 9:8, VOLTAGE_MIN field
|
||||
unsigned int current_max: 4; // Bits 13:10, CURRENT_MAX field
|
||||
unsigned int type: 1; // Bit 14, TYPE field
|
||||
unsigned int detect: 1; // Bit 15, DETECT field
|
||||
} pps;
|
||||
struct {
|
||||
unsigned int voltage_max: 8; // Bits 7:0, VOLTAGE_MAX field
|
||||
unsigned int voltage_min: 2; // Bits 9:8, VOLTAGE_MIN field
|
||||
unsigned int current_max: 4; // Bits 13:10, CURRENT_MAX field
|
||||
unsigned int type: 1; // Bit 14, TYPE field
|
||||
unsigned int detect: 1; // Bit 15, DETECT field
|
||||
} avs;
|
||||
struct {
|
||||
uint8_t byte0;
|
||||
uint8_t byte1;
|
||||
};
|
||||
};
|
||||
unsigned long data;
|
||||
} SRC_SPRandEPR_PDO_Fields_t;
|
||||
|
||||
typedef struct Ap33772s_t {
|
||||
SRC_SPRandEPR_PDO_Fields_t SRC_SPRandEPRpdoArray[AP33772S_MAX_PDO_ENTRIES];
|
||||
|
||||
int voltage_PPS;
|
||||
int current_PPS;
|
||||
|
||||
int voltage_AVS_byte;
|
||||
int current_AVS_byte;
|
||||
int index_AVS;
|
||||
|
||||
int slider_voltage;
|
||||
int slider_current;
|
||||
|
||||
uint8_t read_buffer[2];
|
||||
uint8_t write_buffer[2];
|
||||
int8_t index_PPS_user;
|
||||
int8_t index_AVS_user;
|
||||
bool output;
|
||||
uint8_t bus;
|
||||
} Ap33772s_t;
|
||||
Ap33772s_t* Ap33772s = nullptr;
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
#ifdef AP33772S_DEBUG
|
||||
|
||||
String AP33772S_DisplayCurrentRange(uint32_t current_max) {
|
||||
String result = "Invalid value";
|
||||
switch (current_max) {
|
||||
case 0:
|
||||
result = "0.00A ~ 1.24A (Less than)";
|
||||
break;
|
||||
case 1:
|
||||
result = "1.25A ~ 1.49A";
|
||||
break;
|
||||
case 2:
|
||||
result = "1.50A ~ 1.74A";
|
||||
break;
|
||||
case 3:
|
||||
result = "1.75A ~ 1.99A";
|
||||
break;
|
||||
case 4:
|
||||
result = "2.00A ~ 2.24A";
|
||||
break;
|
||||
case 5:
|
||||
result = "2.25A ~ 2.49A";
|
||||
break;
|
||||
case 6:
|
||||
result = "2.50A ~ 2.74A";
|
||||
break;
|
||||
case 7:
|
||||
result = "2.75A ~ 2.99A";
|
||||
break;
|
||||
case 8:
|
||||
result = "3.00A ~ 3.24A";
|
||||
break;
|
||||
case 9:
|
||||
result = "3.25A ~ 3.49A";
|
||||
break;
|
||||
case 10:
|
||||
result = "3.50A ~ 3.74A";
|
||||
break;
|
||||
case 11:
|
||||
result = "3.75A ~ 3.99A";
|
||||
break;
|
||||
case 12:
|
||||
result = "4.00A ~ 4.24A";
|
||||
break;
|
||||
case 13:
|
||||
result = "4.25A ~ 4.49A";
|
||||
break;
|
||||
case 14:
|
||||
result = "4.50A ~ 4.99A";
|
||||
break;
|
||||
case 15:
|
||||
result = "5.00A ~ (More than)";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String AP33772S_DisplayEPRVoltageMin(uint32_t current_max) {
|
||||
String result = "Invalid value";
|
||||
switch (current_max) {
|
||||
case 0:
|
||||
result = "Reserved";
|
||||
break;
|
||||
case 1:
|
||||
result = "15000mV ~";
|
||||
break;
|
||||
case 2:
|
||||
result = "15000mV < VOLTAGE_MIN ≤ 20000mV ";
|
||||
break;
|
||||
case 3:
|
||||
result = "others";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String AP33772S_DisplaySPRVoltageMin(uint32_t current_max) {
|
||||
String result = "Invalid value";
|
||||
switch (current_max) {
|
||||
case 0:
|
||||
result = "Reserved";
|
||||
break;
|
||||
case 1:
|
||||
result = "3300mV ~";
|
||||
break;
|
||||
case 2:
|
||||
result = "3300mV < VOLTAGE_MIN ≤ 5000mV ";
|
||||
break;
|
||||
case 3:
|
||||
result = "others";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode PDO information from SRC_SPRandEPR_PDO_Fields
|
||||
* @param pdoIndex feed from loop
|
||||
*/
|
||||
void AP33772S_DisplayPDOInfo(int pdoIndex) {
|
||||
// Determine if it's SPR or EPR based on pdoIndex
|
||||
bool isEPR = (pdoIndex >= 7 && pdoIndex <= 12); // 1-6 for SPR, 7-12 for EPR
|
||||
// Check if both bytes are zero
|
||||
if (Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex].byte0 == 0 && Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex].byte1 == 0) {
|
||||
return; // If both bytes are zero, exit the function
|
||||
}
|
||||
|
||||
// Print the PDO type and index
|
||||
// Now, the individual fields can be accessed through the union in the struct
|
||||
if (Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex].fixed.type == 0) { // Fixed PDO
|
||||
// Print parsed values
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: %s_PDO%d Fixed_PDO %dmV %s"),
|
||||
(pdoIndex <= 6) ? "SPR" : "EPR",
|
||||
pdoIndex+1,
|
||||
Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex].fixed.voltage_max * (isEPR ? 200 : 100), // Voltage in 200mV units for EPR, 100mV for SPR
|
||||
AP33772S_DisplayCurrentRange(Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex].fixed.current_max).c_str() // Assuming displayCurrentRange function is available
|
||||
);
|
||||
} else { // PPS or AVS PDO
|
||||
// Print parsed values
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: %s_PDO%d %s_PDO %s %dmV %s"),
|
||||
(pdoIndex <= 6) ? "SPR" : "EPR",
|
||||
pdoIndex+1,
|
||||
(isEPR) ? "AVS" : "PPS",
|
||||
(isEPR) ? AP33772S_DisplayEPRVoltageMin(Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex].avs.voltage_min).c_str() : // Assuming displayVoltageMin function is available
|
||||
AP33772S_DisplaySPRVoltageMin(Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex].pps.voltage_min).c_str(), // Assuming displayVoltageMin function is available
|
||||
Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex].fixed.voltage_max * (isEPR ? 200 : 100), // Maximum Voltage in 200mV units for EPR, 100mV for SPR
|
||||
AP33772S_DisplayCurrentRange(Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex].fixed.current_max).c_str() // Assuming displayCurrentRange function is available
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AP33772S_DEBUG
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void AP33772S_I2cRead(uint8_t cmdAddr, byte len) {
|
||||
// clear readBuffer
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
Ap33772s->read_buffer[i] = 0;
|
||||
}
|
||||
I2cReadBuffer(AP33772S_I2C_ADDR, cmdAddr, Ap33772s->read_buffer, len, Ap33772s->bus);
|
||||
}
|
||||
|
||||
void AP33772S_I2cWrite(byte cmdAddr, byte len) {
|
||||
I2cWriteBuffer(AP33772S_I2C_ADDR, cmdAddr, Ap33772s->write_buffer, len, Ap33772s->bus);
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief take in current in mA unit
|
||||
* @return value from 0 to 15
|
||||
* @return -1 if there is an error
|
||||
*/
|
||||
int AP33772S_CurrentMap(int current) {
|
||||
// Check if the value is out of bounds
|
||||
if (current < 0 || current > 5000) {
|
||||
return -1; // Return -1 for invalid inputs
|
||||
}
|
||||
|
||||
// If value is below 1250, return 0
|
||||
if (current < 1250) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate the result for ranges above 1250
|
||||
return ((current - 1250) / 250) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request fixed PDO voltage, work for both standard and EPR mode
|
||||
* @param pdoIndex index 1
|
||||
* @param max_current unit in mA
|
||||
*/
|
||||
void AP33772S_SetFixPDO(int pdoIndex, int max_current) {
|
||||
RDO_DATA_t rdoData;
|
||||
|
||||
// Max current sanity check
|
||||
if (max_current <= 0) { return; }
|
||||
|
||||
// For Fix voltage, only need to set PDO_INDEX and CURRENT_SEL
|
||||
// No need to change the selected voltage
|
||||
// handle the same in standard as well as EPR
|
||||
|
||||
// PDO index need to be fixed type
|
||||
if (Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].fixed.type == 0) {
|
||||
// Now that we are in fix PDO mode
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: Type is fixed"));
|
||||
|
||||
rdoData.REQMSG_Fields.PDO_INDEX = pdoIndex; // Index 1
|
||||
|
||||
// Serial.printf("You entered current: %dmA", max_current); //DEBUG
|
||||
// Serial.println(SRC_SPRandEPRpdoArray[pdoIndex].fixed.current_max); //DEBUG
|
||||
// Serial.println(currentMap(max_current)); //DEBUG
|
||||
if (AP33772S_CurrentMap(max_current) > Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].fixed.current_max) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: Current not in range"));
|
||||
return; // Check if current setting is in range
|
||||
}
|
||||
|
||||
rdoData.REQMSG_Fields.CURRENT_SEL = AP33772S_CurrentMap(max_current);
|
||||
// Note: For profile less than or equal to 3A power, CURRENT_SEL = 9 will not work.
|
||||
// rdoData.REQMSG_Fields.CURRENT_SEL = 9;
|
||||
|
||||
Ap33772s->write_buffer[0] = rdoData.byte0; // Store the upper 8 bits
|
||||
Ap33772s->write_buffer[1] = rdoData.byte1; // Store the lower 8 bits
|
||||
AP33772S_I2cWrite(AP33772S_CMD_PD_REQMSG, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request PPS voltage
|
||||
* @param pdoIndex index 1
|
||||
* @param target_voltage unit in mV
|
||||
* @param max_current unit in mA
|
||||
* @bug only work if min PPS voltage is 3.3V
|
||||
*/
|
||||
void AP33772S_SetPPSPDO(int pdoIndex, int target_voltage, int max_current) {
|
||||
RDO_DATA_t rdoData;
|
||||
|
||||
int voltage_min_decoded;
|
||||
// Sanity check include, check if the value is in EPR range (index < 8) and also AVS mode
|
||||
if ((pdoIndex < 8) && (Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].pps.type == 1)) {
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: Type is PPS"));
|
||||
// Now that we are in PPS mode
|
||||
|
||||
rdoData.REQMSG_Fields.PDO_INDEX = pdoIndex; // Index 1
|
||||
|
||||
if (AP33772S_CurrentMap(max_current) > Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].pps.current_max) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: PPS Current not in range"));
|
||||
return; // Check if current setting is in range
|
||||
}
|
||||
|
||||
// Decode voltage_min
|
||||
if (Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].pps.voltage_min > 0) {
|
||||
voltage_min_decoded = 3300;
|
||||
}
|
||||
|
||||
if ((target_voltage < voltage_min_decoded) ||
|
||||
(target_voltage > Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].pps.voltage_max*100)) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: PPS Voltage not in range"));
|
||||
return; // Check if current setting is in range
|
||||
}
|
||||
|
||||
rdoData.REQMSG_Fields.VOLTAGE_SEL = target_voltage/100; // Output Voltage in 200mV units
|
||||
rdoData.REQMSG_Fields.CURRENT_SEL = AP33772S_CurrentMap(max_current);
|
||||
|
||||
Ap33772s->write_buffer[0] = rdoData.byte0; // Store the upper 8 bits
|
||||
Ap33772s->write_buffer[1] = rdoData.byte1; // Store the lower 8 bits
|
||||
AP33772S_I2cWrite(AP33772S_CMD_PD_REQMSG, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request AVS voltage
|
||||
* @param pdoIndex index 1
|
||||
* @param target_voltage unit in mV
|
||||
* @param max_current unit in mA
|
||||
* @bug only work if min AVS voltage is 15V, AVS max voltage is not capped at 30V
|
||||
*/
|
||||
void AP33772S_SetAVSPDO(int pdoIndex, int target_voltage, int max_current) {
|
||||
RDO_DATA_t rdoData;
|
||||
|
||||
int voltage_min_decoded;
|
||||
// Sanity check include, check if the value is in EPR range (index >= 8) and also AVS mode
|
||||
if ((pdoIndex >= 8) && (Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].avs.type == 1)) {
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: Type is AVS"));
|
||||
// Now that we are in AVS mode
|
||||
|
||||
// Decode voltage_min
|
||||
if (Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].avs.voltage_min > 0) {
|
||||
voltage_min_decoded = 15000;
|
||||
}
|
||||
|
||||
rdoData.REQMSG_Fields.PDO_INDEX = pdoIndex; // Index 1
|
||||
|
||||
if (AP33772S_CurrentMap(max_current) > Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].avs.current_max) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: AVS Current not in range."));
|
||||
return; // Check if current setting is in range
|
||||
}
|
||||
|
||||
// Decode voltage_min
|
||||
if (Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].avs.voltage_min > 0) {
|
||||
voltage_min_decoded = 15000;
|
||||
}
|
||||
|
||||
if ((target_voltage < voltage_min_decoded) ||
|
||||
(target_voltage > Ap33772s->SRC_SPRandEPRpdoArray[pdoIndex-1].avs.voltage_max*200)) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: AVS Voltage not in range"));
|
||||
return; // Check if current setting is in range
|
||||
}
|
||||
|
||||
rdoData.REQMSG_Fields.VOLTAGE_SEL = target_voltage/200; // Output Voltage in 200mV units
|
||||
rdoData.REQMSG_Fields.CURRENT_SEL = AP33772S_CurrentMap(max_current);
|
||||
|
||||
Ap33772s->write_buffer[0] = rdoData.byte0; // Store the upper 8 bits
|
||||
Ap33772s->write_buffer[1] = rdoData.byte1; // Store the lower 8 bits
|
||||
AP33772S_I2cWrite(AP33772S_CMD_PD_REQMSG, 2);
|
||||
|
||||
Ap33772s->index_AVS = rdoData.REQMSG_Fields.PDO_INDEX;
|
||||
Ap33772s->voltage_AVS_byte = rdoData.REQMSG_Fields.VOLTAGE_SEL;
|
||||
Ap33772s->current_AVS_byte = rdoData.REQMSG_Fields.CURRENT_SEL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set resistance value of 10K NTC at 25C, 50C, 75C and 100C.
|
||||
* Default is 10000, 4161, 1928, 974Ohm
|
||||
* @param TR25, TR50, TR75, TR100 unit in Ohm
|
||||
* @attention Blocking function due to long I2C write, min blocking time 15ms
|
||||
*/
|
||||
void AP33772S_SetNTC(int TR25, int TR50, int TR75, int TR100) {
|
||||
Ap33772s->write_buffer[0] = TR25 & 0xff;
|
||||
Ap33772s->write_buffer[1] = (TR25 >> 8) & 0xff;
|
||||
AP33772S_I2cWrite(AP33772S_CMD_TR25, 2);
|
||||
delay(5);
|
||||
Ap33772s->write_buffer[0] = TR50 & 0xff;
|
||||
Ap33772s->write_buffer[1] = (TR50 >> 8) & 0xff;
|
||||
AP33772S_I2cWrite(AP33772S_CMD_TR50, 2);
|
||||
delay(5);
|
||||
Ap33772s->write_buffer[0] = TR75 & 0xff;
|
||||
Ap33772s->write_buffer[1] = (TR75 >> 8) & 0xff;
|
||||
AP33772S_I2cWrite(AP33772S_CMD_TR75, 2);
|
||||
delay(5);
|
||||
Ap33772s->write_buffer[0] = TR100 & 0xff;
|
||||
Ap33772s->write_buffer[1] = (TR100 >> 8) & 0xff;
|
||||
AP33772S_I2cWrite(AP33772S_CMD_TR100, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read NTC temperature
|
||||
* @return tempearture in C
|
||||
*/
|
||||
int AP33772S_ReadTemp(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_TEMP, 1);
|
||||
return Ap33772s->read_buffer[0]; // I2C read return 1C/LSB
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read VBUS voltage
|
||||
* @return voltage in mV
|
||||
*/
|
||||
int AP33772S_ReadVoltage(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_VOLTAGE, 2);
|
||||
return ((Ap33772s->read_buffer[1] << 8) | Ap33772s->read_buffer[0]) * 80; // I2C read return 80mV/LSB
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read VBUS current
|
||||
* @return current in mA
|
||||
*/
|
||||
int AP33772S_ReadCurrent(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_CURRENT, 1);
|
||||
return Ap33772s->read_buffer[0] * 24; // I2C read return 24mA/LSB
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read VREQ The latest requested voltage negotiated with the source
|
||||
* @return voltage in mV
|
||||
*/
|
||||
int AP33772S_ReadVREQ(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_VREQ, 1);
|
||||
return Ap33772s->read_buffer[0] * 50; // I2C read return 50mV/LSB
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read IREQ The latest requested voltage negotiated with the source
|
||||
* @return current in mA
|
||||
*/
|
||||
int AP33772S_ReadIREQ(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_IREQ, 1);
|
||||
return Ap33772s->read_buffer[0] * 10; // I2C read return 10mA/LSB
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read VSELMIN register. The Minimum Selection Voltage
|
||||
* @return voltage in mV
|
||||
*/
|
||||
int AP33772S_ReadVSELMIN(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_VSELMIN, 1);
|
||||
return Ap33772s->read_buffer[0] * 200; // I2C read return 200mV/LSB
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set VSELMIN register. The Minimum Selection Voltage
|
||||
* @param voltage in mV
|
||||
*/
|
||||
void AP33772S_SetVSELMIN(int voltage) {
|
||||
Ap33772s->write_buffer[0] = voltage / 200; // 200mV/LSB
|
||||
AP33772S_I2cWrite(AP33772S_CMD_VSELMIN, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read UVP Threshold, percentage(%) of VREQ
|
||||
* @return percentage, should only return 80%, 75%, or 70%. -1 for error
|
||||
*/
|
||||
int AP33772S_ReadUVPTHR(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_UVPTHR, 1);
|
||||
switch(Ap33772s->read_buffer[0]) {
|
||||
case 1:
|
||||
return 80;
|
||||
case 2:
|
||||
return 75;
|
||||
case 3:
|
||||
return 70;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set UVP Threshold, percentage(%) of VREQ
|
||||
* @param value percentage. If 80% then value = 80
|
||||
*/
|
||||
void AP33772S_SetUVPTHR(int value) {
|
||||
if ((value >= 70) && (value <= 80)) {
|
||||
switch(value) {
|
||||
case 80:
|
||||
Ap33772s->write_buffer[0] = 1;
|
||||
break;
|
||||
case 75:
|
||||
Ap33772s->write_buffer[0] = 2;
|
||||
break;
|
||||
case 70:
|
||||
Ap33772s->write_buffer[0] = 3;
|
||||
break;
|
||||
default:
|
||||
return; // Error
|
||||
}
|
||||
AP33772S_I2cWrite(AP33772S_CMD_UVPTHR, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read OVP Threshold Voltage is the VREQ voltage plus OVPTHR offset voltage (mV)
|
||||
* @return voltage in mV
|
||||
*/
|
||||
int AP33772S_ReadOVPTHR(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_OVPTHR, 1);
|
||||
return Ap33772s->read_buffer[0] * 80; // I2C read return 80mV/LSB
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set OVP Threshold Voltage is the VREQ voltage plus OVPTHR offset voltage (mV)
|
||||
* @param voltage in mV
|
||||
*/
|
||||
void AP33772S_SetOVPTHR(int value) {
|
||||
Ap33772s->write_buffer[0] = value / 80; // 80mV/LSB
|
||||
AP33772S_I2cWrite(AP33772S_CMD_OVPTHR, 1);
|
||||
}
|
||||
|
||||
int AP33772S_ReadOCPTHR(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_OCPTHR, 1);
|
||||
return Ap33772s->read_buffer[0] * 50; // I2C read return 50mA/LSB
|
||||
}
|
||||
|
||||
void AP33772S_SetOCPTHR(int value) {
|
||||
Ap33772s->write_buffer[0] = value/50; // 50mA/LSB
|
||||
AP33772S_I2cWrite(AP33772S_CMD_OCPTHR, 1);
|
||||
}
|
||||
|
||||
int AP33772S_ReadOTPTHR(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_OTPTHR, 1);
|
||||
return Ap33772s->read_buffer[0]; // I2C read return 1C/LSB
|
||||
}
|
||||
|
||||
void AP33772S_SetOTPTHR(int value) {
|
||||
Ap33772s->write_buffer[0] = value; // 1C/LSB
|
||||
AP33772S_I2cWrite(AP33772S_CMD_OTPTHR, 1);
|
||||
}
|
||||
|
||||
int AP33772S_ReadDRTHR(void) {
|
||||
AP33772S_I2cRead(AP33772S_CMD_DRTHR, 1);
|
||||
return Ap33772s->read_buffer[0]; // I2C read return 1C/LSB
|
||||
}
|
||||
|
||||
void AP33772S_SetDRTHR(int value) {
|
||||
Ap33772s->write_buffer[0] = value; // 1C/LSB
|
||||
AP33772S_I2cWrite(AP33772S_CMD_DRTHR, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Turn on/off the NMOS switch
|
||||
* @param flag 0 or 1 for OFF/ON
|
||||
* @return 1 if flag make sense
|
||||
* @bug can add code to check Vout voltage to ensure on or off, worry about settle time required for VOUT
|
||||
*/
|
||||
bool AP33772S_SetOutput(uint8_t flag) {
|
||||
switch(flag) {
|
||||
case 0:
|
||||
Ap33772s->write_buffer[0] = 0b00010001; // Turn off
|
||||
AP33772S_I2cWrite(AP33772S_CMD_SYSTEM, 1);
|
||||
return true;
|
||||
break; //Sanity
|
||||
case 1:
|
||||
Ap33772s->write_buffer[0] = 0b00010010; // Turn on
|
||||
AP33772S_I2cWrite(AP33772S_CMD_SYSTEM, 1);
|
||||
return true;
|
||||
break; //Sanity
|
||||
default:
|
||||
return false; // Error, dont know the input
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void AP33772S_Init(void) {
|
||||
uint32_t bus;
|
||||
for (bus = 0; bus < 2; bus++) {
|
||||
if (!I2cSetDevice(AP33772S_I2C_ADDR, bus)) {
|
||||
continue;
|
||||
}
|
||||
uint8_t data[26];
|
||||
delay(100); // We expect only one chip
|
||||
|
||||
if (!I2cReadBuffer(AP33772S_I2C_ADDR, AP33772S_CMD_SRCPDO, data, sizeof(data), bus)) {
|
||||
Ap33772s = (Ap33772s_t*)calloc(sizeof(Ap33772s_t), 1); // Need calloc to reset registers to 0/false
|
||||
if (nullptr == Ap33772s) { return; }
|
||||
Ap33772s->bus = bus;
|
||||
I2cSetActiveFound(AP33772S_I2C_ADDR, "AP33772S", Ap33772s->bus);
|
||||
|
||||
Ap33772s->index_PPS_user = -1;
|
||||
Ap33772s->index_AVS_user = -1;
|
||||
// Store the bytes in the array of structs
|
||||
for (uint32_t i = 0; i < sizeof(data); i += 2) {
|
||||
uint32_t pdo_index = (i / 2); // Calculate the PDO index
|
||||
Ap33772s->SRC_SPRandEPRpdoArray[pdo_index].byte0 = data[i];
|
||||
Ap33772s->SRC_SPRandEPRpdoArray[pdo_index].byte1 = data[i + 1];
|
||||
|
||||
// @brief Search through the list of profile and look for PPS, AVS
|
||||
// @bug If system has 2 PPS profiles. The index only show the last one. Use displayPDOInfo() to check.
|
||||
if ((pdo_index < 7) && (Ap33772s->SRC_SPRandEPRpdoArray[pdo_index].pps.type == 1)) {
|
||||
Ap33772s->index_PPS_user = pdo_index +1;
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: Found PPS profile %d"), Ap33772s->index_PPS_user);
|
||||
}
|
||||
else if ((pdo_index >= 7) && (Ap33772s->SRC_SPRandEPRpdoArray[pdo_index].avs.type == 1)) {
|
||||
Ap33772s->index_AVS_user = pdo_index +1;
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("AP3: Found AVS profile %d"), Ap33772s->index_AVS_user);
|
||||
}
|
||||
#ifdef AP33772S_DEBUG
|
||||
AP33772S_DisplayPDOInfo(pdo_index);
|
||||
#endif // AP33772S_DEBUG
|
||||
}
|
||||
|
||||
AP33772S_SetOutput(0); // Default output OFF
|
||||
Ap33772s->voltage_PPS = 5000; // Default 5V
|
||||
Ap33772s->current_PPS = 3000; // Default 3A
|
||||
AP33772S_SetPPSPDO(Ap33772s->index_PPS_user, Ap33772s->voltage_PPS, Ap33772s->current_PPS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Some charger will disconnect with sink if no refresh request is sent within 1s
|
||||
* Spamming request to keep power on
|
||||
*/
|
||||
void AP33772S_KeepAlive(void) {
|
||||
if (Ap33772s->output) {
|
||||
AP33772S_SetPPSPDO(Ap33772s->index_PPS_user, Ap33772s->voltage_PPS, Ap33772s->current_PPS);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Commands
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char kAP33772SCommands[] PROGMEM = "PD|" // Prefix
|
||||
"Output|Voltage|Current";
|
||||
|
||||
void (* const AP33772SCommands[])(void) PROGMEM = {
|
||||
&CmndPDOutput, &CmndPDVoltage, &CmndPDCurrent };
|
||||
|
||||
void CmndPDOutput(void) {
|
||||
// PDOutput - Show output state
|
||||
// PDOutput 0 - Turn output off
|
||||
// PDOutput 1 - Turn output on
|
||||
// PDOutput 2 - Toggle output
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) {
|
||||
switch (XdrvMailbox.payload) {
|
||||
case 0: // Off
|
||||
Ap33772s->output = 0;
|
||||
break;
|
||||
case 1: // On
|
||||
Ap33772s->output = 1;
|
||||
break;
|
||||
case 2: // Toggle
|
||||
Ap33772s->output ^= 1;
|
||||
break;
|
||||
}
|
||||
AP33772S_SetOutput(Ap33772s->output);
|
||||
}
|
||||
ResponseCmndChar(GetStateText(Ap33772s->output));
|
||||
}
|
||||
|
||||
void CmndPDVoltage(void) {
|
||||
// PDVoltage - Show PPS voltage
|
||||
// PDVoltage 5000 - Set PPS voltage to 5000 mV or 5V
|
||||
if ((XdrvMailbox.payload >= 3300) && (XdrvMailbox.payload <= 20000)) {
|
||||
Ap33772s->voltage_PPS = XdrvMailbox.payload;
|
||||
if (Ap33772s->current_PPS < 1250) {
|
||||
Ap33772s->current_PPS = 1250; // Default 1.25A
|
||||
}
|
||||
AP33772S_SetPPSPDO(Ap33772s->index_PPS_user, Ap33772s->voltage_PPS, Ap33772s->current_PPS);
|
||||
}
|
||||
uint32_t voltage = AP33772S_ReadVoltage();
|
||||
ResponseCmndNumber(voltage);
|
||||
}
|
||||
|
||||
void CmndPDCurrent(void) {
|
||||
// PDCurrent - Show max PPS current
|
||||
// PDCurrent 2000 - Set max PPS current to 2000mA or 2A
|
||||
if ((XdrvMailbox.payload >= 1250) && (XdrvMailbox.payload <= 5000)) {
|
||||
Ap33772s->current_PPS = XdrvMailbox.payload;
|
||||
if (Ap33772s->voltage_PPS < 3300) {
|
||||
Ap33772s->voltage_PPS = 5000; // Default 5V
|
||||
}
|
||||
AP33772S_SetPPSPDO(Ap33772s->index_PPS_user, Ap33772s->voltage_PPS, Ap33772s->current_PPS);
|
||||
}
|
||||
uint32_t current = AP33772S_ReadCurrent();
|
||||
ResponseCmndNumber(current);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Presentation
|
||||
\*********************************************************************************************/
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
const char HTTP_MSG_SLIDER_AP33772S[] PROGMEM =
|
||||
"<tr>"
|
||||
"<td colspan='%d' style='width:%d%%'>"
|
||||
"<div id='d119%d' class='r' style='background-image:linear-gradient(to right,#000,#fff);font-size:10px;'>"
|
||||
"<span id='s119%d'></span> %s"
|
||||
"<input id='i119%d' type='range' min='%d' max='%d' value='%d' onchange='lc(\"i\",119%d,value)'>"
|
||||
"</div>"
|
||||
"</td>"
|
||||
"<script>"
|
||||
"eb('s119%d').innerHTML=eb('i119%d').value/1000;"
|
||||
"eb('i119%d').oninput=function(){"
|
||||
"eb('s119%d').innerHTML=this.value/1000;"
|
||||
"}"
|
||||
"</script>";
|
||||
|
||||
const char HTTP_MSG_BUTTON_AP33772S[] PROGMEM =
|
||||
"<td style='width:15%%'><button id='k119' style='height:46px;background:#%06x;' onclick='la(\"&k119=1\");'>PD</button></td>";
|
||||
|
||||
void AP33772S_WebAddMainSlider(void) {
|
||||
WSContentSend_P(HTTP_TABLE100);
|
||||
|
||||
Ap33772s->slider_voltage = Ap33772s->voltage_PPS;
|
||||
WSContentSend_P(HTTP_MSG_SLIDER_AP33772S, // Voltage
|
||||
2, 100, // colspan, width
|
||||
1, // d1191 - Unique HTML id (not used)
|
||||
1, // s1191 - Unique span HTML id - Used for label updates
|
||||
"V", // label
|
||||
1, // i1191 - Unique range HTML id - Used for slider updates
|
||||
3300, 20000, // Range 3V3 to 20V
|
||||
Ap33772s->slider_voltage, // Range value
|
||||
1, // i1191 - Value id
|
||||
1, 1, 1, 1 // s1191, i1191, i1191, s1191 - Script ids
|
||||
);
|
||||
WSContentSend_P(PSTR("</tr>"));
|
||||
|
||||
Ap33772s->slider_current = Ap33772s->current_PPS;
|
||||
WSContentSend_P(HTTP_MSG_SLIDER_AP33772S, // Current
|
||||
1, 85, // colspan, width
|
||||
2, // d1192 - Unique HTML id (not used)
|
||||
2, // s1192 - Unique span HTML id - Used for label updates
|
||||
"A max", // label
|
||||
2, // i1192 - Unique range HTML id - Used for slider updates
|
||||
1250, 5000, // Range 1.25A to 5A
|
||||
Ap33772s->slider_current, // Range value
|
||||
2, // i1192 - Value id
|
||||
2, 2, 2, 2 // s1192, i1192, i1192, s1192 - Script ids
|
||||
);
|
||||
WSContentSend_P(HTTP_MSG_BUTTON_AP33772S, // Output
|
||||
WebColor((Ap33772s->output) ? COL_BUTTON : COL_BUTTON_OFF));
|
||||
WSContentSend_P(PSTR("</tr>"));
|
||||
|
||||
WSContentSend_P(PSTR("</table>"));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------*/
|
||||
|
||||
void AP33772S_WebUpdateButtonSliderState(void) {
|
||||
WSContentSend_P(PSTR("</table>")); // Terminate current {t}
|
||||
WSContentSend_P(HTTP_MSG_EXEC_JAVASCRIPT); // "<img style='display:none;' src onerror=\""
|
||||
if (Ap33772s->voltage_PPS != Ap33772s->slider_voltage) {
|
||||
if (WebUpdateSliderTime()) {
|
||||
Ap33772s->slider_voltage = Ap33772s->voltage_PPS;
|
||||
}
|
||||
WSContentSend_P(PSTR("eb('i1191').value=%d;eb('s1191').innerHTML=%d/1000;"),
|
||||
Ap33772s->voltage_PPS, Ap33772s->voltage_PPS);
|
||||
}
|
||||
if (Ap33772s->current_PPS != Ap33772s->slider_current) {
|
||||
if (WebUpdateSliderTime()) {
|
||||
Ap33772s->slider_current = Ap33772s->current_PPS;
|
||||
}
|
||||
WSContentSend_P(PSTR("eb('i1192').value=%d;eb('s1192').innerHTML=%d/1000;"),
|
||||
Ap33772s->current_PPS, Ap33772s->current_PPS);
|
||||
}
|
||||
WSContentSend_P(PSTR("eb('k119').style='background:#%06x';"),
|
||||
WebColor((Ap33772s->output) ? COL_BUTTON : COL_BUTTON_OFF));
|
||||
WSContentSend_P(PSTR("\">{t}")); // Restart {t} = <table style='width:100%'>
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void AP33772S_WebGetArg(void) {
|
||||
char tmp[8]; // WebGetArg numbers only
|
||||
char svalue[32]; // Command and number parameter
|
||||
|
||||
WebGetArg("i1191", tmp, sizeof(tmp));
|
||||
if (strlen(tmp)) {
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("PDVoltage %s"), tmp);
|
||||
ExecuteWebCommand(svalue);
|
||||
}
|
||||
WebGetArg("i1192", tmp, sizeof(tmp));
|
||||
if (strlen(tmp)) {
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("PDCurrent %s"), tmp);
|
||||
ExecuteWebCommand(svalue);
|
||||
}
|
||||
WebGetArg(PSTR("k119"), tmp, sizeof(tmp));
|
||||
if (strlen(tmp)) {
|
||||
snprintf_P(svalue, sizeof(svalue), PSTR("PDOutput 2"));
|
||||
ExecuteWebCommand(svalue);
|
||||
}
|
||||
}
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void AP33772S_Show(bool json) {
|
||||
float f_voltage = (float)AP33772S_ReadVoltage() / 1000;
|
||||
float f_current = (float)AP33772S_ReadCurrent() / 1000;
|
||||
float f_power = f_voltage * f_current;
|
||||
float f_temperature = ConvertTemp(AP33772S_ReadTemp());
|
||||
|
||||
if (json) {
|
||||
ResponseAppend_P(",\"AP33772S\":{\"" D_JSON_VOLTAGE "\":%*_f,\"" D_JSON_CURRENT "\":%*_f,\"" D_JSON_POWERUSAGE "\":%*_f,\"" D_JSON_TEMPERATURE "\":%*_f}",
|
||||
Settings->flag2.voltage_resolution, &f_voltage,
|
||||
Settings->flag2.current_resolution, &f_current,
|
||||
Settings->flag2.wattage_resolution, &f_power,
|
||||
Settings->flag2.temperature_resolution, &f_temperature);
|
||||
#ifdef USE_WEBSERVER
|
||||
} else {
|
||||
WSContentSend_Voltage("AP33772S", f_voltage);
|
||||
WSContentSend_Current("AP33772S", f_current);
|
||||
WSContentSend_PD(HTTP_SNS_F_POWER, "AP33772S", Settings->flag2.wattage_resolution, &f_power);
|
||||
WSContentSend_Temp("AP33772S", f_temperature);
|
||||
AP33772S_WebUpdateButtonSliderState();
|
||||
#endif // USE_WEBSERVER
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
bool Xdrv119(uint32_t function) {
|
||||
if (!I2cEnabled(XI2C_93)) { return false; }
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (FUNC_INIT == function) {
|
||||
AP33772S_Init();
|
||||
}
|
||||
else if (Ap33772s) {
|
||||
switch (function) {
|
||||
case FUNC_EVERY_250_MSECOND:
|
||||
AP33772S_KeepAlive();
|
||||
break;
|
||||
case FUNC_JSON_APPEND:
|
||||
AP33772S_Show(1);
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_SENSOR:
|
||||
AP33772S_Show(0);
|
||||
break;
|
||||
case FUNC_WEB_ADD_MAIN_BUTTON:
|
||||
AP33772S_WebAddMainSlider();
|
||||
break;
|
||||
case FUNC_WEB_GET_ARG:
|
||||
AP33772S_WebGetArg();
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kAP33772SCommands, AP33772SCommands);
|
||||
break;
|
||||
case FUNC_ACTIVE:
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_AP33772S
|
||||
#endif // USE_I2C
|
||||
|
@ -312,7 +312,7 @@ a_features = [[
|
||||
"USE_SPI_LORA","USE_SPL06_007","USE_QMP6988","USE_WOOLIIS",
|
||||
"USE_HX711_M5SCALES","USE_RX8010","USE_PCF85063","USE_ESP32_TWAI",
|
||||
"USE_C8_CO2_5K","USE_WIZMOTE","USE_V9240","USE_TELNET",
|
||||
"USE_XYZMODEM","","","",
|
||||
"USE_XYZMODEM","USE_WIREGUARD","USE_AP33772S","",
|
||||
"","","","",
|
||||
"","","","",
|
||||
"","","",""
|
||||
@ -343,7 +343,7 @@ else:
|
||||
obj = json.load(fp)
|
||||
|
||||
def StartDecode():
|
||||
print ("\n*** decode-status.py v14.5.0.3 by Theo Arends and Jacek Ziolkowski ***")
|
||||
print ("\n*** decode-status.py v14.6.0.2 by Theo Arends and Jacek Ziolkowski ***")
|
||||
|
||||
# print("Decoding\n{}".format(obj))
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user