Update example to support LilyGo LoRa series

This commit is contained in:
lewisxhe 2020-12-08 11:33:03 +08:00
commit 4afcbe6ec6
276 changed files with 44743 additions and 767 deletions

View file

@ -0,0 +1,218 @@
/*
* A program that prints out the time (min/avg/max) taken by the
* AceButton::check() method.
*/
#include <AceButton.h>
#include "ProfilingButtonConfig.h"
using namespace ace_button;
// The pin number attached to the button.
const int BUTTON_PIN = 2;
ProfilingButtonConfig buttonConfig;
// One button wired using the ProfilingButtonConfig.
AceButton button(&buttonConfig);
const unsigned long STATS_PRINT_INTERVAL = 2000;
unsigned long lastStatsPrintedTime;
TimingStats stats;
const uint8_t LOOP_MODE_START = 0;
const uint8_t LOOP_MODE_IDLE = 1;
const uint8_t LOOP_MODE_PRESS_RELEASE = 2;
const uint8_t LOOP_MODE_CLICK = 3;
const uint8_t LOOP_MODE_DOUBLE_CLICK = 4;
const uint8_t LOOP_MODE_LONG_PRESS = 5;
const uint8_t LOOP_MODE_END = 6;
uint8_t loopMode;
uint8_t loopEventType;
void handleEvent(AceButton*, uint8_t, uint8_t);
void setup() {
delay(1000); // some microcontrollers reboot twice
Serial.begin(115200);
while (!Serial); // for Leonardo/Micro
Serial.println(F("setup(): begin"));
// Button uses the built-in pull up register.
pinMode(BUTTON_PIN, INPUT_PULLUP);
button.init(BUTTON_PIN);
// Configure the ButtonConfig with the event handler, and enable all higher
// level events.
buttonConfig.setEventHandler(handleEvent);
buttonConfig.setFeature(ButtonConfig::kFeatureClick);
buttonConfig.setFeature(ButtonConfig::kFeatureDoubleClick);
buttonConfig.setFeature(ButtonConfig::kFeatureLongPress);
buttonConfig.setFeature(ButtonConfig::kFeatureRepeatPress);
buttonConfig.setFeature(ButtonConfig::kFeatureSuppressAll);
buttonConfig.setTimingStats(&stats);
lastStatsPrintedTime = millis();
loopMode = LOOP_MODE_START;
loopEventType = AceButton::kEventPressed;
Serial.println(F("setup(): end"));
}
void loop() {
delay(1); // Decrease sampling frequency to about 1000 Hz
button.check();
switch (loopMode) {
case LOOP_MODE_START:
loopStart();
break;
case LOOP_MODE_IDLE:
loopIdle();
break;
case LOOP_MODE_PRESS_RELEASE:
loopPressRelease();
break;
case LOOP_MODE_CLICK:
loopClick();
break;
case LOOP_MODE_DOUBLE_CLICK:
loopDoubleClick();
break;
case LOOP_MODE_LONG_PRESS:
loopLongPress();
break;
case LOOP_MODE_END:
loopEnd();
break;
}
}
void loopStart() {
static unsigned long start = millis();
// Wait one iteration for things to cool down.
if (millis() - start > STATS_PRINT_INTERVAL) {
Serial.println(F("------------------------+-------------+---------+"));
Serial.println(F("button event | min/avg/max | samples |"));
Serial.println(F("------------------------+-------------+---------+"));
nextMode();
}
}
void loopEnd() {
Serial.println(F("------------------------+-------------+---------+"));
nextMode();
}
void loopIdle() {
static unsigned long start = millis();
if (millis() - start > STATS_PRINT_INTERVAL) {
Serial.print(F("idle | "));
printStats();
Serial.println(F(" |"));
nextMode();
}
}
void loopPressRelease() {
static unsigned long start = millis();
unsigned long now = millis();
unsigned long elapsed = now - start;
if (100 <= elapsed && elapsed < 1000) buttonConfig.setButtonState(LOW);
if (1000 <= elapsed) buttonConfig.setButtonState(HIGH);
if (millis() - start > STATS_PRINT_INTERVAL) {
if (loopEventType == AceButton::kEventReleased) {
Serial.print(F("press/release | "));
printStats();
Serial.println(F(" |"));
}
nextMode();
}
}
void loopClick() {
static unsigned long start = millis();
unsigned long now = millis();
unsigned long elapsed = now - start;
if (100 <= elapsed && elapsed < 200) buttonConfig.setButtonState(LOW);
if (200 <= elapsed) buttonConfig.setButtonState(HIGH);
if (millis() - start > STATS_PRINT_INTERVAL) {
if (loopEventType == AceButton::kEventClicked) {
Serial.print(F("click | "));
printStats();
Serial.println(F(" |"));
}
nextMode();
}
}
void loopDoubleClick() {
static unsigned long start = millis();
unsigned long now = millis();
unsigned long elapsed = now - start;
if (100 <= elapsed && elapsed < 200) buttonConfig.setButtonState(LOW);
if (200 <= elapsed && elapsed < 300) buttonConfig.setButtonState(HIGH);
if (300 <= elapsed && elapsed < 400) buttonConfig.setButtonState(LOW);
if (400 <= elapsed) buttonConfig.setButtonState(HIGH);
if (millis() - start > STATS_PRINT_INTERVAL) {
if (loopEventType == AceButton::kEventDoubleClicked) {
Serial.print(F("double click | "));
printStats();
Serial.println(F(" |"));
}
nextMode();
}
}
void loopLongPress() {
static unsigned long start = millis();
unsigned long now = millis();
unsigned long elapsed = now - start;
if (100 <= elapsed) buttonConfig.setButtonState(LOW);
if (millis() - start > STATS_PRINT_INTERVAL) {
if (loopEventType == AceButton::kEventRepeatPressed) {
Serial.print(F("long press/repeat press | "));
printStats();
Serial.println(F(" |"));
}
nextMode();
}
}
void nextMode() {
stats.reset();
buttonConfig.setButtonState(HIGH);
loopMode++;
}
void printStats() {
printInt(stats.getMin());
Serial.print('/');
printInt(stats.getAvg());
Serial.print('/');
printInt(stats.getMax());
Serial.print(F(" | "));
printInt(stats.getCount());
}
// print integer within 3 characters, padded on left with spaces
void printInt(uint16_t i) {
if (i < 100) Serial.print(' ');
if (i < 10) Serial.print(' ');
Serial.print(i);
}
// An empty event handler.
void handleEvent(AceButton* /* button */, uint8_t eventType,
uint8_t /* buttonState */) {
loopEventType = eventType;
}

View file

@ -0,0 +1,38 @@
#ifndef PROFILING_BUTTON_CONFIG_H
#define PROFILING_BUTTON_CONFIG_H
#include <Arduino.h> // LOW, HIGH
#include <ButtonConfig.h>
namespace ace_button {
/**
* A subclass of ButtonConfig which overrides readButton() so that the
* AutoBenchmark sketch can inject button clicks into the AceButton::check()
* loop, which we can use to collect timing stats.
*/
class ProfilingButtonConfig: public ButtonConfig {
public:
ProfilingButtonConfig():
mButtonState(HIGH) {}
void init() override {
ButtonConfig::init();
mButtonState = HIGH;
}
int readButton(uint8_t /* pin */) override { return mButtonState; }
/** Set the state of the fake physical button. */
void setButtonState(int buttonState) { mButtonState = buttonState; }
private:
// Disable copy-constructor and assignment operator
ProfilingButtonConfig(const ProfilingButtonConfig&) = delete;
ProfilingButtonConfig& operator=(const ProfilingButtonConfig&) = delete;
int mButtonState;
};
}
#endif

View file

@ -0,0 +1,111 @@
# AutoBenchmark
This sketch measures the amount of time consumed by the `AceButton::check()`
method when processing various button events. It uses a special
`ProfilingButtonConfig` object that allows the program to inject button events
into the library. The profiling numbers come from activating the `TimingStats`
object that has been instrumented into the `AceButton::check()` method.
Note that `ProfilingButtonConfig` class generates synthetic button events,
bypassing the actual `digitalRead()` function. The `digitalRead()` function on
an Arduino AVR platform (UNO, Nano, etc) is
[known to be slow](https://forum.arduino.cc/index.php?topic=337578)
which will add to the timing values in actual usage.
The [digitalWriteFast library](https://github.com/NicksonYap/digitalWriteFast)
might be an alternative if speed is critical.
## Benchmark Results
In all of the tests, the **min** time for the "idle" case is larger than any of
the other button events. This is because when a button event occurs, the
`AceButton::checkDebounced()` method returns immediately until the debouncing
time is over which brings down the minimum time. No debouncing is done in the
"idle" case so the minimum code path takes more CPU cycles.
All times are in microseconds. The "samples" column is the number of
`TimingStats::update()` calls that were made.
### Arduino Nano
* 16MHz ATmega328P
```
------------------------+-------------+---------+
button event | min/avg/max | samples |
------------------------+-------------+---------+
idle | 12/ 13/ 20 | 1934 |
press/release | 8/ 14/ 20 | 1925 |
click | 8/ 14/ 24 | 1925 |
double click | 8/ 13/ 24 | 1925 |
long press/repeat press | 8/ 15/ 24 | 1927 |
------------------------+-------------+---------+
```
### Arduino Pro Micro
* 16MHz ATmega32U4
```
------------------------+-------------+---------+
button event | min/avg/max | samples |
------------------------+-------------+---------+
idle | 12/ 13/ 24 | 1935 |
press/release | 8/ 14/ 24 | 1928 |
click | 8/ 13/ 24 | 1928 |
double click | 8/ 13/ 24 | 1926 |
long press/repeat press | 8/ 15/ 28 | 1928 |
------------------------+-------------+---------+
```
### Teensy 3.2
* 96 MHz ARM Cortex-M4
```
------------------------+-------------+---------+
button event | min/avg/max | samples |
------------------------+-------------+---------+
idle | 3/ 3/ 5 | 1985 |
press/release | 1/ 3/ 6 | 1983 |
click | 1/ 3/ 6 | 1984 |
double click | 1/ 3/ 6 | 1984 |
long press/repeat press | 1/ 3/ 6 | 1983 |
------------------------+-------------+---------+
```
### NodeMCU 1.0 clone
* 80MHz ESP8266
```
------------------------+-------------+---------+
button event | min/avg/max | samples |
------------------------+-------------+---------+
idle | 7/ 8/ 24 | 1922 |
press/release | 6/ 8/ 53 | 1919 |
click | 6/ 8/ 50 | 1920 |
double click | 6/ 8/ 67 | 1910 |
long press/repeat press | 6/ 9/ 60 | 1894 |
------------------------+-------------+---------+
```
The large **max** times for "double click" and "long press" seem to be
reproducible. I have not researched this but my speculation is that the system
WiFi code interrupts the `AceButton::check()` method right when the "double
click" and "long press" samples are taken, causing the extra latency.
### ESP32-01 Dev Board
* 240 MHz Tensilica LX6
```
------------------------+-------------+---------+
button event | min/avg/max | samples |
------------------------+-------------+---------+
idle | 3/ 3/ 3 | 2002 |
press/release | 2/ 2/ 8 | 2002 |
click | 2/ 2/ 7 | 2002 |
double click | 2/ 2/ 4 | 2002 |
long press/repeat press | 2/ 2/ 4 | 2002 |
------------------------+-------------+---------+
```