Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 44 additions & 51 deletions examples/UPS/UPS.ino
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const byte bOEMVendor = IOEMVENDOR;
PresentStatus iPresentStatus = {}, iPreviousStatus = {};

byte bRechargable = 1;
byte bCapacityMode = 2; // units are in %%
byte bCapacityMode = 1; // units are in mWh

// Physical parameters
const uint16_t iConfigVoltage = 1380;
Expand All @@ -43,76 +43,74 @@ const byte bCapacityGranularity1 = 1;
const byte bCapacityGranularity2 = 1;
byte iFullChargeCapacity = 100;

byte iRemaining =0, iPrevRemaining=0;
byte iRemaining[BATTERY_COUNT] = {48, 50, 51, 49, 50, 52}, iPrevRemaining=0;

int iRes=0;


void setup() {

Serial.begin(57600);

PowerDevice.begin();

for (int i = 0; i < BATTERY_COUNT; i++) {
PowerDevice[i].begin();

// Serial No is set in a special way as it forms Arduino port name
PowerDevice.setSerial(STRING_SERIAL);

// Used for debugging purposes.
PowerDevice.setOutput(Serial);
// Serial No is set in a special way as it forms Arduino port name
PowerDevice[i].setSerial(STRING_SERIAL);
}

pinMode(CHGDCHPIN, INPUT_PULLUP); // ground this pin to simulate power failure.
pinMode(RUNSTATUSPIN, OUTPUT); // output flushing 1 sec indicating that the arduino cycle is running.
pinMode(COMMLOSTPIN, OUTPUT); // output is on once communication is lost with the host, otherwise off.


PowerDevice.setFeature(HID_PD_PRESENTSTATUS, &iPresentStatus, sizeof(iPresentStatus));
for (int i = 0; i < BATTERY_COUNT; i++) {
PowerDevice[i].SetFeature(HID_PD_PRESENTSTATUS, &iPresentStatus, sizeof(iPresentStatus));

PowerDevice.setFeature(HID_PD_RUNTIMETOEMPTY, &iRunTimeToEmpty, sizeof(iRunTimeToEmpty));
PowerDevice.setFeature(HID_PD_AVERAGETIME2FULL, &iAvgTimeToFull, sizeof(iAvgTimeToFull));
PowerDevice.setFeature(HID_PD_AVERAGETIME2EMPTY, &iAvgTimeToEmpty, sizeof(iAvgTimeToEmpty));
PowerDevice.setFeature(HID_PD_REMAINTIMELIMIT, &iRemainTimeLimit, sizeof(iRemainTimeLimit));
PowerDevice.setFeature(HID_PD_DELAYBE4REBOOT, &iDelayBe4Reboot, sizeof(iDelayBe4Reboot));
PowerDevice.setFeature(HID_PD_DELAYBE4SHUTDOWN, &iDelayBe4ShutDown, sizeof(iDelayBe4ShutDown));
PowerDevice[i].SetFeature(HID_PD_RUNTIMETOEMPTY, &iRunTimeToEmpty, sizeof(iRunTimeToEmpty));
PowerDevice[i].SetFeature(HID_PD_AVERAGETIME2FULL, &iAvgTimeToFull, sizeof(iAvgTimeToFull));
PowerDevice[i].SetFeature(HID_PD_AVERAGETIME2EMPTY, &iAvgTimeToEmpty, sizeof(iAvgTimeToEmpty));
PowerDevice[i].SetFeature(HID_PD_REMAINTIMELIMIT, &iRemainTimeLimit, sizeof(iRemainTimeLimit));
PowerDevice[i].SetFeature(HID_PD_DELAYBE4REBOOT, &iDelayBe4Reboot, sizeof(iDelayBe4Reboot));
PowerDevice[i].SetFeature(HID_PD_DELAYBE4SHUTDOWN, &iDelayBe4ShutDown, sizeof(iDelayBe4ShutDown));

PowerDevice.setFeature(HID_PD_RECHARGEABLE, &bRechargable, sizeof(bRechargable));
PowerDevice.setFeature(HID_PD_CAPACITYMODE, &bCapacityMode, sizeof(bCapacityMode));
PowerDevice.setFeature(HID_PD_CONFIGVOLTAGE, &iConfigVoltage, sizeof(iConfigVoltage));
PowerDevice.setFeature(HID_PD_VOLTAGE, &iVoltage, sizeof(iVoltage));
PowerDevice[i].SetFeature(HID_PD_RECHARGEABLE, &bRechargable, sizeof(bRechargable));
PowerDevice[i].SetFeature(HID_PD_CAPACITYMODE, &bCapacityMode, sizeof(bCapacityMode));
PowerDevice[i].SetFeature(HID_PD_CONFIGVOLTAGE, &iConfigVoltage, sizeof(iConfigVoltage));
PowerDevice[i].SetFeature(HID_PD_VOLTAGE, &iVoltage, sizeof(iVoltage));

PowerDevice.setStringFeature(HID_PD_IDEVICECHEMISTRY, &bDeviceChemistry, STRING_DEVICECHEMISTRY);
PowerDevice.setStringFeature(HID_PD_IOEMINFORMATION, &bOEMVendor, STRING_OEMVENDOR);
PowerDevice[i].setStringFeature(HID_PD_IDEVICECHEMISTRY, &bDeviceChemistry, STRING_DEVICECHEMISTRY);
PowerDevice[i].setStringFeature(HID_PD_IOEMINFORMATION, &bOEMVendor, STRING_OEMVENDOR);

PowerDevice.setFeature(HID_PD_AUDIBLEALARMCTRL, &iAudibleAlarmCtrl, sizeof(iAudibleAlarmCtrl));
PowerDevice[i].SetFeature(HID_PD_AUDIBLEALARMCTRL, &iAudibleAlarmCtrl, sizeof(iAudibleAlarmCtrl));

PowerDevice.setFeature(HID_PD_DESIGNCAPACITY, &iDesignCapacity, sizeof(iDesignCapacity));
PowerDevice.setFeature(HID_PD_FULLCHRGECAPACITY, &iFullChargeCapacity, sizeof(iFullChargeCapacity));
PowerDevice.setFeature(HID_PD_REMAININGCAPACITY, &iRemaining, sizeof(iRemaining));
PowerDevice.setFeature(HID_PD_WARNCAPACITYLIMIT, &iWarnCapacityLimit, sizeof(iWarnCapacityLimit));
PowerDevice.setFeature(HID_PD_REMNCAPACITYLIMIT, &iRemnCapacityLimit, sizeof(iRemnCapacityLimit));
PowerDevice.setFeature(HID_PD_CPCTYGRANULARITY1, &bCapacityGranularity1, sizeof(bCapacityGranularity1));
PowerDevice.setFeature(HID_PD_CPCTYGRANULARITY2, &bCapacityGranularity2, sizeof(bCapacityGranularity2));
PowerDevice[i].SetFeature(HID_PD_DESIGNCAPACITY, &iDesignCapacity, sizeof(iDesignCapacity));
PowerDevice[i].SetFeature(HID_PD_FULLCHRGECAPACITY, &iFullChargeCapacity, sizeof(iFullChargeCapacity));
PowerDevice[i].SetFeature(HID_PD_REMAININGCAPACITY, &iRemaining[i], sizeof(iRemaining[i]));
PowerDevice[i].SetFeature(HID_PD_WARNCAPACITYLIMIT, &iWarnCapacityLimit, sizeof(iWarnCapacityLimit));
PowerDevice[i].SetFeature(HID_PD_REMNCAPACITYLIMIT, &iRemnCapacityLimit, sizeof(iRemnCapacityLimit));
PowerDevice[i].SetFeature(HID_PD_CPCTYGRANULARITY1, &bCapacityGranularity1, sizeof(bCapacityGranularity1));
PowerDevice[i].SetFeature(HID_PD_CPCTYGRANULARITY2, &bCapacityGranularity2, sizeof(bCapacityGranularity2));

uint16_t year = 2024, month = 10, day = 12;
iManufacturerDate = (year - 1980)*512 + month*32 + day; // from 4.2.6 Battery Settings in "Universal Serial Bus Usage Tables for HID Power Devices"
PowerDevice.setFeature(HID_PD_MANUFACTUREDATE, &iManufacturerDate, sizeof(iManufacturerDate));
PowerDevice[i].SetFeature(HID_PD_MANUFACTUREDATE, &iManufacturerDate, sizeof(iManufacturerDate));
}
}

void loop() {


//*********** Measurements Unit ****************************
bool bCharging = digitalRead(CHGDCHPIN);
bool bCharging = false; digitalRead(CHGDCHPIN);
bool bACPresent = bCharging; // TODO - replace with sensor
bool bDischarging = !bCharging; // TODO - replace with sensor
int iBattSoc = analogRead(BATTSOCPIN); // TODO - this is for debug only. Replace with charge estimation
int iBattSoc = 400; //analogRead(BATTSOCPIN); // TODO - this is for debug only. Replace with charge estimation

iRemaining = (byte)(round((float)iFullChargeCapacity*iBattSoc/1024));
iRunTimeToEmpty = (uint16_t)round((float)iAvgTimeToEmpty*iRemaining/iFullChargeCapacity);
//iRemaining = (byte)(round((float)iFullChargeCapacity*iBattSoc/1024));
iRunTimeToEmpty = (uint16_t)round((float)iAvgTimeToEmpty*iRemaining[0]/iFullChargeCapacity);

// Charging
iPresentStatus.Charging = bCharging;
iPresentStatus.ACPresent = bACPresent;
iPresentStatus.FullyCharged = (iRemaining == iFullChargeCapacity);
iPresentStatus.FullyCharged = (iRemaining[0] == iFullChargeCapacity);

// Discharging
if(bDischarging) {
Expand All @@ -130,7 +128,6 @@ void loop() {
// Shutdown requested
if(iDelayBe4ShutDown > 0 ) {
iPresentStatus.ShutdownRequested = 1;
Serial.println("shutdown requested");
}
else
iPresentStatus.ShutdownRequested = 0;
Expand All @@ -139,7 +136,6 @@ void loop() {
if((iPresentStatus.ShutdownRequested) ||
(iPresentStatus.RemainingTimeLimitExpired)) {
iPresentStatus.ShutdownImminent = 1;
Serial.println("shutdown imminent");
}
else
iPresentStatus.ShutdownImminent = 0;
Expand All @@ -164,11 +160,13 @@ void loop() {

//************ Bulk send or interrupt ***********************

if((iPresentStatus != iPreviousStatus) || (iRemaining != iPrevRemaining) || (iRunTimeToEmpty != iPrevRunTimeToEmpty) || (iIntTimer>MINUPDATEINTERVAL) ) {
if((iPresentStatus != iPreviousStatus) || (iRemaining[0] != iPrevRemaining) || (iRunTimeToEmpty != iPrevRunTimeToEmpty) || (iIntTimer>MINUPDATEINTERVAL) ) {

PowerDevice.sendReport(HID_PD_REMAININGCAPACITY, &iRemaining, sizeof(iRemaining));
if(bDischarging) PowerDevice.sendReport(HID_PD_RUNTIMETOEMPTY, &iRunTimeToEmpty, sizeof(iRunTimeToEmpty));
iRes = PowerDevice.sendReport(HID_PD_PRESENTSTATUS, &iPresentStatus, sizeof(iPresentStatus));
for (int i = 0; i < BATTERY_COUNT; i++) {
PowerDevice[i].SendReport(HID_PD_REMAININGCAPACITY, &iRemaining[0], sizeof(iRemaining[0]));
if(bDischarging) PowerDevice[i].SendReport(HID_PD_RUNTIMETOEMPTY, &iRunTimeToEmpty, sizeof(iRunTimeToEmpty));
iRes = PowerDevice[i].SendReport(HID_PD_PRESENTSTATUS, &iPresentStatus, sizeof(iPresentStatus));
}

if(iRes <0 ) {
digitalWrite(COMMLOSTPIN, HIGH);
Expand All @@ -178,13 +176,8 @@ void loop() {

iIntTimer = 0;
iPreviousStatus = iPresentStatus;
iPrevRemaining = iRemaining;
iPrevRemaining = iRemaining[0];
iPrevRunTimeToEmpty = iRunTimeToEmpty;
}


Serial.println(iRemaining);
Serial.println(iRunTimeToEmpty);
Serial.println(iRes);

}
18 changes: 5 additions & 13 deletions src/HID/HID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,13 @@

#if defined(USBCON)

HID_& HID()
{
static HID_ obj;
return obj;
}

int HID_::getInterface(uint8_t* interfaceCount)
{
*interfaceCount += 1; // uses 1
HIDDescriptor hidInterface = {
D_INTERFACE(pluggedInterface, 2, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE),
D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE),
D_HIDREPORT(descriptorSize),
D_ENDPOINT(USB_ENDPOINT_IN(HID_TX), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x14),
D_ENDPOINT(USB_ENDPOINT_OUT(HID_RX), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x0A)
D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x14)
};
return USB_SendControl(0, &hidInterface, sizeof(hidInterface));
}
Expand Down Expand Up @@ -168,9 +161,9 @@ bool HID_::LockFeature(uint16_t id, bool lock) {

int HID_::SendReport(uint16_t id, const void* data, int len)
{
auto ret = USB_Send(HID_TX, &id, 1);
auto ret = USB_Send(pluggedEndpoint, &id, 1);
if (ret < 0) return ret;
auto ret2 = USB_Send(HID_TX | TRANSFER_RELEASE, data, len);
auto ret2 = USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, len);
if (ret2 < 0) return ret2;
return ret + ret2;
}
Expand Down Expand Up @@ -254,12 +247,11 @@ bool HID_::setup(USBSetup& setup)
return false;
}

HID_::HID_(void) : PluggableUSBModule(2, 1, epType),
HID_::HID_(void) : PluggableUSBModule(1, 1, epType),
rootNode(NULL), descriptorSize(0),
protocol(HID_REPORT_PROTOCOL), idle(1)
{
epType[0] = EP_TYPE_INTERRUPT_IN;
epType[1] = EP_TYPE_INTERRUPT_OUT;
PluggableUSB().plug(this);
}

Expand Down
16 changes: 1 addition & 15 deletions src/HID/HID.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,6 @@
#define HID_REPORT_TYPE_OUTPUT 2
#define HID_REPORT_TYPE_FEATURE 3

#define HID_INTERFACE (CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT) // HID Interface
#define HID_FIRST_ENDPOINT (CDC_FIRST_ENDPOINT + CDC_ENPOINT_COUNT)
#define HID_ENDPOINT_INT (HID_FIRST_ENDPOINT)
#define HID_ENDPOINT_OUT (HID_FIRST_ENDPOINT+1)

#define HID_TX HID_ENDPOINT_INT
#define HID_RX HID_ENDPOINT_OUT //++ EP HID_RX for ease of use with USB_Available & USB_Rec

typedef struct
{
uint8_t len; // 9
Expand All @@ -87,7 +79,6 @@ typedef struct
InterfaceDescriptor hid;
HIDDescDescriptor desc;
EndpointDescriptor in;
EndpointDescriptor out; //added
} HIDDescriptor;

class HIDReport {
Expand Down Expand Up @@ -139,7 +130,7 @@ class HID_ : public PluggableUSBModule
uint8_t getShortName(char* name) override;

private:
uint8_t epType[2];
uint8_t epType[1];

HIDSubDescriptor* rootNode;
uint16_t descriptorSize;
Expand All @@ -157,11 +148,6 @@ class HID_ : public PluggableUSBModule

};

// Replacement for global singleton.
// This function prevents static-initialization-order-fiasco
// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use
HID_& HID();

#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0x21, 1, 0x22, lowByte(length), highByte(length) }

#endif // USBCON
Expand Down
34 changes: 9 additions & 25 deletions src/HIDPowerDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,56 +224,40 @@ static const uint8_t _hidReportDescriptor[] PROGMEM = {
HIDPowerDevice_::HIDPowerDevice_(void) {
static HIDSubDescriptor node(_hidReportDescriptor, sizeof (_hidReportDescriptor));

HID().AppendDescriptor(&node);
AppendDescriptor(&node);
}

void HIDPowerDevice_::begin(void) {
HID().begin();
HID_::begin();

// set string ID here

HID().SetFeature(HID_PD_IPRODUCT, &bProduct, sizeof(bProduct));
HID().SetFeature(HID_PD_SERIAL, &bSerial, sizeof(bSerial));
HID().SetFeature(HID_PD_MANUFACTURER, &bManufacturer, sizeof(bManufacturer));
SetFeature(HID_PD_IPRODUCT, &bProduct, sizeof(bProduct));
SetFeature(HID_PD_SERIAL, &bSerial, sizeof(bSerial));
SetFeature(HID_PD_MANUFACTURER, &bManufacturer, sizeof(bManufacturer));

}

void HIDPowerDevice_::setOutput(Serial_& out) {
HID().setOutput(out);
}

void HIDPowerDevice_::setSerial(const char* s) {
HID().setSerial(s);
}

void HIDPowerDevice_::end(void) {
}

int HIDPowerDevice_::sendDate(uint16_t id, uint16_t year, uint8_t month, uint8_t day) {
uint16_t bval = (year - 1980)*512 + month * 32 + day;
return HID().SendReport(id, &bval, sizeof (bval));
}

int HIDPowerDevice_::sendReport(uint16_t id, const void* bval, int len) {
return HID().SendReport(id, bval, len);
}

int HIDPowerDevice_::setFeature(uint16_t id, const void *data, int len) {
return HID().SetFeature(id, data, len);
return SendReport(id, &bval, sizeof (bval));
}

int HIDPowerDevice_::setStringFeature(uint8_t id, const uint8_t* index, const char* data) {

int res = HID().SetFeature(id, index, 1);
int res = SetFeature(id, index, 1);

if(res == 0) return 0;

res += HID().SetFeature(0xFF00 | *index , data, strlen_P(data));
res += SetFeature(0xFF00 | *index , data, strlen_P(data));

return res;
}

HIDPowerDevice_ PowerDevice;
HIDPowerDevice_ PowerDevice[BATTERY_COUNT];

#endif

15 changes: 4 additions & 11 deletions src/HIDPowerDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ static_assert(sizeof(PresentStatus) == sizeof(uint16_t));



class HIDPowerDevice_ {
class HIDPowerDevice_ : public HID_ {

private:

Expand All @@ -114,24 +114,17 @@ class HIDPowerDevice_ {
HIDPowerDevice_(void);
void begin(void);

void setOutput(Serial_&);

void setSerial(const char*);


void end(void);

int sendDate(uint16_t id, uint16_t year, uint8_t month, uint8_t day);
int sendReport(uint16_t id, const void* bval, int len);

int setFeature(uint16_t id, const void* data, int len);

int setStringFeature(uint8_t id, const uint8_t* index, const char* data);

};

extern HIDPowerDevice_ PowerDevice;
// as many batteries as supported by the HW
#define BATTERY_COUNT (USB_ENDPOINTS - CDC_FIRST_ENDPOINT - CDC_ENPOINT_COUNT) // 3 by default; 6 if defining CDC_DISABLED

extern HIDPowerDevice_ PowerDevice[BATTERY_COUNT];

#endif
#endif
Expand Down