Skip to content
Snippets Groups Projects
main.c 6.49 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "bootloader.h"
    
    #include "card10-version.h"
    
    #include "card10.h"
    
    #include "led.h"
    #include "pb.h"
    
    #include "pmic.h"
    
    #include "board.h"
    #include "crc.h"
    #include "crc16-ccitt.h"
    #include "ff.h"
    #include "flc.h"
    #include "i2c.h"
    #include "icc.h"
    #include "mxc_config.h"
    #include "mxc_delay.h"
    #include "mxc_sys.h"
    
    #include <stdbool.h>
    #include <stddef.h>
    #include <stdio.h>
    #include <string.h>
    
    #include <errno.h>
    
    #define GPIO_PORT_IN PORT_1
    #define GPIO_PIN_IN PIN_6
    
    #define PARTITION_START (0x10000000 + 64 * 1024)
    
    #define PARTITION_END (0x10000000 + 1024 * 1024 - 1)
    
    FATFS FatFs;
    
    int format(void)
    {
    	BYTE work[FF_MAX_SS * 16];
    	/* Create FAT volume */
    	int res = f_mkfs("", FM_ANY | FM_SFD, 0, work, sizeof work);
    	if (res != FR_OK) {
    		printf("Failed to make new FS %d\n", res);
    		return -1;
    	}
    
    
    	f_setlabel("card10");
    	if (res != FR_OK) {
    		printf("Failed to set volume name %d\n", res);
    		return -1;
    	}
    
    	FRESULT res;
    	res = f_mount(&FatFs, "/", 0);
    	if (res != FR_OK) {
    		printf("f_mount error %d\n", res);
    
    	}
    
    	res = f_opendir(&dir, "0:");
    	if (res != FR_OK) {
    		printf("f_opendir error %d\n", res);
    
    int check_integrity(void)
    
    	FIL file;
    	UINT readbytes;
    	char *filename = "card10.bin";
    	uint8_t data[512];
    	FRESULT res;
    
    	res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ);
    	if (res != FR_OK) {
    		printf("f_open error %d\n", res);
    
    	}
    
    	uint16_t crcval = 0;
    	do {
    		res = f_read(&file, data, sizeof(data), &readbytes);
    		if (res != FR_OK) {
    			printf("f_read error %d\n", res);
    			crcval = 1; // Make sure to fail the test
    			break;
    		}
    		crcval = crc16_ccitt(crcval, data, readbytes);
    	} while (readbytes == sizeof(data));
    
    	f_close(&file);
    
    
    	if (crcval != 0) {
    
    		printf("CRC check failed. Final CRC: %d\n", crcval);
    
    bool is_update_needed(void)
    
    	FIL file;
    	UINT readbytes;
    	char *filename = "card10.bin";
    	uint8_t data[512];
    	FRESULT res;
    
    	res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ);
    	if (res != FR_OK) {
    		printf("f_open error %d\n", res);
    		return false;
    	}
    
    	uint8_t *partition = (uint8_t *)(intptr_t)PARTITION_START;
    	bool different     = false;
    	do {
    		res = f_read(&file, data, sizeof(data), &readbytes);
    		if (res != FR_OK) {
    			printf("f_read error %d\n", res);
    			break; /* Going to return false, don't want to use this file */
    		}
    		if (memcmp(partition, data, readbytes)) {
    			different = true;
    			break;
    		}
    		partition += readbytes;
    	} while (readbytes == sizeof(data));
    
    	f_close(&file);
    
    	return different;
    
    void erase_partition(void)
    
    	int ret = FLC_MultiPageErase(PARTITION_START, PARTITION_END);
    	if (ret != E_NO_ERROR) {
    		printf("FLC_MultiPageErase failed with %d\n", ret);
    		while (1)
    			;
    	}
    
    void flash_partition(void)
    
    	FIL file;
    	UINT readbytes;
    	char *filename = "card10.bin";
    	uint8_t data[512];
    	FRESULT res;
    
    	res = f_open(&file, filename, FA_OPEN_EXISTING | FA_READ);
    	if (res != FR_OK) {
    		printf("f_open error %d\n", res);
    		while (1)
    			;
    	}
    
    	uint32_t partition = PARTITION_START;
    
    	ICC_Disable();
    	do {
    		res = f_read(&file, data, sizeof(data), &readbytes);
    		if (res != FR_OK) {
    			printf("f_read error %d\n", res);
    			break; /* Going to return false, don't want to use this file */
    		}
    		int ret = FLC_Write(
    			partition,
    			readbytes,
    			(uint32_t *
    		)
    				data); /* wild cast. not sure if this works */
    		if (ret != E_NO_ERROR) {
    			printf("FLC_Write failed with %d\n", ret);
    
    danukeru's avatar
    danukeru committed
    			bootloader_display_error(
    				"Firmware Write", "Firmware not", "updated."
    			);
    
    			while (1)
    				;
    		}
    		partition += readbytes;
    	} while (readbytes == sizeof(data));
    	ICC_Enable();
    
    	f_close(&file);
    
    static inline void boot(const void *vtable)
    {
    	SCB->VTOR = (uintptr_t)vtable;
    
    
    	// Reset stack pointer & branch to the new reset vector.
    
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wdeprecated"
    
    	__asm("mov r0, %0\n"
    	      "ldr sp, [r0]\n"
    	      "ldr r0, [r0, #4]\n"
    	      "bx r0\n"
    	      :
    	      : "r"(vtable)
    	      : "%sp", "r0");
    
    static void pmic_button(bool falling)
    {
    	if (falling) {
    
    		card10_reset();
    
    static void msc(void)
    {
    	bootloader_display_header();
    	bootloader_display_line(3, "USB activated.", 0xffff);
    	bootloader_display_line(4, "Ready.", 0xffff);
    	run_usbmsc();
    
    	// If we return, don't try to boot. Maybe rather trigger a software reset.
    	// Reason: Not sure in which state the USB peripheral is and what kind
    	// of interrupts are active.
    	while (1)
    		;
    }
    
    /******************************************************************************/
    
    int main(void)
    
    	printf("\n\nBootloader " CARD10_VERSION "\n");
    
    	/*
    	 * Make the power/reset button restart card10.
    	 */
    
    	pmic_set_button_callback(pmic_button);
    
    
    	bootloader_display_init();
    
    
    	// If the button is pressed, we go into MSC mode.
    	if (PB_Get(3)) {
    
    	if (mount() == 0) {
    		int res = check_integrity();
    		if (res == -ENOENT) {
    			printf("card10.bin not found!\n");
    		} else if (res == -EINVAL) {
    			printf("card10.bin CRC is invalid!\n");
    
    			bootloader_display_header();
    
    			bootloader_display_line(
    
    				3, "Integrity check failed", 0xffff
    
    
    			bootloader_display_line(4, "Trying to boot", 0xffff);
    
    		} else if (res == 0) {
    
    			printf("Found valid application image\n");
    			if (is_update_needed()) {
    
    				printf("Trying to update firmware from external flash\n");
    
    				bootloader_display_header();
    
    					4, "Updating ...", 0xffff
    
    				);
    				erase_partition();
    				flash_partition();
    
    				f_unlink("card10.bin");
    
    				bootloader_display_line(
    					4, "Trying to boot", 0xffff
    				);
    
    			} else {
    				printf("No update needed\n");
    			}
    		}
    
    		bootloader_display_header();
    
    		bootloader_display_line(3, "Creating new filesystem", 0xffff);
    		printf("Creating new filesystem\n");
    
    		if (format() == 0) {
    			/* Drop into MSC after a reboot */
    			card10_reset();
    		} else {
    			bootloader_display_line(
    				3, "Failed to create new filesystem", 0xffff
    			);
    			printf("Feiled to create new filesystem\n");
    			/* Prevent bootloops */
    			while (1) {
    			}
    		}
    
    	/* Get the intital SP of the firmware. If it is 0xFFFFFFFF, no image has been
    	 * flashed yet. Drop into MSC for initial flashing. */
    	if (*((uint32_t *)PARTITION_START) == 0xFFFFFFFF) {
    		printf("No valid image in flash\n");
    		msc();
    	}
    
    
    	printf("Trying to boot\n");
    
    	boot((uintptr_t *)PARTITION_START);
    
    	while (1) {
    		// Should never be reached.
    	}
    
    }
    
    /******************************************************************************/
    void SysTick_Handler(void)
    {
    
    	mxc_delay_handler();