summaryrefslogtreecommitdiff
path: root/src/recoveryLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/recoveryLoader.cpp')
-rw-r--r--src/recoveryLoader.cpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/src/recoveryLoader.cpp b/src/recoveryLoader.cpp
new file mode 100644
index 00000000..40cd66da
--- /dev/null
+++ b/src/recoveryLoader.cpp
@@ -0,0 +1,167 @@
+#include <legacy/nrf_drv_clock.h>
+#include <softdevice/common/nrf_sdh.h>
+#include <drivers/SpiMaster.h>
+#include <drivers/Spi.h>
+#include <drivers/SpiNorFlash.h>
+#include <libraries/log/nrf_log.h>
+#include <FreeRTOS.h>
+#include <task.h>
+#include <legacy/nrf_drv_gpiote.h>
+#include <libraries/gpiote/app_gpiote.h>
+#include <hal/nrf_wdt.h>
+#include <cstring>
+#include <components/gfx/Gfx.h>
+#include <drivers/St7789.h>
+#include <components/brightness/BrightnessController.h>
+#include <algorithm>
+#include "recoveryImage.h"
+
+#include "displayapp/icons/infinitime/infinitime-nb.c"
+#include "components/rle/RleDecoder.h"
+
+
+#if NRF_LOG_ENABLED
+#include "logging/NrfLogger.h"
+Pinetime::Logging::NrfLogger logger;
+#else
+#include "logging/DummyLogger.h"
+Pinetime::Logging::DummyLogger logger;
+#endif
+
+static constexpr uint8_t pinSpiSck = 2;
+static constexpr uint8_t pinSpiMosi = 3;
+static constexpr uint8_t pinSpiMiso = 4;
+static constexpr uint8_t pinSpiFlashCsn = 5;
+static constexpr uint8_t pinLcdCsn = 25;
+static constexpr uint8_t pinLcdDataCommand = 18;
+
+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;
+
+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,
+ pinSpiSck,
+ pinSpiMosi,
+ pinSpiMiso
+}
+};
+Pinetime::Drivers::Spi flashSpi{spi, pinSpiFlashCsn};
+Pinetime::Drivers::SpiNorFlash spiNorFlash{flashSpi};
+
+Pinetime::Drivers::Spi lcdSpi {spi, pinLcdCsn};
+Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand};
+
+Pinetime::Components::Gfx gfx{lcd};
+Pinetime::Controllers::BrightnessController brightnessController;
+
+void DisplayProgressBar(uint8_t percent, uint16_t color);
+
+void DisplayLogo();
+
+extern "C" {
+void vApplicationIdleHook(void) {
+
+}
+
+void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) {
+ if(((NRF_SPIM0->INTENSET & (1<<6)) != 0) && NRF_SPIM0->EVENTS_END == 1) {
+ NRF_SPIM0->EVENTS_END = 0;
+ spi.OnEndEvent();
+ }
+
+ if(((NRF_SPIM0->INTENSET & (1<<19)) != 0) && NRF_SPIM0->EVENTS_STARTED == 1) {
+ NRF_SPIM0->EVENTS_STARTED = 0;
+ spi.OnStartedEvent();
+ }
+
+ if(((NRF_SPIM0->INTENSET & (1<<1)) != 0) && NRF_SPIM0->EVENTS_STOPPED == 1) {
+ NRF_SPIM0->EVENTS_STOPPED = 0;
+ }
+}
+}
+
+void RefreshWatchdog() {
+ NRF_WDT->RR[0] = WDT_RR_RR_Reload;
+}
+
+uint8_t displayBuffer[displayWidth * bytesPerPixel];
+void Process(void* instance) {
+ RefreshWatchdog();
+ APP_GPIOTE_INIT(2);
+
+ NRF_LOG_INFO("Init...");
+ spi.Init();
+ spiNorFlash.Init();
+ spiNorFlash.Wakeup();
+ brightnessController.Init();
+ lcd.Init();
+ gfx.Init();
+
+ NRF_LOG_INFO("Display logo")
+ DisplayLogo();
+
+ NRF_LOG_INFO("Erasing...");
+ for (uint32_t erased = 0; erased < sizeof(recoveryImage); erased += 0x1000) {
+ spiNorFlash.SectorErase(erased);
+ RefreshWatchdog();
+ }
+
+ NRF_LOG_INFO("Writing factory image...");
+ static constexpr uint32_t memoryChunkSize = 200;
+ uint8_t writeBuffer[memoryChunkSize];
+ for(size_t offset = 0; offset < sizeof(recoveryImage); offset+=memoryChunkSize) {
+ std::memcpy(writeBuffer, &recoveryImage[offset], memoryChunkSize);
+ spiNorFlash.Write(offset, writeBuffer, memoryChunkSize);
+ DisplayProgressBar((static_cast<float>(offset) / static_cast<float>(sizeof(recoveryImage))) * 100.0f, colorWhite);
+ RefreshWatchdog();
+ }
+ NRF_LOG_INFO("Writing factory image done!");
+ DisplayProgressBar(100.0f, colorGreen);
+
+ while(1) {
+ asm("nop" );
+ }
+}
+
+void DisplayLogo() {
+ Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb));
+ for(int i = 0; i < displayWidth; i++) {
+ rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel);
+ ulTaskNotifyTake(pdTRUE, 500);
+ lcd.BeginDrawBuffer(0, i, displayWidth, 1);
+ lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(displayBuffer), displayWidth * bytesPerPixel);
+ }
+}
+
+void DisplayProgressBar(uint8_t percent, uint16_t color) {
+ static constexpr uint8_t barHeight = 20;
+ std::fill(displayBuffer, displayBuffer+(displayWidth * bytesPerPixel), color);
+ for(int i = 0; i < barHeight; i++) {
+ ulTaskNotifyTake(pdTRUE, 500);
+ uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth));
+ lcd.BeginDrawBuffer(0, displayWidth - barHeight + i, barWidth, 1);
+ lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(displayBuffer), barWidth * bytesPerPixel);
+ }
+}
+
+int main(void) {
+ TaskHandle_t taskHandle;
+ RefreshWatchdog();
+ 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);
+ }
+}