Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / examples / common / screen-framework / Display.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2018 Nest Labs, Inc.
5  *    All rights reserved.
6  *
7  *    Licensed under the Apache License, Version 2.0 (the "License");
8  *    you may not use this file except in compliance with the License.
9  *    You may obtain a copy of the License at
10  *
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *    Unless required by applicable law or agreed to in writing, software
14  *    distributed under the License is distributed on an "AS IS" BASIS,
15  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *    See the License for the specific language governing permissions and
17  *    limitations under the License.
18  */
19
20 /**
21  * @file Display.cpp
22  *
23  * This file implements helper APIs for the M5Stack's display
24  *
25  */
26
27 #include <string.h>
28
29 #include "driver/ledc.h"
30 #include "esp_log.h"
31 #include "esp_system.h"
32 #include "freertos/FreeRTOS.h"
33 #include "freertos/task.h"
34 #include "freertos/timers.h"
35
36 #include "Display.h"
37
38 #if CONFIG_HAVE_DISPLAY
39
40 // Brightness picked such that it's easy for cameras to focus on
41 #define DEFAULT_BRIGHTNESS_PERCENT 10
42
43 // 8MHz is the recommended SPI speed to init the driver with
44 // It later gets set to the preconfigured defaults within the driver
45 #define TFT_SPI_CLOCK_INIT_HZ 8000000
46
47 // The frequency used by the ledc timer
48 // value chosen to eliminate flicker
49 #define LEDC_PWM_HZ 1000
50
51 // with a duty resolution of LEDC_TIMER_8_BIT
52 // the highest possible brightness value is 255
53 #define BRIGHTNESS_MAX 255
54 // The M5Stack's backlight is on Channel 7
55 #define BACKLIGHT_CHANNEL LEDC_CHANNEL_7
56
57 extern const char * TAG;
58
59 uint16_t DisplayHeight = 0;
60 uint16_t DisplayWidth  = 0;
61
62 bool awake = false;
63
64 #if CONFIG_DISPLAY_AUTO_OFF
65 // FreeRTOS timer used to turn the display off after a short while
66 TimerHandle_t displayTimer = NULL;
67 #endif
68
69 #if CONFIG_DISPLAY_AUTO_OFF
70 static void TimerCallback(TimerHandle_t xTimer);
71 #endif
72 static void SetupBrightnessControl();
73 static void SetBrightness(uint16_t brightness_percent);
74
75 esp_err_t InitDisplay()
76 {
77     esp_err_t err;
78     spi_lobo_device_handle_t spi;
79
80     // configured based on the display driver's examples
81     spi_lobo_bus_config_t buscfg;
82     memset((void *) &buscfg, 0, sizeof(buscfg));
83     buscfg.miso_io_num   = PIN_NUM_MISO; // set SPI MISO pin
84     buscfg.mosi_io_num   = PIN_NUM_MOSI; // set SPI MOSI pin
85     buscfg.sclk_io_num   = PIN_NUM_CLK;  // set SPI CLK pin
86     buscfg.quadwp_io_num = -1;
87     buscfg.quadhd_io_num = -1;
88
89     spi_lobo_device_interface_config_t devcfg;
90     memset((void *) &devcfg, 0, sizeof(devcfg));
91     devcfg.clock_speed_hz   = TFT_SPI_CLOCK_INIT_HZ;
92     devcfg.mode             = 0;                        // SPI mode 0
93     devcfg.spics_io_num     = -1;                       // we will use external CS pin
94     devcfg.spics_ext_io_num = PIN_NUM_CS;               // external CS pin
95     devcfg.flags            = LB_SPI_DEVICE_HALFDUPLEX; // ALWAYS SET  to HALF DUPLEX MODE!! for display spi
96     tft_max_rdclock         = TFT_SPI_CLOCK_INIT_HZ;
97
98     // Initialize all pins used by display driver.
99     TFT_PinsInit();
100
101     // Initialize SPI bus and add a device for the display.
102     err = spi_lobo_bus_add_device(TFT_HSPI_HOST, &buscfg, &devcfg, &spi);
103     if (err != ESP_OK)
104         return err;
105
106     // Configure the display to use the new SPI device.
107     tft_disp_spi = spi;
108
109     err = spi_lobo_device_select(spi, 1);
110     if (err != ESP_OK)
111         return err;
112     err = spi_lobo_device_deselect(spi);
113     if (err != ESP_OK)
114         return err;
115
116     // Initialize the display driver.
117     TFT_display_init();
118
119     // Detect maximum read speed and set it.
120     tft_max_rdclock = find_rd_speed();
121
122     // Set the SPI clock speed overriding the initialized 8MHz speed
123     spi_lobo_set_speed(spi, DEFAULT_SPI_CLOCK);
124
125     TFT_setGammaCurve(0);
126     TFT_setRotation(LANDSCAPE);
127     TFT_resetclipwin();
128
129     DisplayWidth  = (uint16_t)(1 + tft_dispWin.x2 - tft_dispWin.x1);
130     DisplayHeight = (uint16_t)(1 + tft_dispWin.y2 - tft_dispWin.y1);
131
132     ESP_LOGI(TAG, "Display initialized (height %u, width %u)", DisplayHeight, DisplayWidth);
133
134     TFT_invertDisplay(INVERT_DISPLAY);
135
136     // prepare the display for brightness control
137     SetupBrightnessControl();
138
139 #if CONFIG_DISPLAY_AUTO_OFF
140     displayTimer = xTimerCreate("DisplayTimer", pdMS_TO_TICKS(DISPLAY_TIMEOUT_MS), false, NULL, TimerCallback);
141 #endif
142     // lower the brightness of the screen
143     WakeDisplay();
144
145     return err;
146 }
147
148 void SetBrightness(uint16_t brightness_percent)
149 {
150     uint16_t brightness = (brightness_percent * BRIGHTNESS_MAX) / 100;
151     if (ledc_set_duty(LEDC_HIGH_SPEED_MODE, BACKLIGHT_CHANNEL, brightness) ||
152         ledc_update_duty(LEDC_HIGH_SPEED_MODE, BACKLIGHT_CHANNEL))
153     {
154         ESP_LOGE(TAG, "Failed to set display brightness...");
155     }
156 }
157
158 bool WakeDisplay()
159 {
160     bool woken = !awake;
161     awake      = true;
162     SetBrightness(DEFAULT_BRIGHTNESS_PERCENT);
163 #if CONFIG_DISPLAY_AUTO_OFF
164     xTimerStart(displayTimer, 0);
165     ESP_LOGI(TAG, "Display awake but will switch off automatically in %d seconds", DISPLAY_TIMEOUT_MS / 1000);
166 #endif
167     return woken;
168 }
169
170 void ClearDisplay()
171 {
172     ClearRect();
173 }
174
175 void ClearRect(uint16_t x_percent_start, uint16_t y_percent_start, uint16_t x_percent_end, uint16_t y_percent_end)
176 {
177     if (x_percent_end < x_percent_start)
178     {
179         x_percent_end = x_percent_start;
180     }
181     if (y_percent_end < y_percent_start)
182     {
183         y_percent_end = y_percent_start;
184     }
185     uint16_t start_x = (DisplayWidth * x_percent_start) / 100;
186     uint16_t start_y = (DisplayHeight * y_percent_start) / 100;
187     uint16_t end_x   = (DisplayWidth * x_percent_end) / 100;
188     uint16_t end_y   = (DisplayHeight * y_percent_end) / 100;
189     TFT_fillRect(start_x, start_y, end_x, end_y, TFT_BLACK);
190 }
191
192 void DisplayStatusMessage(char * msg, uint16_t vpos)
193 {
194     TFT_setFont(SMALL_FONT, NULL);
195     uint16_t msgX = 0;
196     uint16_t msgY = (DisplayHeight * vpos) / 100;
197     TFT_print(msg, msgX, msgY);
198 }
199
200 void TimerCallback(TimerHandle_t xTimer)
201 {
202     ESP_LOGI(TAG, "Display going to sleep...");
203     SetBrightness(0);
204     awake = false;
205 }
206
207 void SetupBrightnessControl()
208 {
209     ledc_timer_config_t ledc_timer;
210     memset(&ledc_timer, 0, sizeof(ledc_timer));
211
212     ledc_timer.duty_resolution = LEDC_TIMER_8_BIT;     // resolution of PWM duty
213     ledc_timer.freq_hz         = LEDC_PWM_HZ;          // frequency of PWM signal
214     ledc_timer.speed_mode      = LEDC_HIGH_SPEED_MODE; // timer mode
215     ledc_timer.timer_num       = LEDC_TIMER_0;         // timer index
216     ledc_timer_config(&ledc_timer);
217
218     ledc_timer_set(LEDC_HIGH_SPEED_MODE, LEDC_TIMER_0, LEDC_PWM_HZ, LEDC_TIMER_8_BIT, LEDC_REF_TICK);
219
220     ledc_channel_config_t ledc_channel;
221     memset(&ledc_channel, 0, sizeof(ledc_channel));
222     ledc_channel.channel    = BACKLIGHT_CHANNEL;
223     ledc_channel.duty       = BRIGHTNESS_MAX;
224     ledc_channel.gpio_num   = PIN_NUM_BCKL;
225     ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE;
226     ledc_channel.timer_sel  = LEDC_TIMER_0;
227     ledc_channel_config(&ledc_channel);
228 }
229
230 #endif // CONFIG_HAVE_DISPLAY