Files
IronOS/source/Core/BSP/Pinecilv2/ble_handlers.cpp
Ben V. Brown baf2f26e59 Big overhaul of the UI framework (#1749)
* Starting GUI render refactor to be more immediate mode

Update TemperatureAdjust.cpp

.

Cleanup Soldering

Sleep

SolderingProfiles

Soldering Rework

Rough pass GUI

Temp Adjust

Cleanup old OperatingMode

Debug Menu

* Update TemperatureAdjust.cpp

* Roughing some transition work

* Fixup! Hook in the init starter helper

* Better home screen button handler

* FIXUP! Fix typo's

.

* Update SettingsMenu.cpp

* More settings rework

* More settings rendering

* Fixup

* Transitions

Update SolderingProfile.cpp

Hook in transistions

* Update TemperatureAdjust.cpp

* Update push.yml

* Add auto-repeat to settings menu

* Miniware: Use IT for I2C writes

* Update USBPDDebug_HUSB238.cpp

* Force write screen on side animation cancel

.

* Refactor moving down the settings list

* Update settingsGUI.cpp

* Update I2C_Wrapper.cpp

* Update OLED.cpp

* Rework button handling

* Fix PD debug at boot

* Fixup not showing right menu options

* silence some warnings

* Style cleanup

* Fkit use bit-bang I2C for Miniware

* Update GUIRendering.md

* Fixup transition on enter soldering mode

* Save Settings

* Fixes for some animations not running

Dont bail on animations if keypress is still held

* Fixup settings acceleration

* OLED Up animation

* Link up/down on debug meny

* Make all accelerometers I2C bus aware

Update accelerometers_common.h

* Make I2C mag optional

* Miniware -> Only Bit-Bang I2C

* Fixup for scrollbar

FIXUP! Debug menu returns to home screen

FIXUP! Up oled animation

Fix temp exit

* Settings menu -> Both buttons return a menu layer

* Merge fixup

* Update BMA223.cpp

* Re-Enable OLED sleep

* Save Setting on temp adjust exit

* WiP on startup mode

* Some autostart working

* Add hibernation mode & more autostart fixes

* If cant CJC; go to startup

* Hibernate in sleep

* Cleanup scroll indicator

* FIXUP! Ensure startup warnings are linked in

* FIXUP! Ensure we render out temp change before timing out

* Ensure 100ms delay between CJC samples

* Fix not re-calculating menu length on entering menu

* Implement NegotiationinProgress for USB-PD

* Mask heating until PD finishes negotiation

* Fixup staying in hibernate correctly

* Warning timeout

* Show reset settings warning

* Correctly compensate help text start time

* Update GUIThread.cpp

* Update USBPD.cpp

* .

* Fixup sleep time

* Update printSleepCountdown.cpp

* replacing countdown with big plus while in boost mode

* bringing back the + 1 since it was missing when not in boost mode

* Bail on USB-PD check after 3 seconds incase of DC source

* Fix hibernate

* Update PIDThread.cpp

* did center plus symbol (boost mode)

* Big refactor to not make settings increment handler handle the "is last item" return

* Fixup boot logo

* Fix flashing

* Fixup recalculate the menu length on long hold

* Fixup missing menu entries

* Fix junk left on screen after user confirmation

* Re-order button handler to use custom, then default order to allow setting associated setting

* Attach setting for settings using custom handler

* Fix swap +/- keys

* Fix boost temp

* Implement last menu option for Language selector

* Wait for init before CJC runs

* Check last setting via increment value

* Update BSP.cpp

* removed = from >=

Otherwise incrementing would stop and the scroll bar would already flash at the second to last value.

* (Hacky) Fix for Settings reset

---------

Co-authored-by: discip <53649486+discip@users.noreply.github.com>
2024-02-18 09:42:08 +11:00

318 lines
9.5 KiB
C++

#include <FreeRTOS.h>
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <task.h>
#include "types.h"
#include "BSP.h"
#include "TipThermoModel.h"
#include "ble_peripheral.h"
#include "bluetooth.h"
#include "configuration.h"
#include "conn.h"
#include "gatt.h"
#include "hal_clock.h"
#include "hci_core.h"
#include "log.h"
#include "uuid.h"
#include "../../version.h"
#include "OLED.hpp"
#include "OperatingModes.h"
#include "USBPD.h"
#include "ble_characteristics.h"
#include "ble_handlers.h"
#include "pd.h"
#include "power.hpp"
#ifdef POW_PD
#include "USBPD.h"
#include "pd.h"
#endif
extern TickType_t lastMovementTime;
extern OperatingMode currentOperatingMode;
int ble_char_read_status_callback(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) {
if (attr == NULL || attr->uuid == NULL) {
return 0;
}
// Decode the uuid
// Byte 12 has the lowest part of the first UUID chunk
uint16_t uuid_value = ((struct bt_uuid_128 *)attr->uuid)->val[12];
uint32_t temp = 0;
switch (uuid_value) {
case 1: // Live temp
{
temp = TipThermoModel::getTipInC();
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
} break;
case 2: // Setpoint temp
temp = getSettingValue(SettingsOptions::SolderingTemp);
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 3: // DC Input
temp = getInputVoltageX10(getSettingValue(SettingsOptions::VoltageDiv), 0);
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 4: // Handle temp
temp = getHandleTemperature(0);
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 5: // power level
// return current PWM level
temp = X10WattsToPWM(x10WattHistory.average());
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 6: // power src
// Todo return enum for current power source
temp = getPowerSrc();
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 7:
// Tip resistance
temp = getTipResistanceX10();
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 8:
// uptime
temp = xTaskGetTickCount() / TICKS_100MS;
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 9:
// movement
temp = lastMovementTime / TICKS_100MS;
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 10:
// max temp
temp = TipThermoModel::getTipMaxInC();
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 11:
// raw tip
temp = TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0), true);
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 12:
// hall sensor
{
int16_t hallEffectStrength = getRawHallEffect();
if (hallEffectStrength < 0) {
hallEffectStrength = -hallEffectStrength;
}
temp = hallEffectStrength;
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
}
break;
case 13:
// Operating mode
temp = (uint32_t)currentOperatingMode;
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
case 14:
// Estimated watts
temp = x10WattHistory.average();
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
break;
}
MSG((char *)"Unhandled attr read %d | %d\n", (uint32_t)attr->uuid, uuid_value);
return 0;
}
int ble_char_read_bulk_value_callback(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) {
if (attr == NULL || attr->uuid == NULL) {
return 0;
}
// Byte 12 has the lowest part of the first UUID chunk
uint16_t uuid_value = ((struct bt_uuid_128 *)attr->uuid)->val[12];
// Bulk is the non-const size service
switch (uuid_value) {
case 1:
// Bulk data
{
uint32_t bulkData[] = {
TipThermoModel::getTipInC(), // 0 - Current temp
getSettingValue(SettingsOptions::SolderingTemp), // 1 - Setpoint
getInputVoltageX10(getSettingValue(SettingsOptions::VoltageDiv), 0), // 2 - Input voltage
getHandleTemperature(0), // 3 - Handle X10 Temp in C
X10WattsToPWM(x10WattHistory.average()), // 4 - Power as PWM level
getPowerSrc(), // 5 - power src
getTipResistanceX10(), // 6 - Tip resistance
xTaskGetTickCount() / TICKS_100MS, // 7 - uptime in deciseconds
lastMovementTime / TICKS_100MS, // 8 - last movement time (deciseconds)
TipThermoModel::getTipMaxInC(), // 9 - max temp
TipThermoModel::convertTipRawADCTouV(getTipRawTemp(0), true), // 10 - Raw tip in μV
abs(getRawHallEffect()), // 11 - hall sensor
(uint32_t)currentOperatingMode, // 12 - Operating mode
x10WattHistory.average(), // 13 - Estimated Wattage *10
};
int lenToCopy = sizeof(bulkData) - offset;
if (lenToCopy > len) {
lenToCopy = len;
}
if (lenToCopy < 0) {
lenToCopy = 0;
}
memcpy(buf, ((uint8_t *)bulkData) + offset, lenToCopy);
return lenToCopy;
}
break;
case 2:
// Accelerometer name
// TODO: Need to store non-encoded version
break;
case 3:
// FW Version
memcpy(buf, &BUILD_VERSION, sizeof(BUILD_VERSION) - 1);
return sizeof(BUILD_VERSION) - 1;
case 4:
// Device serial number.
// Serial number is the ID burned by manufacturer.
// In case of Pinecil V2, device SN = device MAC.
{
uint64_t sn = getDeviceID();
memcpy(buf, &sn, sizeof(sn));
return sizeof(sn);
}
break;
case 5:
// Device ID [https://github.com/Ralim/IronOS/issues/1609].
// ID is a unique key Pine burns at the factory and records in their db.
{
uint32_t id = getDeviceValidation();
memcpy(buf, &id, sizeof(id));
return sizeof(id);
}
default:
break;
}
return 0;
}
int ble_char_read_setting_value_callback(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) {
if (attr == NULL || attr->uuid == NULL) {
return 0;
}
// Byte 12 has the lowest part of the first UUID chunk
uint16_t uuid_value = ((struct bt_uuid_128 *)attr->uuid)->val[12];
uint16_t temp = 0xFFFF;
if (uuid_value <= SettingsOptions::SettingsOptionsLength) {
temp = getSettingValue((SettingsOptions)(uuid_value));
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
} else {
memcpy(buf, &temp, sizeof(temp));
return sizeof(temp);
}
MSG((char *)"Unhandled attr read %d | %d\n", (uint32_t)attr->uuid, uuid_value);
return 0;
}
int ble_char_write_setting_value_callback(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, u16_t len, u16_t offset, u8_t flags) {
if (flags & BT_GATT_WRITE_FLAG_PREPARE) {
// Don't use prepare write data, execute write will upload data again.
BT_WARN((char *)"recv prepare write request\n");
return 0;
}
if (attr == NULL || attr->uuid == NULL) {
return 0;
}
if (flags & BT_GATT_WRITE_FLAG_CMD) {
// Use write command data.
BT_WARN((char *)"recv write command\n");
} else {
// Use write request / execute write data.
BT_WARN((char *)"recv write request / exce write\n");
}
uint8_t uuid_value = ((struct bt_uuid_128 *)attr->uuid)->val[12];
if (len == 2) {
uint16_t new_value = 0;
memcpy(&new_value, buf, sizeof(new_value));
if (uuid_value == 0xFF) {
if (new_value == 1) {
saveSettings();
return len;
}
} else if (uuid_value == 0xFE) {
if (new_value == 1) {
resetSettings();
return len;
}
} else if (uuid_value < SettingsOptions::SettingsOptionsLength) {
setSettingValue((SettingsOptions)(uuid_value), new_value);
switch (uuid_value) {
case SettingsOptions::OLEDInversion:
OLED::setInverseDisplay(getSettingValue(SettingsOptions::OLEDInversion));
break;
case SettingsOptions::OLEDBrightness:
OLED::setBrightness(getSettingValue(SettingsOptions::OLEDBrightness));
break;
case SettingsOptions::OrientationMode:
OLED::setRotation(getSettingValue(SettingsOptions::OrientationMode) & 1);
break;
default:
break;
}
return len;
}
}
MSG((char *)"Unhandled attr write %d | %d\n", (uint32_t)attr->uuid, uuid_value);
return 0;
}
uint32_t getPowerSrc() {
int sourceNumber = 0;
if (getIsPoweredByDCIN()) {
sourceNumber = 0;
} else {
// We are not powered via DC, so want to display the appropriate state for PD or QC
bool poweredbyPD = false;
bool pdHasVBUSConnected = false;
#ifdef POW_PD
if (USBPowerDelivery::fusbPresent()) {
// We are PD capable
if (USBPowerDelivery::negotiationComplete()) {
// We are powered via PD
poweredbyPD = true;
#ifdef VBUS_MOD_TEST
pdHasVBUSConnected = USBPowerDelivery::isVBUSConnected();
#endif
}
}
#endif
if (poweredbyPD) {
if (pdHasVBUSConnected) {
sourceNumber = 2;
} else {
sourceNumber = 3;
}
} else {
sourceNumber = 1;
}
}
return sourceNumber;
}