Skip to content
Snippets Groups Projects
Unverified Commit 735f5437 authored by Sagar Dhawan's avatar Sagar Dhawan Committed by GitHub
Browse files

Show a QRCode and status on the M5Stack's display (#890)


* Add display support for the ESP32

* Attempt to use real payload

* Restyled by clang-format

* Leave the DevKit-C as the default device

* Fix the ESP build in CI

* Update docs

* Restyled by prettier-markdown

* Minor tweak to docs

* Restyled by prettier-markdown

* Fix missing word in doc

Co-authored-by: default avatarRestyled.io <commits@restyled.io>
parent ab814a9a
No related branches found
No related tags found
No related merge requests found
Showing
with 779 additions and 15 deletions
...@@ -27,6 +27,8 @@ third_party/nlfaultinjection/ ...@@ -27,6 +27,8 @@ third_party/nlfaultinjection/
third_party/nlio/ third_party/nlio/
third_party/nlunit-test/ third_party/nlunit-test/
third_party/mbedtls/ third_party/mbedtls/
examples/common/m5stack-tft/
examples/common/QRCode/repo
# Example specific rules # Example specific rules
examples/**/sdkconfig examples/**/sdkconfig
......
...@@ -142,7 +142,8 @@ COMPONENT_ADD_INCLUDEDIRS = project-config \ ...@@ -142,7 +142,8 @@ COMPONENT_ADD_INCLUDEDIRS = project-config \
$(REL_CHIP_ROOT)/src/lib \ $(REL_CHIP_ROOT)/src/lib \
$(REL_CHIP_ROOT)/src/ \ $(REL_CHIP_ROOT)/src/ \
$(REL_CHIP_ROOT)/src/system \ $(REL_CHIP_ROOT)/src/system \
$(IDF_PATH)/components/mbedtls/mbedtls/include $(IDF_PATH)/components/mbedtls/mbedtls/include \
$(REL_CHIP_ROOT)/src/app \
# Linker flags to be included when building other components that use CHIP. # Linker flags to be included when building other components that use CHIP.
...@@ -151,7 +152,8 @@ COMPONENT_ADD_LDFLAGS = -L$(OUTPUT_DIR)/lib/ \ ...@@ -151,7 +152,8 @@ COMPONENT_ADD_LDFLAGS = -L$(OUTPUT_DIR)/lib/ \
-lInetLayer \ -lInetLayer \
-lSystemLayer \ -lSystemLayer \
-lDeviceLayer \ -lDeviceLayer \
-lChipCrypto -lChipCrypto \
-lSetupPayload
# Tell the ESP-IDF build system that the CHIP component defines its own build # Tell the ESP-IDF build system that the CHIP component defines its own build
# and clean targets. # and clean targets.
......
#
# Copyright (c) 2020 Project CHIP Authors
# Copyright (c) 2018 Nest Labs, Inc.
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Description:
# Component makefile for the QRCode component used by the CHIP
# ESP32 demo applications.
#
CFLAGS += -Wno-unknown-pragmas
COMPONENT_ADD_INCLUDEDIRS := repo/c
COMPONENT_SRCDIRS := repo/c
COMPONENT_OBJS := repo/c/qrcodegen.o
#
# Copyright (c) 2020 Project CHIP Authors
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# #
# This is a project Makefile. It is assumed the directory this Makefile resides in is a # This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory. # project subdirectory.
...@@ -5,6 +21,8 @@ ...@@ -5,6 +21,8 @@
PROJECT_NAME := chip-wifi-echo PROJECT_NAME := chip-wifi-echo
EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/third_party/connectedhomeip/config/esp32/components EXTRA_COMPONENT_DIRS += $(PROJECT_PATH)/third_party/connectedhomeip/config/esp32/components \
$(PROJECT_PATH)/../../../common/m5stack-tft/repo/components \
$(PROJECT_PATH)/../../../common/QRCode \
include $(IDF_PATH)/make/project.mk include $(IDF_PATH)/make/project.mk
...@@ -18,8 +18,9 @@ messaging is supported in CHIP. ...@@ -18,8 +18,9 @@ messaging is supported in CHIP.
The CHIP demo application is intended to work on two categories of ESP32 The CHIP demo application is intended to work on two categories of ESP32
devices: the devices: the
[ESP32-DevKitC](https://www.espressif.com/en/products/hardware/esp32-devkitc/overview), [ESP32-DevKitC](https://www.espressif.com/en/products/hardware/esp32-devkitc/overview),
and the [M5Stack](http://m5stack.com). Support for the and the [M5Stack](http://m5stack.com). On the [M5Stack](http://m5stack.com) this
[M5Stack](http://m5stack.com) is still a Work in Progress. example displays a CHIP QRCode with the device's Soft-AP SSID encoded in the TLV
section.
## Building the Example Application ## Building the Example Application
...@@ -45,13 +46,25 @@ step. To install these components manually, follow these steps: ...@@ -45,13 +46,25 @@ step. To install these components manually, follow these steps:
Currently building in VSCode _and_ deploying from native is not supported, so Currently building in VSCode _and_ deploying from native is not supported, so
make sure the IDF_PATH has been exported(See the manual setup steps above). make sure the IDF_PATH has been exported(See the manual setup steps above).
- In the root of the example directory, source `idf.sh` and use the - In the root of the example directory, sync the dependencies and source
`defconfig` make target to configure the application with defaults. `idf.sh`. Note: This does not have to be repeated for incremental builds.
$ make -C third_party/connectedhomeip -f Makefile-bootstrap repos
$ source idf.sh $ source idf.sh
- Next, if you want to use the M5Stack with its display and show a QRCode run
`menuconfig`.
$ idf make menuconfig
While in the configurator, navigate to `WiFi Echo Demo`->`Device Type` and
select `M5Stack`.
Otherwise, run the default config.
$ idf make defconfig $ idf make defconfig
- Run make to build the demo application - Run make to build the demo application.
$ idf make $ idf make
...@@ -105,6 +118,10 @@ There are two ways to use the Echo Server running on the device. ...@@ -105,6 +118,10 @@ There are two ways to use the Echo Server running on the device.
I (5524) chip[DL]: SYSTEM_EVENT_STA_GOT_IP I (5524) chip[DL]: SYSTEM_EVENT_STA_GOT_IP
I (5524) chip[DL]: IPv4 address changed on WiFi station interface: <IP_ADDRESS>... I (5524) chip[DL]: IPv4 address changed on WiFi station interface: <IP_ADDRESS>...
Note: If you are using the M5Stack, the screen will display the server's IP
Address and Port if it successfully conencts to the configured 2.4GHz
Network.
5. Then running the following command will ping the ESP32 and cause it to echo. 5. Then running the following command will ping the ESP32 and cause it to echo.
If necessary replace the `<IP_ADDRESS>` with the address printed by the If necessary replace the `<IP_ADDRESS>` with the address printed by the
device in the monitor. device in the monitor.
...@@ -120,9 +137,10 @@ your network configuration. To erase it, simply run. ...@@ -120,9 +137,10 @@ your network configuration. To erase it, simply run.
Alternatively, you can connect to the ESP32's Soft-AP directly. Alternatively, you can connect to the ESP32's Soft-AP directly.
1. After the application has been flashed, connect the ESP32's Soft-AP. It's 1. After the application has been flashed, connect the ESP32's Soft-AP. If you
usually something like `CHIP_DEMO-XXXX` where the last 4 digits are from the use the M5Stack, the Soft-AP's SSID is encoded in the TLV section of the
device's MAC address. QRCode on screen. It's usually something like `CHIP_DEMO-XXXX` where the
last 4 digits are from the device's MAC address.
2. Once you're connected, the server's IP can be found at the gateway address 2. Once you're connected, the server's IP can be found at the gateway address
and at the listed port number(Default: `8000`). and at the listed port number(Default: `8000`).
......
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2018 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_system.h"
#include "Button.h"
#include <platform/CHIPDeviceLayer.h>
#include <support/CodeUtils.h>
extern const char * TAG;
esp_err_t Button::Init(gpio_num_t gpioNum, uint16_t debouncePeriod)
{
esp_err_t err;
mGPIONum = gpioNum;
mDebouncePeriod = debouncePeriod / portTICK_PERIOD_MS;
mState = false;
mLastState = false;
err = gpio_set_direction(gpioNum, GPIO_MODE_INPUT);
SuccessOrExit(err);
Poll();
exit:
return err;
}
bool Button::Poll()
{
uint32_t now = xTaskGetTickCount();
bool newState = gpio_get_level(mGPIONum) == 0;
if (newState != mLastState)
{
mLastState = newState;
mLastReadTime = now;
}
else if (newState != mState && (now - mLastReadTime) >= mDebouncePeriod)
{
mState = newState;
mPrevStateDur = now - mStateStartTime;
mStateStartTime = now;
return true;
}
return false;
}
uint32_t Button::GetStateDuration()
{
return (xTaskGetTickCount() - mStateStartTime) * portTICK_PERIOD_MS;
}
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2018 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "driver/ledc.h"
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "Display.h"
#if CONFIG_HAVE_DISPLAY
#define DEF_BRIGHTNESS_PERCENT 80
// with a duty resolution of LEDC_TIMER_8_BIT
// the highest possible brightness value is 255
#define BRIGHTNESS_MAX 255
// The M5Stack's backlight is on Channel 7
#define BACKLIGHT_CHANNEL LEDC_CHANNEL_7
extern const char * TAG;
uint16_t DisplayHeight = 0;
uint16_t DisplayWidth = 0;
// FreeRTOS timer used to turn the display off after a short while
TimerHandle_t displayTimer = NULL;
static void TimerCallback(TimerHandle_t xTimer);
static void SetupBrightnessControl();
void SetBrightness(uint16_t brightness);
esp_err_t InitDisplay()
{
esp_err_t err;
spi_lobo_device_handle_t spi;
spi_lobo_bus_config_t buscfg;
memset((void *) &buscfg, 0, sizeof(buscfg));
buscfg.miso_io_num = PIN_NUM_MISO; // set SPI MISO pin
buscfg.mosi_io_num = PIN_NUM_MOSI; // set SPI MOSI pin
buscfg.sclk_io_num = PIN_NUM_CLK; // set SPI CLK pin
buscfg.quadwp_io_num = -1;
buscfg.quadhd_io_num = -1;
buscfg.max_transfer_sz = 6 * 1024;
spi_lobo_device_interface_config_t devcfg;
memset((void *) &devcfg, 0, sizeof(devcfg));
devcfg.clock_speed_hz = 8000000; // Initial clock out at 8 MHz
devcfg.mode = 0; // SPI mode 0
devcfg.spics_io_num = -1; // we will use external CS pin
devcfg.spics_ext_io_num = PIN_NUM_CS; // external CS pin
devcfg.flags = LB_SPI_DEVICE_HALFDUPLEX; // ALWAYS SET to HALF DUPLEX MODE!! for display spi
tft_disp_type = DISP_TYPE_ILI9341;
tft_max_rdclock = 8000000;
// Initialize all pins used by display driver.
TFT_PinsInit();
// Initialize SPI bus and add a device for the display.
err = spi_lobo_bus_add_device(TFT_HSPI_HOST, &buscfg, &devcfg, &spi);
if (err != ESP_OK)
return err;
// Configure the display to use the new SPI device.
tft_disp_spi = spi;
err = spi_lobo_device_select(spi, 1);
if (err != ESP_OK)
return err;
err = spi_lobo_device_deselect(spi);
if (err != ESP_OK)
return err;
// Initialize the display driver.
TFT_display_init();
// ---- Detect maximum read speed ----
tft_max_rdclock = find_rd_speed();
// Set the SPI clock speed.
spi_lobo_set_speed(spi, DEFAULT_SPI_CLOCK);
TFT_setGammaCurve(0);
TFT_setRotation(LANDSCAPE);
TFT_resetclipwin();
DisplayWidth = (uint16_t)(1 + tft_dispWin.x2 - tft_dispWin.x1);
DisplayHeight = (uint16_t)(1 + tft_dispWin.y2 - tft_dispWin.y1);
ESP_LOGI(TAG, "Display initialized (height %u, width %u)", DisplayHeight, DisplayWidth);
// for some reason this is backwards (turns out this is because of a rece2019nt update to the m5stack hw)
TFT_invertDisplay(INVERT_ON);
// prepare the display for brightness control
SetupBrightnessControl();
displayTimer = xTimerCreate("DisplayTimer", pdMS_TO_TICKS(DISPLAY_TIMEOUT_MS), false, NULL, TimerCallback);
// lower the brightness of the screen
WakeDisplay();
return err;
}
void SetBrightness(uint16_t brightness)
{
uint16_t brightness_percent = (brightness * BRIGHTNESS_MAX) / 100;
if (ledc_set_duty(LEDC_HIGH_SPEED_MODE, BACKLIGHT_CHANNEL, brightness_percent) ||
ledc_update_duty(LEDC_HIGH_SPEED_MODE, BACKLIGHT_CHANNEL))
{
ESP_LOGE(TAG, "Failed to set display brightness...");
}
}
void WakeDisplay()
{
SetBrightness(DEF_BRIGHTNESS_PERCENT);
xTimerStart(displayTimer, 0);
ESP_LOGI(TAG, "Display awake but will switch off automatically in %d seconds", DISPLAY_TIMEOUT_MS / 1000);
}
void ClearDisplay()
{
TFT_fillRect(0, 0, (int) DisplayWidth, (int) DisplayHeight, TFT_BLACK);
}
void DisplayStatusMessage(char * msg, uint16_t vpos)
{
TFT_setFont(SMALL_FONT, NULL);
uint16_t msgX = 0;
uint16_t msgY = (DisplayHeight * vpos) / 100;
TFT_print(msg, msgX, msgY);
}
void TimerCallback(TimerHandle_t xTimer)
{
ESP_LOGI(TAG, "Display going to sleep...");
SetBrightness(0);
}
void SetupBrightnessControl()
{
ledc_timer_config_t ledc_timer;
memset(&ledc_timer, 0, sizeof(ledc_timer));
ledc_timer.duty_resolution = LEDC_TIMER_8_BIT; // resolution of PWM duty
ledc_timer.freq_hz = 1000; // frequency of PWM signal
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; // timer mode
ledc_timer.timer_num = LEDC_TIMER_0; // timer index
ledc_timer_config(&ledc_timer);
ledc_timer_set(LEDC_HIGH_SPEED_MODE, LEDC_TIMER_0, 1000, LEDC_TIMER_8_BIT, LEDC_REF_TICK);
ledc_channel_config_t ledc_channel;
memset(&ledc_channel, 0, sizeof(ledc_channel));
ledc_channel.channel = BACKLIGHT_CHANNEL;
ledc_channel.duty = BRIGHTNESS_MAX;
ledc_channel.gpio_num = PIN_NUM_BCKL;
ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
ledc_channel.timer_sel = LEDC_TIMER_0;
ledc_channel_config(&ledc_channel);
}
#endif // CONFIG_HAVE_DISPLAY
...@@ -44,7 +44,7 @@ menu "WiFi Echo Demo" ...@@ -44,7 +44,7 @@ menu "WiFi Echo Demo"
config USE_ECHO_CLIENT config USE_ECHO_CLIENT
bool "Enable the built-in Echo Client" bool "Enable the built-in Echo Client"
default "y" default "n"
help help
This enables a local FreeRTOS Echo Client so that the end-to-end echo server can be This enables a local FreeRTOS Echo Client so that the end-to-end echo server can be
tested easily tested easily
...@@ -55,4 +55,15 @@ menu "WiFi Echo Demo" ...@@ -55,4 +55,15 @@ menu "WiFi Echo Demo"
depends on USE_ECHO_CLIENT depends on USE_ECHO_CLIENT
help help
The IPV4 Address of the ECHO Server. The IPV4 Address of the ECHO Server.
# NOTE: This config is not displayed as a input in the Kconfig menu, as its value is
# entirely derived from the Device Type choice. However the CONFIG_EXAMPLE_DISPLAY_TYPE
# define that is produced is needed to configure the TFT library correctly.
config TFT_PREDEFINED_DISPLAY_TYPE
int
range 0 5
default 3 if DEVICE_TYPE_M5STACK
default 0 if DEVICE_TYPE_ESP32_DEVKITC
endmenu endmenu
\ No newline at end of file
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2018 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "esp_log.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "qrcodegen.h"
#include <platform/CHIPDeviceLayer.h>
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
#include <support/CodeUtils.h>
#include "Display.h"
#include "QRCodeWidget.h"
#define MAX_SSID_LEN 32
#if CONFIG_HAVE_DISPLAY
extern const char * TAG;
const char * const QRCODE_DATA = "https://github.com/project-chip/connectedhomeip";
using namespace ::chip;
using namespace ::chip::DeviceLayer;
// QRCode config
enum
{
kQRCodeVersion = 4,
kQRCodeModuleSizePix = 4,
kQRCodePadding = 2
};
// TODO Pull this from the configuration manager
void GetAPName(char * ssid, size_t ssid_len)
{
uint8_t mac[6];
CHIP_ERROR err = esp_wifi_get_mac(ESP_IF_WIFI_STA, mac);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "esp_wifi_get_mac(ESP_IF_WIFI_STA) failed: %s", chip::ErrorStr(err));
}
snprintf(ssid, ssid_len, "%s%02X%02X", "CHIP_DEMO-", mac[4], mac[5]);
}
string createSetupPayload()
{
char ap_ssid[MAX_SSID_LEN];
GetAPName(ap_ssid, sizeof(ap_ssid));
SetupPayload payload;
payload.version = 1;
payload.vendorID = 2;
payload.productID = 3;
uint64_t tag;
VendorTag(2, tag);
OptionalQRCodeInfo stringInfo;
stringInfo.tag = tag;
stringInfo.type = optionalQRCodeInfoTypeString;
stringInfo.data = ap_ssid;
payload.addOptionalData(stringInfo);
QRCodeSetupPayloadGenerator generator(payload);
string result;
uint8_t tlvDataStart[sizeof(ap_ssid)];
CHIP_ERROR err = generator.payloadBase41Representation(result, tlvDataStart, sizeof(tlvDataStart));
if (err != CHIP_NO_ERROR)
{
ESP_LOGE(TAG, "Couldn't get payload string %d", generator.payloadBase41Representation(result));
}
return result;
};
void QRCodeWidget::Init()
{
QRCodeColor = TFT_DARKGREY;
VMargin = 10;
}
void QRCodeWidget::Display()
{
CHIP_ERROR err = CHIP_NO_ERROR;
enum
{
kMaxQRCodeStrLength = 120
};
char * qrCodeStr = NULL;
uint8_t * qrCodeDataBuf = NULL;
uint8_t * qrCode = NULL;
uint16_t qrCodeDisplaySize, qrCodeX, qrCodeY, qrCodeXOffset, qrCodeYOffset;
qrCodeStr = (char *) createSetupPayload().c_str();
// Generate the QR code.
uint16_t qrCodeSize = qrcodegen_BUFFER_LEN_FOR_VERSION(kQRCodeVersion);
qrCodeDataBuf = (uint8_t *) malloc(qrCodeSize);
qrCode = (uint8_t *) malloc(qrCodeSize);
VerifyOrExit(qrCodeDataBuf != NULL, err = CHIP_ERROR_NO_MEMORY);
if (!qrcodegen_encodeText(qrCodeStr, qrCodeDataBuf, qrCode, qrcodegen_Ecc_LOW, kQRCodeVersion, kQRCodeVersion,
qrcodegen_Mask_AUTO, true))
{
ESP_LOGE(TAG, "qrcodegen_encodeText() failed");
ExitNow(err = CHIP_ERROR_INCORRECT_STATE);
}
// Draw the QR code image on the screen.
qrCodeDisplaySize = (qrcodegen_getSize(qrCode) + kQRCodePadding) * kQRCodeModuleSizePix;
qrCodeX = (DisplayWidth - qrCodeDisplaySize) / 2;
qrCodeY = (DisplayHeight * VMargin) / 100;
qrCodeXOffset = qrCodeX + kQRCodeModuleSizePix;
qrCodeYOffset = qrCodeY + kQRCodeModuleSizePix;
TFT_fillRect(qrCodeX, qrCodeY, (int) qrCodeDisplaySize, (int) qrCodeDisplaySize, QRCodeColor);
for (uint8_t y = 0; y < qrcodegen_getSize(qrCode); y++)
{
for (uint8_t x = 0; x < qrcodegen_getSize(qrCode); x++)
{
if (qrcodegen_getModule(qrCode, x, y))
{
TFT_fillRect(x * kQRCodeModuleSizePix + qrCodeXOffset, y * kQRCodeModuleSizePix + qrCodeYOffset,
(int) kQRCodeModuleSizePix, (int) kQRCodeModuleSizePix, TFT_BLACK);
}
}
}
exit:
if (qrCode != NULL)
{
free(qrCode);
}
if (qrCodeDataBuf != NULL)
{
free(qrCodeDataBuf);
}
if (err != CHIP_NO_ERROR)
{
ESP_LOGE(TAG, "QRCodeWidget::Display() failed: %s", ErrorStr(err));
}
}
#endif // CONFIG_HAVE_DISPLAY
...@@ -19,6 +19,4 @@ ...@@ -19,6 +19,4 @@
# #
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
COMPONENT_DEPENDS := chip COMPONENT_DEPENDS := chip QRCode tft spidriver
COMPONENT_INCLUDES += $(PROJECT_PATH)/third_party/connectedhomeip/src/app
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2018 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BUTTON_H
#define BUTTON_H
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
class Button
{
public:
esp_err_t Init(gpio_num_t gpioNum, uint16_t debouncePeriod);
bool Poll();
bool IsPressed();
uint32_t GetStateStartTime();
uint32_t GetStateDuration();
uint32_t GetPrevStateDuration();
private:
uint32_t mLastReadTime; // in ticks
uint32_t mStateStartTime; // in ticks
uint32_t mPrevStateDur; // in ticks
gpio_num_t mGPIONum;
uint16_t mDebouncePeriod; // in ticks
bool mState;
bool mLastState;
};
inline bool Button::IsPressed()
{
return mState;
}
inline uint32_t Button::GetStateStartTime()
{
return mStateStartTime * portTICK_PERIOD_MS;
}
inline uint32_t Button::GetPrevStateDuration()
{
return mPrevStateDur * portTICK_PERIOD_MS;
}
#endif // BUTTON_H
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2018 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DISPLAY_H
#define DISPLAY_H
#include "esp_system.h"
#if CONFIG_DEVICE_TYPE_M5STACK
#define CONFIG_HAVE_DISPLAY 1
#define CONFIG_TFT_PREDEFINED_DISPLAY_TYPE 3
#else // !CONFIG_DEVICE_TYPE_M5STACK
#define CONFIG_HAVE_DISPLAY 0
#endif // !CONFIG_DEVICE_TYPE_M5STACK
#if CONFIG_HAVE_DISPLAY
extern "C" {
#include "tft.h"
#include "tftspi.h"
} // extern "C"
// To reduce wear (and heat) on the screen, the display will always go off after a few seconds
#define DISPLAY_TIMEOUT_MS 30000
extern uint16_t DisplayHeight;
extern uint16_t DisplayWidth;
extern esp_err_t InitDisplay();
extern void ClearDisplay();
extern void DisplayStatusMessage(char * msg, uint16_t vpos);
extern void WakeDisplay();
#endif // #if CONFIG_HAVE_DISPLAY
#endif // DISPLAY_H
/* /*
* *
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2018 Nest Labs, Inc. * Copyright (c) 2018 Nest Labs, Inc.
* All rights reserved. * All rights reserved.
* *
......
/*
*
* Copyright (c) 2020 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef QRCODE_WIDGET_H
#define QRCODE_WIDGET_H
#include "Display.h"
#if CONFIG_HAVE_DISPLAY
class QRCodeWidget
{
public:
color_t QRCodeColor;
uint16_t VMargin;
void Init();
void Display();
};
#endif // CONFIG_HAVE_DISPLAY
#endif // QRCODE_WIDGET_H
...@@ -15,8 +15,11 @@ ...@@ -15,8 +15,11 @@
* limitations under the License. * limitations under the License.
*/ */
#include "Button.h"
#include "DataModelHandler.h" #include "DataModelHandler.h"
#include "Display.h"
#include "LEDWidget.h" #include "LEDWidget.h"
#include "QRCodeWidget.h"
#include "esp_event_loop.h" #include "esp_event_loop.h"
#include "esp_heap_caps_init.h" #include "esp_heap_caps_init.h"
#include "esp_log.h" #include "esp_log.h"
...@@ -26,6 +29,8 @@ ...@@ -26,6 +29,8 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "tcpip_adapter.h"
#include <stdio.h> #include <stdio.h>
#include <platform/CHIPDeviceLayer.h> #include <platform/CHIPDeviceLayer.h>
...@@ -59,7 +64,15 @@ extern void startClient(void); ...@@ -59,7 +64,15 @@ extern void startClient(void);
#endif // !CONFIG_DEVICE_TYPE_ESP32_DEVKITC #endif // !CONFIG_DEVICE_TYPE_ESP32_DEVKITC
#if CONFIG_HAVE_DISPLAY
static QRCodeWidget sQRCodeWidget;
#endif // CONFIG_HAVE_DISPLAY
LEDWidget statusLED; LEDWidget statusLED;
static Button attentionButton;
static volatile ConnectivityChange sConnectionState = kConnectivity_NoChange;
const char * TAG = "wifi-echo-demo"; const char * TAG = "wifi-echo-demo";
...@@ -159,9 +172,78 @@ extern "C" void app_main() ...@@ -159,9 +172,78 @@ extern "C" void app_main()
startClient(); startClient();
#endif #endif
#if CONFIG_HAVE_DISPLAY
// Only setup the button for the M5Stack since it's only being used to wake the display right now
err = attentionButton.Init(ATTENTION_BUTTON_GPIO_NUM, 50);
if (err != CHIP_NO_ERROR)
{
ESP_LOGE(TAG, "Button.Init() failed: %s", ErrorStr(err));
return;
}
// Initialize the display device.
err = InitDisplay();
if (err != ESP_OK)
{
ESP_LOGE(TAG, "InitDisplay() failed: %s", ErrorStr(err));
return;
}
// Initialize the UI widgets.
sQRCodeWidget.Init();
ClearDisplay();
sQRCodeWidget.Display();
#endif // CONFIG_HAVE_DISPLAY
// Run the UI Loop // Run the UI Loop
while (true) while (true)
{ {
#if CONFIG_HAVE_DISPLAY
// TODO consider refactoring this example to use FreeRTOS tasks
// Poll the attention button. Whenever we detect a *release* of the button
// reset the display timer
if (attentionButton.Poll() && !attentionButton.IsPressed())
{
WakeDisplay();
}
switch (sConnectionState)
{
case kConnectivity_Established:
// Show the currently connected state
tcpip_adapter_ip_info_t ipInfo;
if (tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ipInfo) == ESP_OK)
{
char ipAddrStr[INET_ADDRSTRLEN];
IPAddress::FromIPv4(ipInfo.ip).ToString(ipAddrStr, sizeof(ipAddrStr));
wifi_ap_record_t apInfo;
if (esp_wifi_sta_get_ap_info(&apInfo) == ESP_OK)
{
char message[256];
snprintf(message, sizeof(message), "WiFi Connected: %s\nEcho Server at %s:%d", (char *) apInfo.ssid, ipAddrStr,
CONFIG_ECHO_PORT);
// place it close to the bottom of the screen
DisplayStatusMessage(message, 85);
}
}
sConnectionState = kConnectivity_NoChange;
break;
case kConnectivity_Lost:
ESP_LOGE(TAG, "here4");
// Hide the currently connected state
sConnectionState = kConnectivity_NoChange;
ClearDisplay();
sQRCodeWidget.Display();
break;
case kConnectivity_NoChange:
default:
break;
}
#endif // CONFIG_HAVE_DISPLAY
vTaskDelay(50 / portTICK_PERIOD_MS); vTaskDelay(50 / portTICK_PERIOD_MS);
} }
} }
...@@ -172,6 +254,25 @@ extern "C" void app_main() ...@@ -172,6 +254,25 @@ extern "C" void app_main()
*/ */
void DeviceEventHandler(const ChipDeviceEvent * event, intptr_t arg) void DeviceEventHandler(const ChipDeviceEvent * event, intptr_t arg)
{ {
if (event->Type == DeviceEventType::kInternetConnectivityChange)
{
if (event->InternetConnectivityChange.IPv4 == kConnectivity_Established)
{
tcpip_adapter_ip_info_t ipInfo;
if (tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ipInfo) == ESP_OK)
{
char ipAddrStr[INET_ADDRSTRLEN];
IPAddress::FromIPv4(ipInfo.ip).ToString(ipAddrStr, sizeof(ipAddrStr));
ESP_LOGI(TAG, "Server ready at: %s:%d", ipAddrStr, CONFIG_ECHO_PORT);
sConnectionState = kConnectivity_Established;
}
}
else if (event->InternetConnectivityChange.IPv4 == kConnectivity_Lost)
{
ESP_LOGE(TAG, "Lost IP...");
sConnectionState = kConnectivity_Lost;
}
}
if (event->Type == DeviceEventType::kSessionEstablished && event->SessionEstablished.IsCommissioner) if (event->Type == DeviceEventType::kSessionEstablished && event->SessionEstablished.IsCommissioner)
{ {
ESP_LOGI(TAG, "Commissioner detected!"); ESP_LOGI(TAG, "Commissioner detected!");
......
...@@ -23,3 +23,13 @@ ...@@ -23,3 +23,13 @@
url = https://github.com/ARMmbed/mbedtls.git url = https://github.com/ARMmbed/mbedtls.git
branch = mbedtls-2.18 branch = mbedtls-2.18
update = none update = none
[submodule "qrcode"]
path = examples/common/QRCode/repo
url = https://github.com/nayuki/QR-Code-generator.git
branch = master
update = none
[submodule "m5stack-tft"]
path = examples/common/m5stack-tft/repo
url = https://github.com/jeremyjh/ESP32_TFT_library.git
branch = master
update = none
#!/bin/bash #!/bin/bash
make -f Makefile-bootstrap repos
source examples/wifi-echo/server/esp32/idf.sh source examples/wifi-echo/server/esp32/idf.sh
idf make -C examples/wifi-echo/server/esp32 defconfig idf make -C examples/wifi-echo/server/esp32 defconfig
idf make -C examples/wifi-echo/server/esp32 idf make -C examples/wifi-echo/server/esp32
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment