move uf2 into usb
This commit is contained in:
		
							
								
								
									
										21
									
								
								src/usb/uf2/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/usb/uf2/LICENSE
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
    MIT License
 | 
			
		||||
 | 
			
		||||
    Copyright (c) Microsoft Corporation. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
    of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
    in the Software without restriction, including without limitation the rights
 | 
			
		||||
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
    copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
    furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
    The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
    copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
    SOFTWARE
 | 
			
		||||
							
								
								
									
										339
									
								
								src/usb/uf2/ghostfat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								src/usb/uf2/ghostfat.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,339 @@
 | 
			
		||||
 | 
			
		||||
#include "uf2.h"
 | 
			
		||||
#include "nrf_nvmc.h"
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include "tusb.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint8_t JumpInstruction[3];
 | 
			
		||||
    uint8_t OEMInfo[8];
 | 
			
		||||
    uint16_t SectorSize;
 | 
			
		||||
    uint8_t SectorsPerCluster;
 | 
			
		||||
    uint16_t ReservedSectors;
 | 
			
		||||
    uint8_t FATCopies;
 | 
			
		||||
    uint16_t RootDirectoryEntries;
 | 
			
		||||
    uint16_t TotalSectors16;
 | 
			
		||||
    uint8_t MediaDescriptor;
 | 
			
		||||
    uint16_t SectorsPerFAT;
 | 
			
		||||
    uint16_t SectorsPerTrack;
 | 
			
		||||
    uint16_t Heads;
 | 
			
		||||
    uint32_t HiddenSectors;
 | 
			
		||||
    uint32_t TotalSectors32;
 | 
			
		||||
    uint8_t PhysicalDriveNum;
 | 
			
		||||
    uint8_t Reserved;
 | 
			
		||||
    uint8_t ExtendedBootSig;
 | 
			
		||||
    uint32_t VolumeSerialNumber;
 | 
			
		||||
    uint8_t VolumeLabel[11];
 | 
			
		||||
    uint8_t FilesystemIdentifier[8];
 | 
			
		||||
} __attribute__((packed)) FAT_BootBlock;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    char name[8];
 | 
			
		||||
    char ext[3];
 | 
			
		||||
    uint8_t attrs;
 | 
			
		||||
    uint8_t reserved;
 | 
			
		||||
    uint8_t createTimeFine;
 | 
			
		||||
    uint16_t createTime;
 | 
			
		||||
    uint16_t createDate;
 | 
			
		||||
    uint16_t lastAccessDate;
 | 
			
		||||
    uint16_t highStartCluster;
 | 
			
		||||
    uint16_t updateTime;
 | 
			
		||||
    uint16_t updateDate;
 | 
			
		||||
    uint16_t startCluster;
 | 
			
		||||
    uint32_t size;
 | 
			
		||||
} __attribute__((packed)) DirEntry;
 | 
			
		||||
 | 
			
		||||
STATIC_ASSERT(sizeof(DirEntry) == 32);
 | 
			
		||||
 | 
			
		||||
struct TextFile {
 | 
			
		||||
    const char name[11];
 | 
			
		||||
    const char *content;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define NUM_FAT_BLOCKS UF2_NUM_BLOCKS
 | 
			
		||||
 | 
			
		||||
#define STR0(x) #x
 | 
			
		||||
#define STR(x) STR0(x)
 | 
			
		||||
const char infoUf2File[] = //
 | 
			
		||||
    "UF2 Bootloader " UF2_VERSION "\r\n"
 | 
			
		||||
    "Model: " PRODUCT_NAME "\r\n"
 | 
			
		||||
    "Board-ID: " BOARD_ID "\r\n";
 | 
			
		||||
 | 
			
		||||
const char indexFile[] = //
 | 
			
		||||
    "<!doctype html>\n"
 | 
			
		||||
    "<html>"
 | 
			
		||||
    "<body>"
 | 
			
		||||
    "<script>\n"
 | 
			
		||||
    "location.replace(\"" INDEX_URL "\");\n"
 | 
			
		||||
    "</script>"
 | 
			
		||||
    "</body>"
 | 
			
		||||
    "</html>\n";
 | 
			
		||||
 | 
			
		||||
static const struct TextFile info[] = {
 | 
			
		||||
    {.name = "INFO_UF2TXT", .content = infoUf2File},
 | 
			
		||||
    {.name = "INDEX   HTM", .content = indexFile},
 | 
			
		||||
    {.name = "CURRENT UF2"},
 | 
			
		||||
};
 | 
			
		||||
#define NUM_INFO (sizeof(info) / sizeof(info[0]))
 | 
			
		||||
 | 
			
		||||
#define UF2_SIZE (FLASH_SIZE * 2)
 | 
			
		||||
#define UF2_SECTORS (UF2_SIZE / 512)
 | 
			
		||||
#define UF2_FIRST_SECTOR (NUM_INFO + 1)
 | 
			
		||||
#define UF2_LAST_SECTOR (UF2_FIRST_SECTOR + UF2_SECTORS - 1)
 | 
			
		||||
 | 
			
		||||
#define RESERVED_SECTORS 1
 | 
			
		||||
#define ROOT_DIR_SECTORS 4
 | 
			
		||||
#define SECTORS_PER_FAT ((NUM_FAT_BLOCKS * 2 + 511) / 512)
 | 
			
		||||
 | 
			
		||||
#define START_FAT0 RESERVED_SECTORS
 | 
			
		||||
#define START_FAT1 (START_FAT0 + SECTORS_PER_FAT)
 | 
			
		||||
#define START_ROOTDIR (START_FAT1 + SECTORS_PER_FAT)
 | 
			
		||||
#define START_CLUSTERS (START_ROOTDIR + ROOT_DIR_SECTORS)
 | 
			
		||||
 | 
			
		||||
static const FAT_BootBlock BootBlock = {
 | 
			
		||||
    .JumpInstruction = {0xeb, 0x3c, 0x90},
 | 
			
		||||
    .OEMInfo = "UF2 UF2 ",
 | 
			
		||||
    .SectorSize = 512,
 | 
			
		||||
    .SectorsPerCluster = 1,
 | 
			
		||||
    .ReservedSectors = RESERVED_SECTORS,
 | 
			
		||||
    .FATCopies = 2,
 | 
			
		||||
    .RootDirectoryEntries = (ROOT_DIR_SECTORS * 512 / 32),
 | 
			
		||||
    .TotalSectors16 = NUM_FAT_BLOCKS - 2,
 | 
			
		||||
    .MediaDescriptor = 0xF8,
 | 
			
		||||
    .SectorsPerFAT = SECTORS_PER_FAT,
 | 
			
		||||
    .SectorsPerTrack = 1,
 | 
			
		||||
    .Heads = 1,
 | 
			
		||||
    .ExtendedBootSig = 0x29,
 | 
			
		||||
    .VolumeSerialNumber = 0x00420042,
 | 
			
		||||
    .VolumeLabel = VOLUME_LABEL,
 | 
			
		||||
    .FilesystemIdentifier = "FAT16   ",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define NO_CACHE 0xffffffff
 | 
			
		||||
 | 
			
		||||
#define NRF_LOG_DEBUG(...)
 | 
			
		||||
 | 
			
		||||
uint32_t flashAddr = NO_CACHE;
 | 
			
		||||
uint8_t flashBuf[FLASH_PAGE_SIZE] __attribute__((aligned(4)));
 | 
			
		||||
bool firstFlush = true;
 | 
			
		||||
bool hadWrite = false;
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
void flushFlash() {
 | 
			
		||||
    if (flashAddr == NO_CACHE)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (firstFlush) {
 | 
			
		||||
        if (sdRunning) {
 | 
			
		||||
            // disable SD - we need sync access to flash, and we might be also overwriting the SD
 | 
			
		||||
            nrf_sdh_disable_request();
 | 
			
		||||
            nrf_dfu_settings_init(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        firstFlush = false;
 | 
			
		||||
 | 
			
		||||
        s_dfu_settings.write_offset = 0;
 | 
			
		||||
        s_dfu_settings.sd_size = 0;
 | 
			
		||||
        s_dfu_settings.bank_layout = NRF_DFU_BANK_LAYOUT_DUAL;
 | 
			
		||||
        s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_0;
 | 
			
		||||
 | 
			
		||||
        memset(&s_dfu_settings.bank_0, 0, sizeof(s_dfu_settings.bank_0));
 | 
			
		||||
        memset(&s_dfu_settings.bank_1, 0, sizeof(s_dfu_settings.bank_1));
 | 
			
		||||
 | 
			
		||||
        nrf_dfu_settings_write(NULL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int32_t sz = flashAddr + FLASH_PAGE_SIZE;
 | 
			
		||||
    if (s_dfu_settings.bank_0.image_size < sz)
 | 
			
		||||
        s_dfu_settings.bank_0.image_size = sz;
 | 
			
		||||
 | 
			
		||||
    NRF_LOG_DEBUG("Flush at %x", flashAddr);
 | 
			
		||||
    if (memcmp(flashBuf, (void *)flashAddr, FLASH_PAGE_SIZE) != 0) {
 | 
			
		||||
        NRF_LOG_DEBUG("Write flush at %x", flashAddr);
 | 
			
		||||
        nrf_nvmc_page_erase(flashAddr);
 | 
			
		||||
        nrf_nvmc_write_words(flashAddr, (uint32_t *)flashBuf, FLASH_PAGE_SIZE / sizeof(uint32_t));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    flashAddr = NO_CACHE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void flash_write(uint32_t dst, const uint8_t *src, int len) {
 | 
			
		||||
    uint32_t newAddr = dst & ~(FLASH_PAGE_SIZE - 1);
 | 
			
		||||
 | 
			
		||||
    hadWrite = true;
 | 
			
		||||
 | 
			
		||||
    if (newAddr != flashAddr) {
 | 
			
		||||
        flushFlash();
 | 
			
		||||
        flashAddr = newAddr;
 | 
			
		||||
        memcpy(flashBuf, (void *)newAddr, FLASH_PAGE_SIZE);
 | 
			
		||||
    }
 | 
			
		||||
    memcpy(flashBuf + (dst & (FLASH_PAGE_SIZE - 1)), src, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uf2_timer(void *p_context) {
 | 
			
		||||
    UNUSED_PARAMETER(p_context);
 | 
			
		||||
    if (hadWrite) {
 | 
			
		||||
        flushFlash();
 | 
			
		||||
        s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_VALID_APP;
 | 
			
		||||
        int32_t start = SD_MAGIC_OK() ? MAIN_APPLICATION_START_ADDR : MBR_SIZE;
 | 
			
		||||
        int32_t sz = s_dfu_settings.bank_0.image_size - start;
 | 
			
		||||
        if (sz > 0)
 | 
			
		||||
            s_dfu_settings.bank_0.image_size = sz;
 | 
			
		||||
        nrf_dfu_settings_write(NULL);
 | 
			
		||||
    }
 | 
			
		||||
    NVIC_SystemReset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uf2_timer_start(int ms);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void padded_memcpy(char *dst, const char *src, int len) {
 | 
			
		||||
    for (int i = 0; i < len; ++i) {
 | 
			
		||||
        if (*src)
 | 
			
		||||
            *dst = *src++;
 | 
			
		||||
        else
 | 
			
		||||
            *dst = ' ';
 | 
			
		||||
        dst++;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void read_block(uint32_t block_no, uint8_t *data) {
 | 
			
		||||
    memset(data, 0, 512);
 | 
			
		||||
    uint32_t sectionIdx = block_no;
 | 
			
		||||
 | 
			
		||||
    if (block_no == 0) {
 | 
			
		||||
        memcpy(data, &BootBlock, sizeof(BootBlock));
 | 
			
		||||
        data[510] = 0x55;
 | 
			
		||||
        data[511] = 0xaa;
 | 
			
		||||
        // logval("data[0]", data[0]);
 | 
			
		||||
    } else if (block_no < START_ROOTDIR) {
 | 
			
		||||
        sectionIdx -= START_FAT0;
 | 
			
		||||
        // logval("sidx", sectionIdx);
 | 
			
		||||
        if (sectionIdx >= SECTORS_PER_FAT)
 | 
			
		||||
            sectionIdx -= SECTORS_PER_FAT;
 | 
			
		||||
        if (sectionIdx == 0) {
 | 
			
		||||
            data[0] = 0xf0;
 | 
			
		||||
            for (int i = 1; i < NUM_INFO * 2 + 4; ++i) {
 | 
			
		||||
                data[i] = 0xff;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        for (int i = 0; i < 256; ++i) {
 | 
			
		||||
            uint32_t v = sectionIdx * 256 + i;
 | 
			
		||||
            if (UF2_FIRST_SECTOR <= v && v <= UF2_LAST_SECTOR)
 | 
			
		||||
                ((uint16_t *)(void *)data)[i] = v == UF2_LAST_SECTOR ? 0xffff : v + 1;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (block_no < START_CLUSTERS) {
 | 
			
		||||
        sectionIdx -= START_ROOTDIR;
 | 
			
		||||
        if (sectionIdx == 0) {
 | 
			
		||||
            DirEntry *d = (void *)data;
 | 
			
		||||
            padded_memcpy(d->name, (const char *)BootBlock.VolumeLabel, 11);
 | 
			
		||||
            d->attrs = 0x28;
 | 
			
		||||
            for (int i = 0; i < NUM_INFO; ++i) {
 | 
			
		||||
                d++;
 | 
			
		||||
                const struct TextFile *inf = &info[i];
 | 
			
		||||
                d->size = inf->content ? strlen(inf->content) : UF2_SIZE;
 | 
			
		||||
                d->startCluster = i + 2;
 | 
			
		||||
                padded_memcpy(d->name, inf->name, 11);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        sectionIdx -= START_CLUSTERS;
 | 
			
		||||
        if (sectionIdx < NUM_INFO - 1) {
 | 
			
		||||
            memcpy(data, info[sectionIdx].content, strlen(info[sectionIdx].content));
 | 
			
		||||
        } else {
 | 
			
		||||
            sectionIdx -= NUM_INFO - 1;
 | 
			
		||||
            uint32_t addr = sectionIdx * 256;
 | 
			
		||||
            if (addr < FLASH_SIZE) {
 | 
			
		||||
                UF2_Block *bl = (void *)data;
 | 
			
		||||
                bl->magicStart0 = UF2_MAGIC_START0;
 | 
			
		||||
                bl->magicStart1 = UF2_MAGIC_START1;
 | 
			
		||||
                bl->magicEnd = UF2_MAGIC_END;
 | 
			
		||||
                bl->blockNo = sectionIdx;
 | 
			
		||||
                bl->numBlocks = FLASH_SIZE / 256;
 | 
			
		||||
                bl->targetAddr = addr;
 | 
			
		||||
                bl->payloadSize = 256;
 | 
			
		||||
                memcpy(bl->data, (void *)addr, bl->payloadSize);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int32_t tud_msc_read10_cb (uint8_t rhport, uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport; (void) lun;
 | 
			
		||||
 | 
			
		||||
  // since we return block size each, offset should always be zero
 | 
			
		||||
  TU_ASSERT(offset == 0, -1);
 | 
			
		||||
 | 
			
		||||
  uint32_t count = 0;
 | 
			
		||||
 | 
			
		||||
  while ( count < bufsize )
 | 
			
		||||
  {
 | 
			
		||||
    read_block(lba, buffer);
 | 
			
		||||
 | 
			
		||||
    lba++;
 | 
			
		||||
    buffer += 512;
 | 
			
		||||
    count  += 512;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void write_block(uint32_t block_no, uint8_t *data, bool quiet, WriteState *state) {
 | 
			
		||||
    UF2_Block *bl = (void *)data;
 | 
			
		||||
 | 
			
		||||
    // NRF_LOG_DEBUG("Write magic: %x", bl->magicStart0);
 | 
			
		||||
 | 
			
		||||
    if (!is_uf2_block(bl)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((bl->flags & UF2_FLAG_NOFLASH) || bl->payloadSize > 256 || (bl->targetAddr & 0xff) ||
 | 
			
		||||
        bl->targetAddr < USER_FLASH_START || bl->targetAddr + bl->payloadSize > USER_FLASH_END) {
 | 
			
		||||
#if USE_DBG_MSC
 | 
			
		||||
        if (!quiet)
 | 
			
		||||
            logval("invalid target addr", bl->targetAddr);
 | 
			
		||||
#endif
 | 
			
		||||
        NRF_LOG_WARNING("Skip block at %x", bl->targetAddr);
 | 
			
		||||
        // this happens when we're trying to re-flash CURRENT.UF2 file previously
 | 
			
		||||
        // copied from a device; we still want to count these blocks to reset properly
 | 
			
		||||
    } else {
 | 
			
		||||
        // logval("write block at", bl->targetAddr);
 | 
			
		||||
        NRF_LOG_DEBUG("Write block at %x", bl->targetAddr);
 | 
			
		||||
        flash_write(bl->targetAddr, bl->data, bl->payloadSize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool isSet = false;
 | 
			
		||||
 | 
			
		||||
    if (state && bl->numBlocks) {
 | 
			
		||||
        if (state->numBlocks != bl->numBlocks) {
 | 
			
		||||
            if (bl->numBlocks >= MAX_BLOCKS || state->numBlocks)
 | 
			
		||||
                state->numBlocks = 0xffffffff;
 | 
			
		||||
            else
 | 
			
		||||
                state->numBlocks = bl->numBlocks;
 | 
			
		||||
        }
 | 
			
		||||
        if (bl->blockNo < MAX_BLOCKS) {
 | 
			
		||||
            uint8_t mask = 1 << (bl->blockNo % 8);
 | 
			
		||||
            uint32_t pos = bl->blockNo / 8;
 | 
			
		||||
            if (!(state->writtenMask[pos] & mask)) {
 | 
			
		||||
                // logval("incr", state->numWritten);
 | 
			
		||||
                state->writtenMask[pos] |= mask;
 | 
			
		||||
                state->numWritten++;
 | 
			
		||||
            }
 | 
			
		||||
            if (state->numWritten >= state->numBlocks) {
 | 
			
		||||
                // wait a little bit before resetting, to avoid Windows transmit error
 | 
			
		||||
                // https://github.com/Microsoft/uf2-samd21/issues/11
 | 
			
		||||
                if (!quiet) {
 | 
			
		||||
                    uf2_timer_start(30);
 | 
			
		||||
                    isSet = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        NRF_LOG_DEBUG("wr %d=%d (of %d)", state->numWritten, bl->blockNo, bl->numBlocks);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!isSet && !quiet) {
 | 
			
		||||
        // uf2_timer_start(500);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										206
									
								
								src/usb/uf2/nrf_block_dev_uf2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								src/usb/uf2/nrf_block_dev_uf2.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,206 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright (c) 2016 - 2017, Nordic Semiconductor ASA
 | 
			
		||||
 * 
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * 
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without modification,
 | 
			
		||||
 * are permitted provided that the following conditions are met:
 | 
			
		||||
 * 
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright notice, this
 | 
			
		||||
 *    list of conditions and the following disclaimer.
 | 
			
		||||
 * 
 | 
			
		||||
 * 2. Redistributions in binary form, except as embedded into a Nordic
 | 
			
		||||
 *    Semiconductor ASA integrated circuit in a product or a software update for
 | 
			
		||||
 *    such product, must reproduce the above copyright notice, this list of
 | 
			
		||||
 *    conditions and the following disclaimer in the documentation and/or other
 | 
			
		||||
 *    materials provided with the distribution.
 | 
			
		||||
 * 
 | 
			
		||||
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 | 
			
		||||
 *    contributors may be used to endorse or promote products derived from this
 | 
			
		||||
 *    software without specific prior written permission.
 | 
			
		||||
 * 
 | 
			
		||||
 * 4. This software, with or without modification, must only be used with a
 | 
			
		||||
 *    Nordic Semiconductor ASA integrated circuit.
 | 
			
		||||
 * 
 | 
			
		||||
 * 5. Any software provided in binary form under this license must not be reverse
 | 
			
		||||
 *    engineered, decompiled, modified and/or disassembled.
 | 
			
		||||
 * 
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 | 
			
		||||
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 | 
			
		||||
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 | 
			
		||||
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 | 
			
		||||
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
#include "nrf_block_dev_uf2.h"
 | 
			
		||||
 | 
			
		||||
/**@file
 | 
			
		||||
 *
 | 
			
		||||
 * @ingroup nrf_block_dev
 | 
			
		||||
 * @{
 | 
			
		||||
 *
 | 
			
		||||
 * @brief This module implements block device API. It should be used as a reference block device.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static ret_code_t block_dev_uf2_init(nrf_block_dev_t const * p_blk_dev,
 | 
			
		||||
                                     nrf_block_dev_ev_handler ev_handler,
 | 
			
		||||
                                     void const * p_context)
 | 
			
		||||
{
 | 
			
		||||
    ASSERT(p_blk_dev);
 | 
			
		||||
    nrf_block_dev_uf2_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_uf2_t, block_dev);
 | 
			
		||||
    nrf_block_dev_uf2_work_t * p_work = p_ram_dev->p_work;
 | 
			
		||||
 | 
			
		||||
    p_work->geometry.blk_size = 512;
 | 
			
		||||
    p_work->geometry.blk_count = UF2_NUM_BLOCKS;
 | 
			
		||||
    p_work->p_context = p_context;
 | 
			
		||||
    p_work->ev_handler = ev_handler;
 | 
			
		||||
 | 
			
		||||
    if (p_work->ev_handler)
 | 
			
		||||
    {
 | 
			
		||||
        const nrf_block_dev_event_t ev = {
 | 
			
		||||
                NRF_BLOCK_DEV_EVT_INIT,
 | 
			
		||||
                NRF_BLOCK_DEV_RESULT_SUCCESS,
 | 
			
		||||
                NULL,
 | 
			
		||||
                p_work->p_context
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        p_work->ev_handler(p_blk_dev, &ev);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return NRF_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ret_code_t block_dev_uf2_uninit(nrf_block_dev_t const * p_blk_dev)
 | 
			
		||||
{
 | 
			
		||||
    ASSERT(p_blk_dev);
 | 
			
		||||
    nrf_block_dev_uf2_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_uf2_t, block_dev);
 | 
			
		||||
    nrf_block_dev_uf2_work_t * p_work = p_ram_dev->p_work;
 | 
			
		||||
 | 
			
		||||
    if (p_work->ev_handler)
 | 
			
		||||
    {
 | 
			
		||||
        /*Asynchronous operation (simulation)*/
 | 
			
		||||
        const nrf_block_dev_event_t ev = {
 | 
			
		||||
                NRF_BLOCK_DEV_EVT_UNINIT,
 | 
			
		||||
                NRF_BLOCK_DEV_RESULT_SUCCESS,
 | 
			
		||||
                NULL,
 | 
			
		||||
                p_work->p_context
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        p_work->ev_handler(p_blk_dev, &ev);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memset(p_work, 0, sizeof(nrf_block_dev_uf2_work_t));
 | 
			
		||||
    return NRF_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void write_block(uint32_t block_no, uint8_t *data, bool quiet, WriteState *state);
 | 
			
		||||
void read_block(uint32_t block_no, uint8_t *data);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static WriteState wrState;
 | 
			
		||||
 | 
			
		||||
static ret_code_t block_dev_uf2_req(nrf_block_dev_t const * p_blk_dev,
 | 
			
		||||
                                    nrf_block_req_t const * p_blk,
 | 
			
		||||
                                    nrf_block_dev_event_type_t event)
 | 
			
		||||
{
 | 
			
		||||
    ASSERT(p_blk_dev);
 | 
			
		||||
    ASSERT(p_blk);
 | 
			
		||||
    nrf_block_dev_uf2_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_uf2_t, block_dev);
 | 
			
		||||
    nrf_block_dev_uf2_work_t const * p_work = p_ram_dev->p_work;
 | 
			
		||||
 | 
			
		||||
    if (event == NRF_BLOCK_DEV_EVT_BLK_READ_DONE) {
 | 
			
		||||
        for (uint32_t i = 0; i < p_blk->blk_count; ++i)
 | 
			
		||||
            read_block(p_blk->blk_id + i, p_blk->p_buff + i * 512);
 | 
			
		||||
    } else {
 | 
			
		||||
        for (uint32_t i = 0; i < p_blk->blk_count; ++i)
 | 
			
		||||
            write_block(p_blk->blk_id + i, p_blk->p_buff + i * 512, false, &wrState);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (p_work->ev_handler)
 | 
			
		||||
    {
 | 
			
		||||
        /*Asynchronous operation (simulation)*/
 | 
			
		||||
        const nrf_block_dev_event_t ev = {
 | 
			
		||||
                event,
 | 
			
		||||
                NRF_BLOCK_DEV_RESULT_SUCCESS,
 | 
			
		||||
                p_blk,
 | 
			
		||||
                p_work->p_context
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        p_work->ev_handler(p_blk_dev, &ev);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return NRF_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ret_code_t block_dev_uf2_read_req(nrf_block_dev_t const * p_blk_dev,
 | 
			
		||||
                                         nrf_block_req_t const * p_blk)
 | 
			
		||||
{
 | 
			
		||||
    return block_dev_uf2_req(p_blk_dev, p_blk, NRF_BLOCK_DEV_EVT_BLK_READ_DONE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ret_code_t block_dev_uf2_write_req(nrf_block_dev_t const * p_blk_dev,
 | 
			
		||||
                                          nrf_block_req_t const * p_blk)
 | 
			
		||||
{
 | 
			
		||||
    return block_dev_uf2_req(p_blk_dev, p_blk, NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ret_code_t block_dev_uf2_ioctl(nrf_block_dev_t const * p_blk_dev,
 | 
			
		||||
                                      nrf_block_dev_ioctl_req_t req,
 | 
			
		||||
                                      void * p_data)
 | 
			
		||||
{
 | 
			
		||||
    nrf_block_dev_uf2_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_uf2_t, block_dev);
 | 
			
		||||
    switch (req)
 | 
			
		||||
    {
 | 
			
		||||
        case NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH:
 | 
			
		||||
        {
 | 
			
		||||
            bool * p_flushing = p_data;
 | 
			
		||||
            if (p_flushing)
 | 
			
		||||
            {
 | 
			
		||||
                *p_flushing = false;
 | 
			
		||||
            }
 | 
			
		||||
            return NRF_SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
        case NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS:
 | 
			
		||||
        {
 | 
			
		||||
            if (p_data == NULL)
 | 
			
		||||
            {
 | 
			
		||||
                return NRF_ERROR_INVALID_PARAM;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            nrf_block_dev_info_strings_t const * * pp_strings = p_data;
 | 
			
		||||
            *pp_strings = &p_ram_dev->info_strings;
 | 
			
		||||
            return NRF_SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return NRF_ERROR_NOT_SUPPORTED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static nrf_block_dev_geometry_t const * block_dev_uf2_geometry(nrf_block_dev_t const * p_blk_dev)
 | 
			
		||||
{
 | 
			
		||||
    ASSERT(p_blk_dev);
 | 
			
		||||
    nrf_block_dev_uf2_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_uf2_t, block_dev);
 | 
			
		||||
    nrf_block_dev_uf2_work_t const * p_work = p_ram_dev->p_work;
 | 
			
		||||
 | 
			
		||||
    return &p_work->geometry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const nrf_block_dev_ops_t nrf_block_device_uf2_ops = {
 | 
			
		||||
        .init = block_dev_uf2_init,
 | 
			
		||||
        .uninit = block_dev_uf2_uninit,
 | 
			
		||||
        .read_req = block_dev_uf2_read_req,
 | 
			
		||||
        .write_req = block_dev_uf2_write_req,
 | 
			
		||||
        .ioctl = block_dev_uf2_ioctl,
 | 
			
		||||
        .geometry = block_dev_uf2_geometry,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
							
								
								
									
										137
									
								
								src/usb/uf2/nrf_block_dev_uf2.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								src/usb/uf2/nrf_block_dev_uf2.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright (c) 2016 - 2017, Nordic Semiconductor ASA
 | 
			
		||||
 * 
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * 
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without modification,
 | 
			
		||||
 * are permitted provided that the following conditions are met:
 | 
			
		||||
 * 
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright notice, this
 | 
			
		||||
 *    list of conditions and the following disclaimer.
 | 
			
		||||
 * 
 | 
			
		||||
 * 2. Redistributions in binary form, except as embedded into a Nordic
 | 
			
		||||
 *    Semiconductor ASA integrated circuit in a product or a software update for
 | 
			
		||||
 *    such product, must reproduce the above copyright notice, this list of
 | 
			
		||||
 *    conditions and the following disclaimer in the documentation and/or other
 | 
			
		||||
 *    materials provided with the distribution.
 | 
			
		||||
 * 
 | 
			
		||||
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 | 
			
		||||
 *    contributors may be used to endorse or promote products derived from this
 | 
			
		||||
 *    software without specific prior written permission.
 | 
			
		||||
 * 
 | 
			
		||||
 * 4. This software, with or without modification, must only be used with a
 | 
			
		||||
 *    Nordic Semiconductor ASA integrated circuit.
 | 
			
		||||
 * 
 | 
			
		||||
 * 5. Any software provided in binary form under this license must not be reverse
 | 
			
		||||
 *    engineered, decompiled, modified and/or disassembled.
 | 
			
		||||
 * 
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 | 
			
		||||
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 | 
			
		||||
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 | 
			
		||||
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 | 
			
		||||
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 * 
 | 
			
		||||
 */
 | 
			
		||||
#ifndef NRF_BLOCK_DEV_UF2_H__
 | 
			
		||||
#define NRF_BLOCK_DEV_UF2_H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "uf2.h"
 | 
			
		||||
#include "nrf_block_dev.h"
 | 
			
		||||
 | 
			
		||||
/**@file
 | 
			
		||||
 *
 | 
			
		||||
 * @defgroup nrf_block_dev_uf2 RAM implementation
 | 
			
		||||
 * @ingroup nrf_block_dev
 | 
			
		||||
 * @{
 | 
			
		||||
 | 
			
		||||
 *
 | 
			
		||||
 * @brief This module implements block device API. It should be used as a reference block device.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief RAM block device operations
 | 
			
		||||
 * */
 | 
			
		||||
extern const nrf_block_dev_ops_t nrf_block_device_uf2_ops;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Work structure of RAM block device
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    nrf_block_dev_geometry_t geometry;      //!< Block device geometry
 | 
			
		||||
    nrf_block_dev_ev_handler ev_handler;    //!< Block device event handler
 | 
			
		||||
    void const *             p_context;     //!< Context handle passed to event handler
 | 
			
		||||
} nrf_block_dev_uf2_work_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief RAM block device config initializer (@ref nrf_block_dev_uf2_config_t)
 | 
			
		||||
 *
 | 
			
		||||
 * @param blk_size      Block size
 | 
			
		||||
 * @param buffer        RAM work buffer
 | 
			
		||||
 * @param buffer_size   RAM work buffer size
 | 
			
		||||
 * */
 | 
			
		||||
#define NRF_BLOCK_DEV_UF2_CONFIG(volLbl)  {      \
 | 
			
		||||
        .volume_label = volLbl,                                       \
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Ram block device config
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char *volume_label;
 | 
			
		||||
} nrf_block_dev_uf2_config_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Ram block device
 | 
			
		||||
 * */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    nrf_block_dev_t              block_dev;     //!< Block device
 | 
			
		||||
    nrf_block_dev_info_strings_t info_strings;  //!< Block device information strings
 | 
			
		||||
    nrf_block_dev_uf2_config_t   ram_config;    //!< Ram block device config
 | 
			
		||||
    nrf_block_dev_uf2_work_t *   p_work;        //!< Ram block device work structure
 | 
			
		||||
} nrf_block_dev_uf2_t;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Defines a RAM block device.
 | 
			
		||||
 *
 | 
			
		||||
 * @param name          Instance name
 | 
			
		||||
 * @param config        Configuration @ref nrf_block_dev_uf2_config_t
 | 
			
		||||
 * @param info          Info strings @ref NFR_BLOCK_DEV_INFO_CONFIG
 | 
			
		||||
 * */
 | 
			
		||||
#define NRF_BLOCK_DEV_UF2_DEFINE(name, config, info)                \
 | 
			
		||||
    static nrf_block_dev_uf2_work_t CONCAT_2(name, _work);          \
 | 
			
		||||
    static const nrf_block_dev_uf2_t name = {                       \
 | 
			
		||||
        .block_dev = { .p_ops = &nrf_block_device_uf2_ops },        \
 | 
			
		||||
        .info_strings = BRACKET_EXTRACT(info),                      \
 | 
			
		||||
        .ram_config = config,                                       \
 | 
			
		||||
        .p_work = &CONCAT_2(name, _work),                           \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Returns block device API handle from RAM block device.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in] p_blk_ram Ram block device
 | 
			
		||||
 * @return Block device handle
 | 
			
		||||
 */
 | 
			
		||||
static inline nrf_block_dev_t const *
 | 
			
		||||
nrf_block_dev_uf2_ops_get(nrf_block_dev_uf2_t const * p_blk_ram)
 | 
			
		||||
{
 | 
			
		||||
    return &p_blk_ram->block_dev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* NRF_BLOCK_DEV_UF2_H__ */
 | 
			
		||||
							
								
								
									
										124
									
								
								src/usb/uf2/uf2.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/usb/uf2/uf2.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
			
		||||
#ifndef UF2FORMAT_H
 | 
			
		||||
#define UF2FORMAT_H 1
 | 
			
		||||
 | 
			
		||||
#include "uf2cfg.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include "app_util.h"
 | 
			
		||||
 | 
			
		||||
#include "dfu_types.h"
 | 
			
		||||
 | 
			
		||||
#define SD_MAGIC_NUMBER 0x51b1e5db
 | 
			
		||||
#define SD_MAGIC_OK() (*((uint32_t*)(SOFTDEVICE_INFO_STRUCT_ADDRESS+4)) == 0x51b1e5db)
 | 
			
		||||
extern bool sdRunning;
 | 
			
		||||
 | 
			
		||||
// All entries are little endian.
 | 
			
		||||
 | 
			
		||||
#define UF2_MAGIC_START0 0x0A324655UL // "UF2\n"
 | 
			
		||||
#define UF2_MAGIC_START1 0x9E5D5157UL // Randomly selected
 | 
			
		||||
#define UF2_MAGIC_END 0x0AB16F30UL    // Ditto
 | 
			
		||||
 | 
			
		||||
// If set, the block is "comment" and should not be flashed to the device
 | 
			
		||||
#define UF2_FLAG_NOFLASH 0x00000001
 | 
			
		||||
 | 
			
		||||
#define MAX_BLOCKS (FLASH_SIZE / 256 + 100)
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t numBlocks;
 | 
			
		||||
    uint32_t numWritten;
 | 
			
		||||
    uint8_t writtenMask[MAX_BLOCKS / 8 + 1];
 | 
			
		||||
} WriteState;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    // 32 byte header
 | 
			
		||||
    uint32_t magicStart0;
 | 
			
		||||
    uint32_t magicStart1;
 | 
			
		||||
    uint32_t flags;
 | 
			
		||||
    uint32_t targetAddr;
 | 
			
		||||
    uint32_t payloadSize;
 | 
			
		||||
    uint32_t blockNo;
 | 
			
		||||
    uint32_t numBlocks;
 | 
			
		||||
    uint32_t reserved;
 | 
			
		||||
 | 
			
		||||
    // raw data;
 | 
			
		||||
    uint8_t data[476];
 | 
			
		||||
 | 
			
		||||
    // store magic also at the end to limit damage from partial block reads
 | 
			
		||||
    uint32_t magicEnd;
 | 
			
		||||
} UF2_Block;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint8_t version;
 | 
			
		||||
    uint8_t ep_in;
 | 
			
		||||
    uint8_t ep_out;
 | 
			
		||||
    uint8_t reserved0;
 | 
			
		||||
    uint32_t cbw_tag;
 | 
			
		||||
    uint32_t blocks_remaining;
 | 
			
		||||
    uint8_t *buffer;
 | 
			
		||||
} UF2_HandoverArgs;
 | 
			
		||||
 | 
			
		||||
typedef void (*UF2_MSC_Handover_Handler)(UF2_HandoverArgs *handover);
 | 
			
		||||
typedef void (*UF2_HID_Handover_Handler)(int ep);
 | 
			
		||||
 | 
			
		||||
// this is required to be exactly 16 bytes long by the linker script
 | 
			
		||||
typedef struct {
 | 
			
		||||
    void *reserved0;
 | 
			
		||||
    UF2_HID_Handover_Handler handoverHID;
 | 
			
		||||
    UF2_MSC_Handover_Handler handoverMSC;
 | 
			
		||||
    const char *info_uf2;
 | 
			
		||||
} UF2_BInfo;
 | 
			
		||||
 | 
			
		||||
#define UF2_BINFO ((UF2_BInfo *)(APP_START_ADDRESS - sizeof(UF2_BInfo)))
 | 
			
		||||
 | 
			
		||||
static inline bool is_uf2_block(void *data) {
 | 
			
		||||
    UF2_Block *bl = (UF2_Block *)data;
 | 
			
		||||
    return bl->magicStart0 == UF2_MAGIC_START0 && bl->magicStart1 == UF2_MAGIC_START1 &&
 | 
			
		||||
           bl->magicEnd == UF2_MAGIC_END;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool in_uf2_bootloader_space(const void *addr) {
 | 
			
		||||
    return USER_FLASH_END <= (uint32_t)addr && (uint32_t)addr < FLASH_SIZE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef UF2_DEFINE_HANDOVER
 | 
			
		||||
static inline const char *uf2_info(void) {
 | 
			
		||||
    if (in_uf2_bootloader_space(UF2_BINFO->info_uf2))
 | 
			
		||||
        return UF2_BINFO->info_uf2;
 | 
			
		||||
    return "N/A";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void hf2_handover(uint8_t ep) {
 | 
			
		||||
    const char *board_info = UF2_BINFO->info_uf2;
 | 
			
		||||
    UF2_HID_Handover_Handler fn = UF2_BINFO->handoverHID;
 | 
			
		||||
 | 
			
		||||
    if (in_uf2_bootloader_space(board_info) && in_uf2_bootloader_space((const void *)fn) &&
 | 
			
		||||
        ((uint32_t)fn & 1)) {
 | 
			
		||||
        // Pass control to bootloader; never returns
 | 
			
		||||
        fn(ep & 0xf);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// the ep_in/ep_out are without the 0x80 mask
 | 
			
		||||
// cbw_tag is in the same bit format as it came
 | 
			
		||||
static inline void check_uf2_handover(uint8_t *buffer, uint32_t blocks_remaining, uint8_t ep_in,
 | 
			
		||||
                                      uint8_t ep_out, uint32_t cbw_tag) {
 | 
			
		||||
    if (!is_uf2_block(buffer))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    const char *board_info = UF2_BINFO->info_uf2;
 | 
			
		||||
    UF2_MSC_Handover_Handler fn = UF2_BINFO->handoverMSC;
 | 
			
		||||
 | 
			
		||||
    if (in_uf2_bootloader_space(board_info) && in_uf2_bootloader_space((const void *)fn) &&
 | 
			
		||||
        ((uint32_t)fn & 1)) {
 | 
			
		||||
        UF2_HandoverArgs hand = {
 | 
			
		||||
            1, ep_in, ep_out, 0, cbw_tag, blocks_remaining, buffer,
 | 
			
		||||
        };
 | 
			
		||||
        // Pass control to bootloader; never returns
 | 
			
		||||
        fn(&hand);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										13
									
								
								src/usb/uf2/uf2cfg.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/usb/uf2/uf2cfg.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
#define UF2_VERSION "1.00"
 | 
			
		||||
#define PRODUCT_NAME "Adafruit Bluefruit nRF52"
 | 
			
		||||
#define BOARD_ID "NRF52-Bluefruit-v0"
 | 
			
		||||
#define INDEX_URL "https://www.adafruit.com/product/0000"
 | 
			
		||||
#define UF2_NUM_BLOCKS 8000
 | 
			
		||||
#define VOLUME_LABEL "NRFBOOT"
 | 
			
		||||
#define FLASH_SIZE (1024*1024)
 | 
			
		||||
 | 
			
		||||
// Only allow to write application
 | 
			
		||||
#define USER_FLASH_START 0x26000
 | 
			
		||||
#define USER_FLASH_END BOOTLOADER_REGION_START
 | 
			
		||||
 | 
			
		||||
#define FLASH_PAGE_SIZE 4096
 | 
			
		||||
		Reference in New Issue
	
	Block a user