Added Screen2 - simple presentation with ability to toggle thermostat and change set point (keypad)
This commit is contained in:
parent
fc23538ceb
commit
efe8afeff3
|
@ -44,7 +44,31 @@ size_t C128x64_OLED::write(uint8_t c)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
void C128x64_OLED::getTextExtents(const char* str, uint16_t& w, uint16_t& h)
|
||||
{
|
||||
w = 0;
|
||||
h = 0;
|
||||
if(m_pFontInfo) {
|
||||
while(*str) {
|
||||
unsigned char c = (unsigned char)*str++;
|
||||
if(c >= m_pFontInfo->StartChar && c <= m_pFontInfo->EndChar) {
|
||||
const FONT_CHAR_INFO* pCharInfo = &m_pFontInfo->pCharInfo[c - m_pFontInfo->StartChar];
|
||||
// and extract info from flash (program) storage
|
||||
int xsize = pgm_read_byte(&pCharInfo->Width);
|
||||
int ysize = pgm_read_byte(&pCharInfo->Height);
|
||||
if(ysize > h)
|
||||
h = ysize;
|
||||
w += xsize;
|
||||
}
|
||||
if(*str) // check if next character exists, if so include space size
|
||||
w += m_pFontInfo->SpaceWidth;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int16_t x1, y1;
|
||||
Adafruit_SH1106::getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
C128x64_OLED::drawDotFactoryChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, const FONT_INFO* pFontDescriptor, int& xsize, int& ysize)
|
||||
|
|
|
@ -13,6 +13,8 @@ public:
|
|||
cursor_x += x;
|
||||
cursor_y += y;
|
||||
};
|
||||
void getTextExtents(const char* str, uint16_t& w, uint16_t& h);
|
||||
|
||||
void printRightJustify(const char* str, int yPos, int RHS=127);
|
||||
|
||||
size_t write(uint8_t c);
|
||||
|
|
|
@ -55,4 +55,4 @@
|
|||
#define TEMPERATURE_INTERVAL 1000
|
||||
|
||||
|
||||
#define SUPPORT_OEM_CONTROLLER 0
|
||||
#define SUPPORT_OEM_CONTROLLER 1
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
#include <OneWire.h>
|
||||
#include <DallasTemperature.h>
|
||||
#include "keypad.h"
|
||||
#include "helpers.h"
|
||||
|
||||
|
||||
#define FAILEDSSID "BTCESP32"
|
||||
|
@ -112,6 +113,7 @@ static HardwareSerial& BlueWireSerial(Serial1);
|
|||
|
||||
void initBlueWireSerial();
|
||||
bool validateFrame(const CProtocol& frame, const char* name);
|
||||
void checkDisplayUpdate();
|
||||
|
||||
// DS18B20 temperature sensor support
|
||||
OneWire ds(DS18B20_Pin); // on pin 5 (a 4.7K resistor is necessary)
|
||||
|
@ -139,7 +141,7 @@ const CProtocol* pRxFrame = NULL;
|
|||
const CProtocol* pTxFrame = NULL;
|
||||
|
||||
unsigned long moderator;
|
||||
|
||||
bool bUpdateDisplay = false;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Bluetooth instantiation
|
||||
|
@ -409,13 +411,6 @@ void loop()
|
|||
|
||||
moderator = 50;
|
||||
|
||||
// only update OLED when not processing blue wire
|
||||
tDelta = timenow - lastAnimationTime;
|
||||
if(tDelta >= 100) {
|
||||
lastAnimationTime += 100;
|
||||
animateOLED();
|
||||
}
|
||||
|
||||
#if RX_LED == 1
|
||||
digitalWrite(LED_Pin, LOW);
|
||||
#endif
|
||||
|
@ -448,9 +443,11 @@ void loop()
|
|||
//
|
||||
}
|
||||
else {
|
||||
checkDisplayUpdate();
|
||||
break; // only break if we fail all Idle state tests
|
||||
}
|
||||
#else
|
||||
checkDisplayUpdate();
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
@ -638,15 +635,14 @@ void loop()
|
|||
fFilteredTemperature = fFilteredTemperature * fAlpha + (1-fAlpha) * fTemperature;
|
||||
DefaultBTCParams.setTemperature_Actual((unsigned char)(fFilteredTemperature + 0.5)); // update [BTC] frame to send
|
||||
TempSensor.requestTemperatures(); // prep sensor for future reading
|
||||
|
||||
updateOLED(*pTxFrame, *pRxFrame);
|
||||
reqDisplayUpdate();
|
||||
}
|
||||
CommState.set(CommStates::Idle);
|
||||
break;
|
||||
} // switch(CommState)
|
||||
|
||||
BlueWireData.reset(); // ensure we flush any used data
|
||||
|
||||
|
||||
} // loop
|
||||
|
||||
void DebugReportFrame(const char* hdr, const CProtocol& Frame, const char* ftr)
|
||||
|
@ -780,7 +776,9 @@ bool validateFrame(const CProtocol& frame, const char* name)
|
|||
|
||||
int getRunState()
|
||||
{
|
||||
return pRxFrame->getRunState();
|
||||
if(pRxFrame)
|
||||
return pRxFrame->getRunState();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void requestOn()
|
||||
|
@ -810,3 +808,72 @@ void ToggleOnOff()
|
|||
}
|
||||
|
||||
|
||||
void reqTempChange(int val)
|
||||
{
|
||||
unsigned char curTemp = getSetTemp();
|
||||
|
||||
curTemp += val;
|
||||
unsigned char max = DefaultBTCParams.getTemperature_Max();
|
||||
unsigned char min = DefaultBTCParams.getTemperature_Min();
|
||||
if(curTemp >= max)
|
||||
curTemp = max;
|
||||
if(curTemp <= min)
|
||||
curTemp = min;
|
||||
|
||||
pNVStorage->setTemperature(curTemp);
|
||||
|
||||
reqDisplayUpdate();
|
||||
}
|
||||
|
||||
int getSetTemp()
|
||||
{
|
||||
// pTxFrame->getTemperature_Desired(); // sluggish - delays until new packet goes out!
|
||||
return pNVStorage->getTemperature();
|
||||
}
|
||||
|
||||
float getFixedHz()
|
||||
{
|
||||
if(pRxFrame) {
|
||||
return float(pRxFrame->getPump_Fixed()) / 10.f;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
void reqThermoToggle()
|
||||
{
|
||||
setThermostatMode(getThermostatMode() ? 0 : 1);
|
||||
}
|
||||
|
||||
void setThermostatMode(unsigned char val)
|
||||
{
|
||||
pNVStorage->setThermostatMode(val);
|
||||
}
|
||||
|
||||
|
||||
bool getThermostatMode()
|
||||
{
|
||||
return pNVStorage->getThermostatMode() != 0;
|
||||
}
|
||||
|
||||
void reqDisplayUpdate()
|
||||
{
|
||||
bUpdateDisplay = true;
|
||||
}
|
||||
|
||||
void checkDisplayUpdate()
|
||||
{
|
||||
// only update OLED when not processing blue wire
|
||||
if(bUpdateDisplay) {
|
||||
if(pTxFrame && pRxFrame) {
|
||||
updateOLED(*pTxFrame, *pRxFrame);
|
||||
bUpdateDisplay = false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long tDelta = millis() - lastAnimationTime;
|
||||
if(tDelta >= 100) {
|
||||
lastAnimationTime += 100;
|
||||
animateOLED();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
#include "128x64OLED.h"
|
||||
#include "MiniFont.h"
|
||||
#include "display.h"
|
||||
#include "tahoma16.h"
|
||||
#include "OLEDconsts.h"
|
||||
#include "BluetoothAbstract.h"
|
||||
#include "Screen1.h"
|
||||
#include "BTCWifi.h"
|
||||
#include "KeyPad.h"
|
||||
|
||||
#include "helpers.h"
|
||||
#include "Protocol.h"
|
||||
|
||||
bool animatePump = false;
|
||||
bool animateRPM = false;
|
||||
bool animateGlow = false;
|
||||
|
||||
extern float fFilteredTemperature;
|
||||
|
||||
void showThermometer(C128x64_OLED& display, float desired, float actual);
|
||||
void showBodyThermometer(C128x64_OLED& display, int actual);
|
||||
void showGlowPlug(C128x64_OLED& display, int power);
|
||||
|
@ -22,11 +21,6 @@ void showFan(C128x64_OLED& display, int RPM);
|
|||
void showFuel(C128x64_OLED& display, float rate);
|
||||
void showRunState(C128x64_OLED& display, int state, int errstate);
|
||||
|
||||
extern void ToggleOnOff();
|
||||
extern void requestOn();
|
||||
extern void requestOff();
|
||||
extern int getRunState();
|
||||
|
||||
#define MAXIFONT tahoma_16ptFontInfo
|
||||
#define MINIFONT miniFontInfo
|
||||
|
||||
|
@ -95,14 +89,6 @@ void showScreen1(C128x64_OLED& display, const CProtocol& CtlFrame, const CProtoc
|
|||
|
||||
showRunState(display, runstate, errstate);
|
||||
|
||||
#ifdef DEMO_LARGEFONT
|
||||
display.fillRect(20,20, 80,16, BLACK);
|
||||
display.setCursor(20,20);
|
||||
display.setFontInfo(&MAXIFONT); // Dot Factory Font
|
||||
display.print("25.6`");
|
||||
display.setFontInfo(NULL); // standard 5x7 font
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -332,6 +318,12 @@ void keyhandlerScreen1(uint8_t event)
|
|||
static int repeatCount = -1;
|
||||
if(event & keyPressed) {
|
||||
repeatCount = 0; // unlock tracking of repeat events
|
||||
if(event & key_Left) {
|
||||
prevScreen();
|
||||
}
|
||||
if(event & key_Right) {
|
||||
nextScreen();
|
||||
}
|
||||
}
|
||||
// require hold to turn ON or OFF
|
||||
if(event & keyRepeat) {
|
||||
|
@ -358,4 +350,3 @@ void keyhandlerScreen1(uint8_t event)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
#include "128x64OLED.h"
|
||||
#include "display.h"
|
||||
#include "MiniFont.h"
|
||||
#include "tahoma16.h"
|
||||
#include "OLEDconsts.h"
|
||||
#include "BluetoothAbstract.h"
|
||||
#include "Screen2.h"
|
||||
#include "BTCWifi.h"
|
||||
#include "KeyPad.h"
|
||||
#include "helpers.h"
|
||||
#include "Protocol.h"
|
||||
|
||||
|
||||
#define MAXIFONT tahoma_16ptFontInfo
|
||||
#define MINIFONT miniFontInfo
|
||||
|
||||
unsigned long showSetTemp = 0;
|
||||
unsigned long showMode = 0;
|
||||
unsigned char nModeSel;
|
||||
|
||||
void showScreen2(C128x64_OLED& display, const CProtocol& CtlFrame, const CProtocol& HtrFrame)
|
||||
{
|
||||
char msg[20];
|
||||
|
||||
sprintf(msg, "%.1f`", fFilteredTemperature);
|
||||
display.setFontInfo(&MAXIFONT); // Dot Factory Font
|
||||
uint16_t width, height;
|
||||
display.getTextExtents(msg, width, height);
|
||||
int xPos = 64 - (width/2);
|
||||
display.fillRect(xPos, 25, width, height, BLACK);
|
||||
display.setCursor(xPos, 25);
|
||||
display.print(msg);
|
||||
display.setFontInfo(NULL); // standard 5x7 font
|
||||
|
||||
if(showMode) {
|
||||
if(millis() < showMode) {
|
||||
strcpy(msg, "Fixed Hz");
|
||||
display.getTextExtents(msg, width, height);
|
||||
int yPos = 63 - height - 2;
|
||||
display.setCursor(2, yPos);
|
||||
display.print(msg);
|
||||
if(nModeSel == 0) {
|
||||
display.drawRoundRect(0, yPos-2, width+4, height+4, 3, WHITE);
|
||||
}
|
||||
strcpy(msg, "Thermostat");
|
||||
display.getTextExtents(msg, width, height);
|
||||
int xPos = 127 - width - 2;
|
||||
display.setCursor(xPos, yPos);
|
||||
display.print(msg);
|
||||
if(nModeSel == 1) {
|
||||
display.drawRoundRect(xPos - 2, yPos-2, width+4, height+4, 3, WHITE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
showMode = 0;
|
||||
setThermostatMode(nModeSel);
|
||||
}
|
||||
}
|
||||
else if(millis() < showSetTemp) {
|
||||
if(getThermostatMode()) {
|
||||
sprintf(msg, "Setpoint = %d`C", getSetTemp());
|
||||
}
|
||||
else {
|
||||
sprintf(msg, "Setpoint = %.1fHz", getFixedHz());
|
||||
}
|
||||
display.getTextExtents(msg, width, height);
|
||||
xPos = 64 - (width/2); // centre across
|
||||
int yPos = 63 - height; // at bottom of screen
|
||||
display.setCursor(xPos, yPos);
|
||||
display.print(msg);
|
||||
}
|
||||
else {
|
||||
int runState = getRunState();
|
||||
if(runState) {
|
||||
const char* pMsg;
|
||||
if(runState < 5) {
|
||||
pMsg = "Starting";
|
||||
}
|
||||
else if(runState == 5) {
|
||||
pMsg = "Running";
|
||||
}
|
||||
else {
|
||||
pMsg = "Shutting down";
|
||||
}
|
||||
|
||||
display.getTextExtents(pMsg, width, height);
|
||||
int xPos = 64 - (width/2); // centre across
|
||||
int yPos = 63 - height; // at bottom of screen
|
||||
display.setCursor(xPos, yPos);
|
||||
display.print(pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void animateScreen2(C128x64_OLED& display)
|
||||
{
|
||||
display.display();
|
||||
}
|
||||
|
||||
void keyhandlerScreen2(uint8_t event)
|
||||
{
|
||||
static int repeatCount = -1;
|
||||
if(event & keyPressed) {
|
||||
repeatCount = 0; // unlock tracking of repeat events
|
||||
// press LEFT to select previous screen, or Fixed Hz mode when in mode select
|
||||
if(event & key_Left) {
|
||||
if(!showMode)
|
||||
prevScreen();
|
||||
else {
|
||||
showMode = millis() + 5000;
|
||||
nModeSel = 0;
|
||||
reqDisplayUpdate();
|
||||
}
|
||||
}
|
||||
// press RIGHT to selecxt next screen, or Thermostat mode when in mode select
|
||||
if(event & key_Right) {
|
||||
if(!showMode)
|
||||
nextScreen();
|
||||
else {
|
||||
showMode = millis() + 5000;
|
||||
nModeSel = 1;
|
||||
reqDisplayUpdate();
|
||||
}
|
||||
}
|
||||
// press UP & DOWN to toggle thermostat / fixed Hz mode
|
||||
uint8_t doubleKey = key_Down | key_Up;
|
||||
if((event & doubleKey) == doubleKey) {
|
||||
reqThermoToggle();
|
||||
showSetTemp = millis() + 2000;
|
||||
}
|
||||
// press CENTRE to accept new mode, and/or show current setting
|
||||
if(event & key_Centre) {
|
||||
if(showMode) {
|
||||
setThermostatMode(nModeSel);
|
||||
}
|
||||
showMode = 0;
|
||||
showSetTemp = millis() + 2000;
|
||||
}
|
||||
}
|
||||
// use repeat function for key hold detection
|
||||
if(event & keyRepeat) {
|
||||
if(repeatCount >= 0) {
|
||||
repeatCount++;
|
||||
// hold DOWN to enter thermostat / fixed mode selection
|
||||
if(event & key_Down) {
|
||||
if(repeatCount > 2) {
|
||||
repeatCount = -1; // prevent double handling
|
||||
showMode = millis() + 5000;
|
||||
nModeSel = getThermostatMode();
|
||||
}
|
||||
}
|
||||
// hold CENTRE to turn ON or OFF
|
||||
if(event & key_Centre) {
|
||||
if(getRunState()) {
|
||||
// running, request OFF
|
||||
if(repeatCount > 5) {
|
||||
repeatCount = -1; // prevent double handling
|
||||
requestOff();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// standby, request ON
|
||||
if(repeatCount > 3) {
|
||||
repeatCount = -1;
|
||||
requestOn();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(event & keyReleased) {
|
||||
if(!showMode) {
|
||||
// release DOWN key to reduce set demand, provided we are not in mode select
|
||||
if(event & key_Down) {
|
||||
reqTempChange(-1);
|
||||
showSetTemp = millis() + 2000;
|
||||
}
|
||||
// release UP key to increase set demand, provided we are not in mode select
|
||||
if(event & key_Up) {
|
||||
reqTempChange(+1);
|
||||
showSetTemp = millis() + 2000;
|
||||
}
|
||||
}
|
||||
repeatCount = -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include "stdint.h"
|
||||
|
||||
class C128x64_OLED;
|
||||
class CProtocol;
|
||||
|
||||
void showScreen2(C128x64_OLED& display, const CProtocol& CtlFrame, const CProtocol& HtrFrame);
|
||||
void animateScreen2(C128x64_OLED& display);
|
||||
|
||||
void keyhandlerScreen2(uint8_t event);
|
|
@ -10,7 +10,9 @@
|
|||
#include "BTCWifi.h"
|
||||
#include "BluetoothAbstract.h"
|
||||
#include "Screen1.h"
|
||||
#include "Screen2.h"
|
||||
#include "KeyPad.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#define MAXIFONT tahoma_16ptFontInfo
|
||||
#define MINIFONT miniFontInfo
|
||||
|
@ -27,6 +29,10 @@
|
|||
void showBTicon(C128x64_OLED& display);
|
||||
void showWifiIcon(C128x64_OLED& display);
|
||||
void showBatteryIcon(C128x64_OLED& display, float voltage);
|
||||
void switchScreen();
|
||||
|
||||
static int currentScreen = 0;
|
||||
const int maxScreens = 2;
|
||||
|
||||
//
|
||||
// **** NOTE: There are two very lame libaries conspiring to make life difficult ****
|
||||
|
@ -40,29 +46,12 @@ void showBatteryIcon(C128x64_OLED& display, float voltage);
|
|||
|
||||
// 128 x 64 OLED support
|
||||
SPIClass SPI; // default constructor opens HSPI on standard pins : MOSI=13,CLK=14,MISO=12(unused)
|
||||
//Adafruit_SH1106 display(OLED_DC_pin, -1, OLED_CS_pin);
|
||||
C128x64_OLED display(OLED_DC_pin, -1, OLED_CS_pin);
|
||||
|
||||
/*bool animatePump = false;
|
||||
bool animateRPM = false;
|
||||
bool animateGlow = false;
|
||||
*/
|
||||
/*extern float fFilteredTemperature;
|
||||
extern CBluetoothAbstract& getBluetoothClient();
|
||||
|
||||
void showThermometer(float desired, float actual);
|
||||
void showBodyThermometer(int actual);
|
||||
void showBTicon();
|
||||
void showWifiIcon();
|
||||
void showBatteryIcon(float voltage);
|
||||
void showGlowPlug(int power);
|
||||
void showFan(int RPM);
|
||||
void showFuel(float rate);
|
||||
void showRunState(int state, int errstate);
|
||||
void printRightJustify(const char* str, int yPos, int RHS=128);
|
||||
*/
|
||||
void initOLED()
|
||||
{
|
||||
currentScreen = 0;
|
||||
|
||||
SPI.setFrequency(8000000);
|
||||
// SH1106_SWITCHCAPVCC = generate display voltage from 3.3V internally
|
||||
display.begin(SH1106_SWITCHCAPVCC, 0, false);
|
||||
|
@ -77,7 +66,14 @@ void initOLED()
|
|||
|
||||
void animateOLED()
|
||||
{
|
||||
animateScreen1(display);
|
||||
switch(currentScreen) {
|
||||
case 0:
|
||||
animateScreen1(display);
|
||||
break;
|
||||
case 1:
|
||||
animateScreen2(display);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -102,7 +98,14 @@ void updateOLED(const CProtocol& CtlFrame, const CProtocol& HtrFrame)
|
|||
float voltage = HtrFrame.getVoltage_Supply() * 0.1f;
|
||||
showBatteryIcon(display, voltage);
|
||||
|
||||
showScreen1(display, CtlFrame, HtrFrame);
|
||||
switch(currentScreen) {
|
||||
case 0:
|
||||
showScreen1(display, CtlFrame, HtrFrame);
|
||||
break;
|
||||
case 1:
|
||||
showScreen2(display, CtlFrame, HtrFrame);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void showBTicon(C128x64_OLED& display)
|
||||
|
@ -139,3 +142,34 @@ void showBatteryIcon(C128x64_OLED& display, float voltage)
|
|||
if(Capacity > 11) Capacity = 11;
|
||||
display.fillRect(X_BATT_ICON+2 + Capacity, Y_BATT_ICON+2, W_BATT_ICON-4-Capacity, 6, BLACK);
|
||||
}
|
||||
|
||||
void nextScreen()
|
||||
{
|
||||
currentScreen++;
|
||||
if(currentScreen >= maxScreens) {
|
||||
currentScreen = 0;
|
||||
}
|
||||
switchScreen();
|
||||
}
|
||||
|
||||
void prevScreen()
|
||||
{
|
||||
currentScreen--;
|
||||
if(currentScreen < 0) {
|
||||
currentScreen = maxScreens-1;
|
||||
}
|
||||
switchScreen();
|
||||
}
|
||||
|
||||
void switchScreen()
|
||||
{
|
||||
switch(currentScreen) {
|
||||
case 0:
|
||||
KeyPad.setCallback(keyhandlerScreen1);
|
||||
break;
|
||||
case 1:
|
||||
KeyPad.setCallback(keyhandlerScreen2);
|
||||
break;
|
||||
}
|
||||
reqDisplayUpdate();
|
||||
}
|
||||
|
|
|
@ -9,4 +9,8 @@ void initOLED();
|
|||
void updateOLED(const CProtocol& CtlFrame, const CProtocol& HtrFrame);
|
||||
void animateOLED();
|
||||
|
||||
void nextScreen();
|
||||
void prevScreen();
|
||||
|
||||
|
||||
#endif // __DISPLAY_H__
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
extern void ToggleOnOff();
|
||||
extern void requestOn();
|
||||
extern void requestOff();
|
||||
extern int getRunState();
|
||||
extern void reqTempChange(int val);
|
||||
extern void tempDec();
|
||||
extern int getSetTemp();
|
||||
extern void reqDisplayUpdate();
|
||||
extern void reqThermoToggle();
|
||||
extern void setThermostatMode(unsigned char);
|
||||
extern bool getThermostatMode();
|
||||
extern float getFixedHz();
|
||||
|
||||
extern float fFilteredTemperature;
|
|
@ -142,7 +142,7 @@ CKeyPad::update()
|
|||
|
||||
if(Press) {
|
||||
if(_keyCallback != NULL)
|
||||
_keyCallback(keyPressed | Press);
|
||||
_keyCallback(keyPressed | Press | newKey);
|
||||
return keyPressed | Press;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 299 KiB |
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
Loading…
Reference in New Issue