2020-06-06 13:28:01 -04:00
|
|
|
#include <legacy/nrf_drv_clock.h>
|
|
|
|
#include <softdevice/common/nrf_sdh.h>
|
|
|
|
#include <drivers/SpiMaster.h>
|
|
|
|
#include <drivers/Spi.h>
|
|
|
|
#include <drivers/SpiNorFlash.h>
|
2020-06-16 14:44:11 -04:00
|
|
|
#include <libraries/log/nrf_log.h>
|
2020-06-06 13:28:01 -04:00
|
|
|
#include <FreeRTOS.h>
|
|
|
|
#include <task.h>
|
2020-06-17 03:02:28 -04:00
|
|
|
#include <legacy/nrf_drv_gpiote.h>
|
2020-06-06 13:28:01 -04:00
|
|
|
#include <libraries/gpiote/app_gpiote.h>
|
2020-06-17 03:02:28 -04:00
|
|
|
#include <hal/nrf_wdt.h>
|
2020-06-06 13:28:01 -04:00
|
|
|
#include <cstring>
|
2020-10-20 03:14:16 -04:00
|
|
|
#include <components/gfx/Gfx.h>
|
2020-06-06 13:28:01 -04:00
|
|
|
#include <drivers/St7789.h>
|
2020-10-20 03:14:16 -04:00
|
|
|
#include <components/brightness/BrightnessController.h>
|
2021-01-26 14:31:45 -05:00
|
|
|
#include <algorithm>
|
|
|
|
#include "recoveryImage.h"
|
2021-08-03 14:32:23 -04:00
|
|
|
#include "drivers/PinMap.h"
|
2021-01-26 14:31:45 -05:00
|
|
|
|
|
|
|
#include "displayapp/icons/infinitime/infinitime-nb.c"
|
|
|
|
#include "components/rle/RleDecoder.h"
|
|
|
|
|
2020-06-06 13:28:01 -04:00
|
|
|
#if NRF_LOG_ENABLED
|
2021-04-18 13:28:14 -04:00
|
|
|
#include "logging/NrfLogger.h"
|
2020-06-06 13:28:01 -04:00
|
|
|
Pinetime::Logging::NrfLogger logger;
|
|
|
|
#else
|
2021-04-18 13:28:14 -04:00
|
|
|
#include "logging/DummyLogger.h"
|
2020-06-06 13:28:01 -04:00
|
|
|
Pinetime::Logging::DummyLogger logger;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2021-01-26 14:31:45 -05:00
|
|
|
static constexpr uint8_t displayWidth = 240;
|
|
|
|
static constexpr uint8_t displayHeight = 240;
|
|
|
|
static constexpr uint8_t bytesPerPixel = 2;
|
|
|
|
|
|
|
|
static constexpr uint16_t colorWhite = 0xFFFF;
|
|
|
|
static constexpr uint16_t colorGreen = 0xE007;
|
|
|
|
|
2021-04-18 13:28:14 -04:00
|
|
|
Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0,
|
|
|
|
{Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb,
|
|
|
|
Pinetime::Drivers::SpiMaster::Modes::Mode3,
|
|
|
|
Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz,
|
2021-08-03 14:32:23 -04:00
|
|
|
Pinetime::PinMap::SpiSck,
|
|
|
|
Pinetime::PinMap::SpiMosi,
|
|
|
|
Pinetime::PinMap::SpiMiso}};
|
|
|
|
Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn};
|
2021-04-18 13:28:14 -04:00
|
|
|
Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi};
|
2020-06-06 13:28:01 -04:00
|
|
|
|
2021-08-03 14:32:23 -04:00
|
|
|
Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn};
|
|
|
|
Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand};
|
2020-06-06 13:28:01 -04:00
|
|
|
|
2021-04-18 13:28:14 -04:00
|
|
|
Pinetime::Components::Gfx gfx {lcd};
|
2020-06-06 13:28:01 -04:00
|
|
|
Pinetime::Controllers::BrightnessController brightnessController;
|
|
|
|
|
2021-01-26 14:31:45 -05:00
|
|
|
void DisplayProgressBar(uint8_t percent, uint16_t color);
|
|
|
|
|
|
|
|
void DisplayLogo();
|
|
|
|
|
2020-06-06 13:28:01 -04:00
|
|
|
extern "C" {
|
|
|
|
void vApplicationIdleHook(void) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) {
|
2021-04-18 13:28:14 -04:00
|
|
|
if (((NRF_SPIM0->INTENSET & (1 << 6)) != 0) && NRF_SPIM0->EVENTS_END == 1) {
|
2020-06-06 13:28:01 -04:00
|
|
|
NRF_SPIM0->EVENTS_END = 0;
|
|
|
|
spi.OnEndEvent();
|
|
|
|
}
|
|
|
|
|
2021-04-18 13:28:14 -04:00
|
|
|
if (((NRF_SPIM0->INTENSET & (1 << 19)) != 0) && NRF_SPIM0->EVENTS_STARTED == 1) {
|
2020-06-06 13:28:01 -04:00
|
|
|
NRF_SPIM0->EVENTS_STARTED = 0;
|
|
|
|
spi.OnStartedEvent();
|
|
|
|
}
|
|
|
|
|
2021-04-18 13:28:14 -04:00
|
|
|
if (((NRF_SPIM0->INTENSET & (1 << 1)) != 0) && NRF_SPIM0->EVENTS_STOPPED == 1) {
|
2020-06-06 13:28:01 -04:00
|
|
|
NRF_SPIM0->EVENTS_STOPPED = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-26 14:31:45 -05:00
|
|
|
void RefreshWatchdog() {
|
|
|
|
NRF_WDT->RR[0] = WDT_RR_RR_Reload;
|
|
|
|
}
|
2020-06-06 13:28:01 -04:00
|
|
|
|
2021-01-26 14:31:45 -05:00
|
|
|
uint8_t displayBuffer[displayWidth * bytesPerPixel];
|
|
|
|
void Process(void* instance) {
|
|
|
|
RefreshWatchdog();
|
2020-06-06 13:28:01 -04:00
|
|
|
APP_GPIOTE_INIT(2);
|
|
|
|
|
|
|
|
NRF_LOG_INFO("Init...");
|
|
|
|
spi.Init();
|
|
|
|
spiNorFlash.Init();
|
2020-09-20 08:31:26 -04:00
|
|
|
spiNorFlash.Wakeup();
|
2020-06-06 13:28:01 -04:00
|
|
|
brightnessController.Init();
|
|
|
|
lcd.Init();
|
|
|
|
gfx.Init();
|
2021-01-26 14:31:45 -05:00
|
|
|
|
|
|
|
NRF_LOG_INFO("Display logo")
|
|
|
|
DisplayLogo();
|
2020-06-06 13:28:01 -04:00
|
|
|
|
|
|
|
NRF_LOG_INFO("Erasing...");
|
2021-01-26 14:31:45 -05:00
|
|
|
for (uint32_t erased = 0; erased < sizeof(recoveryImage); erased += 0x1000) {
|
2020-06-06 13:28:01 -04:00
|
|
|
spiNorFlash.SectorErase(erased);
|
2021-01-26 14:31:45 -05:00
|
|
|
RefreshWatchdog();
|
2020-06-06 13:28:01 -04:00
|
|
|
}
|
|
|
|
|
2021-01-26 14:31:45 -05:00
|
|
|
NRF_LOG_INFO("Writing factory image...");
|
2020-06-06 13:28:01 -04:00
|
|
|
static constexpr uint32_t memoryChunkSize = 200;
|
|
|
|
uint8_t writeBuffer[memoryChunkSize];
|
2021-04-18 13:28:14 -04:00
|
|
|
for (size_t offset = 0; offset < sizeof(recoveryImage); offset += memoryChunkSize) {
|
2021-01-26 14:31:45 -05:00
|
|
|
std::memcpy(writeBuffer, &recoveryImage[offset], memoryChunkSize);
|
2020-06-06 13:28:01 -04:00
|
|
|
spiNorFlash.Write(offset, writeBuffer, memoryChunkSize);
|
2021-01-26 14:31:45 -05:00
|
|
|
DisplayProgressBar((static_cast<float>(offset) / static_cast<float>(sizeof(recoveryImage))) * 100.0f, colorWhite);
|
|
|
|
RefreshWatchdog();
|
2020-06-06 13:28:01 -04:00
|
|
|
}
|
2021-01-26 14:31:45 -05:00
|
|
|
NRF_LOG_INFO("Writing factory image done!");
|
|
|
|
DisplayProgressBar(100.0f, colorGreen);
|
2020-06-06 13:28:01 -04:00
|
|
|
|
2021-04-18 13:28:14 -04:00
|
|
|
while (1) {
|
|
|
|
asm("nop");
|
2020-06-06 13:28:01 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-26 14:31:45 -05:00
|
|
|
void DisplayLogo() {
|
|
|
|
Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb));
|
2021-04-18 13:28:14 -04:00
|
|
|
for (int i = 0; i < displayWidth; i++) {
|
2021-01-26 14:31:45 -05:00
|
|
|
rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel);
|
|
|
|
ulTaskNotifyTake(pdTRUE, 500);
|
2021-04-18 13:28:14 -04:00
|
|
|
lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), displayWidth * bytesPerPixel);
|
2021-01-26 14:31:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisplayProgressBar(uint8_t percent, uint16_t color) {
|
|
|
|
static constexpr uint8_t barHeight = 20;
|
2021-04-18 13:28:14 -04:00
|
|
|
std::fill(displayBuffer, displayBuffer + (displayWidth * bytesPerPixel), color);
|
|
|
|
for (int i = 0; i < barHeight; i++) {
|
2021-01-26 14:31:45 -05:00
|
|
|
ulTaskNotifyTake(pdTRUE, 500);
|
|
|
|
uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth));
|
2021-04-18 13:28:14 -04:00
|
|
|
lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast<const uint8_t*>(displayBuffer), barWidth * bytesPerPixel);
|
2021-01-26 14:31:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-06 13:28:01 -04:00
|
|
|
int main(void) {
|
|
|
|
TaskHandle_t taskHandle;
|
2021-01-26 14:31:45 -05:00
|
|
|
RefreshWatchdog();
|
2020-06-06 13:28:01 -04:00
|
|
|
logger.Init();
|
|
|
|
nrf_drv_clock_init();
|
|
|
|
|
|
|
|
if (pdPASS != xTaskCreate(Process, "MAIN", 512, nullptr, 0, &taskHandle))
|
|
|
|
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
|
|
|
|
|
|
|
vTaskStartScheduler();
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
APP_ERROR_HANDLER(NRF_ERROR_FORBIDDEN);
|
|
|
|
}
|
2020-06-17 03:02:28 -04:00
|
|
|
}
|