Compare commits

...
34 Commits
Author SHA1 Message Date
hathach f5b654eb5e update changelog 2019-03-27 13:14:54 +07:00
hathach 60debfc217 Merge pull request #60 from adafruit/develop
fix #59 incorrect button mapping for feather nrf52840
2019-03-26 23:09:27 -07:00
hathach 2713069643 fix #59 incorrect button mapping for feather nrf52840 2019-03-27 13:03:41 +07:00
hathach 8df909f0a8 Merge pull request #57 from henrygab/patch-6
Fix FAT bugs and increase file count limit
2019-03-19 04:50:52 -07:00
hathach 1d816c5cf3 Merge pull request #56 from henrygab/patch-5
Ignore additional SES and J-Link files
2019-03-19 03:02:06 -07:00
Henry Gabryjelski 66d1770407 manually add another lost comment 2019-03-19 01:01:50 -07:00
Henry Gabryjelski 8ab4774c93 Manual merge?
Pickup a couple changes that don't seem to be propagating?
Possible that there's some git merge I missed, but it's simple enough to fix manually.
2019-03-19 00:57:24 -07:00
Henry Gabryjelski 1b54f0457d PR review requested changes.
Per hathach's request, remove built-in test option.
Per hathach's request, remote __TIME__ from info file.
2019-03-19 00:37:53 -07:00
Henry Gabryjelski a004b7619e Add trailing newline 2019-03-18 22:14:52 -07:00
Henry Gabryjelski 04fc396fd8 Put macros into new file, rather than uf2.h. 2019-03-13 23:49:52 -07:00
Henry Gabryjelski 04e0df1c18 prepare to split file 2019-03-13 23:40:18 -07:00
Henry Gabryjelski 6d58633db0 Merge branch 'master' of https://github.com/adafruit/Adafruit_nRF52_Bootloader into patch-6
# Conflicts:
#	src/usb/uf2/ghostfat.c
2019-03-13 22:39:12 -07:00
Henry Gabryjelski 15ca75d10d Merge branch 'master' of https://github.com/adafruit/Adafruit_nRF52_Bootloader into patch-5 2019-03-13 22:23:08 -07:00
Henry Gabryjelski 174e6e9724 Fix Directory entries
The media would show as corrupt in CMD.EXE in Windows.
This is because the date/time fields were invalid.
Since this needed to be fixed anyways, update so that
the date and time correspond to the time that the
preprocessor parsed the source file.
2019-03-13 22:05:57 -07:00
Henry Gabryjelski 53a99195bf Raises file limit from 14 to 62 files.
Enable all four sectors of root directory to contain files.
2019-03-13 21:38:59 -07:00
Henry Gabryjelski 8def8aee53 Safer code
Add additional compile-time assertions
Add additional comments to define limitations future maintainers should be aware of.
2019-03-13 18:28:43 -07:00
Henry Gabryjelski c51a227fd9 Add static assert
This guards against future increase in number of files
causing buffer overflow when reading the first root directory sector.
2019-03-13 15:24:42 -07:00
Henry Gabryjelski f3e3cefb23 Ignore additional SES and J-Link files 2019-03-13 13:10:49 -07:00
hathach 73456ac80e Merge pull request #54 from henrygab/patch-2
Avoid returning uninitialized memory
2019-03-13 01:08:06 -07:00
hathach 113195eabd Merge branch 'master' into patch-2 2019-03-13 00:58:21 -07:00
hathach 0eeff3e679 Merge pull request #53 from henrygab/patch-3
Fix signed/unsigned bug.
2019-03-13 00:55:54 -07:00
hathach be5a925f72 Merge pull request #55 from henrygab/patch-4
Use local variable to store partially-calculated size.
2019-03-13 00:53:37 -07:00
hathach ae28f5b425 Merge pull request #52 from henrygab/patch-1
Fix media type mismatch
2019-03-13 00:46:49 -07:00
Henry Gabryjelski b8a0551678 Use local variable to store partially-calculated size.
This avoid re-entrancy problems, such as if this is ever
interrupted mid-execution, and called a second time before
the initial execution completes.
2019-03-12 13:41:33 -07:00
Henry Gabryjelski 0f216b8618 Fix spacing 2019-03-12 13:13:58 -07:00
Henry Gabryjelski 52cfdaa2d2 Fix signed/unsigned bug. 2019-03-12 13:05:21 -07:00
Henry Gabryjelski a258c6d988 Avoid returning uninitialized memory 2019-03-12 12:57:51 -07:00
Henry Gabryjelski e0251415e7 Add some additional comments. 2019-03-12 12:29:05 -07:00
Henry Gabryjelski 12bb62eadd Per request, keep hard drive type in boot block.
Update the .PhysicalDrive in boot block.
Update the first fat entries to match MediaDescriptor of boot block.
2019-03-12 12:09:49 -07:00
Henry Gabryjelski e2afc36dae Fix media type mismatch
Fix the boot sector media descriptor to match the first FAT entries.
2019-03-10 20:02:56 -07:00
hathach 4ea74d4600 Update README.md 2019-03-06 00:52:07 +07:00
hathach 9bc01fb061 Merge pull request #49 from gpshead/mdk_dongle
Support the MDK nrf52840 USB Dongle.
2019-03-05 09:49:36 -08:00
Gregory P. Smith 01492634b6 Use RGB red and blue as primary and secondary.
The code currently expects a primary LED no matter what so the
RGB led support combined with that clobbers the nice pulsing primary.
2019-03-03 21:12:30 -08:00
Gregory P. Smith 05726e2575 Initial MakerDiary MDK nrf52840 USB dongle support.
Many TODOs to address but it builds and appears at first glance to work...
2019-03-03 18:58:34 -08:00
10 changed files with 396 additions and 34 deletions

No files matched your search

+2
View File
@@ -54,3 +54,5 @@ dkms.conf
src/segger/Output
_build-*/
bin/
*.emSession
*.jlink
+2
View File
@@ -251,6 +251,8 @@ CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -fno-builtin --short-enums -fstack-usage
# Defined Symbol (MACROS)
# TODO use GIT_VERSION (numberic format)
CFLAGS += -DMK_BOOTLOADER_VERSION=0x0$(SD_VER1)0$(SD_VER2)0$(SD_VER3)UL
CFLAGS += -D__HEAP_SIZE=0
+1
View File
@@ -9,6 +9,7 @@ This is a CDC/DFU/UF2 bootloader for nRF52 boards.
- Particle Argon
- Particle Boron
- Particle Xenon
- MakerDiary MDK nRF52840 USB Dongle
UF2 is an easy-to-use bootloader that appears as a flash drive. You can just copy `.uf2`-format
application images to the flash drive to load new firmware.
+6
View File
@@ -1,5 +1,11 @@
# Adafruit nRF52 Bootloader Changelog
## 0.2.10
- Fixed various FAT issues, thanks to @henrygab
- Added MakerDiary MDK nrf52840 USB dongle support, thanks to @gpshead
- Fixed incorrect button mapping for Feather nRF52840
## 0.2.9
- Fixed incomplete writes on Windows. Upated tinyusb to handle write10 completion, and use it for finalizing dfu process. Will prevent windows error message pop up. This will also give an extra time for flash writing to complete.
+2 -2
View File
@@ -53,8 +53,8 @@
/* BUTTON
*------------------------------------------------------------------*/
#define BUTTONS_NUMBER 2
#define BUTTON_1 _PINNUM(0, 15)
#define BUTTON_2 _PINNUM(0, 19)
#define BUTTON_1 _PINNUM(1, 02)
#define BUTTON_2 _PINNUM(0, 10)
#define BUTTON_PULL NRF_GPIO_PIN_PULLUP
/*------------------------------------------------------------------*/
+74
View File
@@ -0,0 +1,74 @@
/**************************************************************************/
/*!
@file mdk_nrf52840_dongle.h
@author gpshead (krypto.org)
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2019, Adafruit Industries (adafruit.com)
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 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 the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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 _MDK_NRF52840_DONGLE_H_
#define _MDK_NRF52840_DONGLE_H_
#define _PINNUM(port, pin) ((port)*32 + (pin))
/*------------------------------------------------------------------*/
/* LED
*------------------------------------------------------------------*/
#define LEDS_NUMBER 2 // TODO(gpshead): support 0.
#define LED_PRIMARY_PIN _PINNUM(0, 23) // Red
#define LED_SECONDARY_PIN _PINNUM(0, 24) // Blue
#define LED_STATE_ON 0
//#define LED_RGB_RED_PIN _PINNUM(0, 23)
//#define LED_RGB_GREEN_PIN _PINNUM(0, 22)
//#define LED_RGB_BLUE_PIN _PINNUM(0, 24)
#define BOARD_RGB_BRIGHTNESS 0x404040
/*------------------------------------------------------------------*/
/* BUTTON
*------------------------------------------------------------------*/
// TODO(gpshead): simplify, have code support 0. double reset only.
#define BUTTONS_NUMBER 2 // none connected at all
#define BUTTON_1 _PINNUM(0, 18) // unusable: RESET
#define BUTTON_2 _PINNUM(0, 19) // no connection
#define BUTTON_PULL NRF_GPIO_PIN_PULLUP
// Used as model string in OTA mode
#define DIS_MANUFACTURER "MakerDiary"
#define DIS_MODEL "nRF52840 Micro Dev Kit USB Dongle"
#define PRODUCT_NAME "MDK nRF52840 USB Dongle"
#define VOLUME_LABEL "MDK840DONGL"
#define BOARD_ID "MakerDiary-nRF52840-USB-Dongle"
#define INDEX_URL "https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/"
#endif /* _MDK_NRF52840_DONGLE_H_ */
@@ -63,6 +63,7 @@
<file file_name="../usb/uf2/uf2cfg.h" />
<file file_name="../usb/uf2/uf2.h" />
<file file_name="../usb/uf2/ghostfat.c" />
<file file_name="../usb/uf2/macros.h" />
</folder>
<file file_name="../usb/msc_uf2.c" />
<file file_name="../usb/usb.c" />
+4 -2
View File
@@ -63,7 +63,8 @@ int write_block(uint32_t block_no, uint8_t *data, bool quiet, WriteState *state)
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
void const* response = NULL;
uint16_t resplen = 0;
int32_t resplen = 0;
memset(buffer, 0, bufsize);
switch ( scsi_cmd[0] )
{
@@ -98,7 +99,7 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
}
// return len must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize;
if ( resplen > (int32_t)bufsize ) resplen = bufsize;
// copy response to stack's buffer if any
if ( response && resplen )
@@ -114,6 +115,7 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
(void) lun;
memset(buffer, 0, bufsize);
// since we return block size each, offset should always be zero
TU_ASSERT(offset == 0, -1);
+79 -30
View File
@@ -1,4 +1,6 @@
#include "macros.h"
#include "uf2.h"
#include "flash_nrf5x.h"
#include <string.h>
@@ -47,7 +49,6 @@ typedef struct {
uint16_t startCluster;
uint32_t size;
} __attribute__((packed)) DirEntry;
STATIC_ASSERT(sizeof(DirEntry) == 32);
struct TextFile {
@@ -59,6 +60,7 @@ struct TextFile {
#define STR0(x) #x
#define STR(x) STR0(x)
const char infoUf2File[] = //
"UF2 Bootloader " UF2_VERSION "\r\n"
"Model: " PRODUCT_NAME "\r\n"
@@ -76,16 +78,27 @@ const char indexFile[] = //
"</body>"
"</html>\n";
// WARNING -- code presumes only one NULL .content for .UF2 file
// and requires it be the last element of the array
static struct TextFile const info[] = {
{.name = "INFO_UF2TXT", .content = infoUf2File},
{.name = "INDEX HTM", .content = indexFile},
{.name = "CURRENT UF2"},
};
#define NUM_INFO (sizeof(info) / sizeof(info[0]))
// WARNING -- code presumes each non-UF2 file content fits in single sector
// Cannot programmatically statically assert .content length
// for each element above.
STATIC_ASSERT(ARRAY_SIZE2(indexFile) < 512);
#define NUM_FILES (ARRAY_SIZE2(info))
#define NUM_DIRENTRIES (NUM_FILES + 1) // Code adds volume label as first root directory entry
#define UF2_SIZE (current_flash_size() * 2)
#define UF2_SECTORS (UF2_SIZE / 512)
#define UF2_FIRST_SECTOR (NUM_INFO + 1)
#define UF2_FIRST_SECTOR (NUM_FILES + 1) // WARNING -- code presumes each non-UF2 file content fits in single sector
#define UF2_LAST_SECTOR (UF2_FIRST_SECTOR + UF2_SECTORS - 1)
#define RESERVED_SECTORS 1
@@ -97,6 +110,13 @@ static struct TextFile const info[] = {
#define START_ROOTDIR (START_FAT1 + SECTORS_PER_FAT)
#define START_CLUSTERS (START_ROOTDIR + ROOT_DIR_SECTORS)
// all directory entries must fit in a single sector
// because otherwise current code overflows buffer
#define DIRENTRIES_PER_SECTOR (512/sizeof(DirEntry))
STATIC_ASSERT(NUM_DIRENTRIES < DIRENTRIES_PER_SECTOR * ROOT_DIR_SECTORS);
static FAT_BootBlock const BootBlock = {
.JumpInstruction = {0xeb, 0x3c, 0x90},
.OEMInfo = "UF2 UF2 ",
@@ -104,12 +124,13 @@ static FAT_BootBlock const BootBlock = {
.SectorsPerCluster = 1,
.ReservedSectors = RESERVED_SECTORS,
.FATCopies = 2,
.RootDirectoryEntries = (ROOT_DIR_SECTORS * 512 / 32),
.RootDirectoryEntries = (ROOT_DIR_SECTORS * DIRENTRIES_PER_SECTOR),
.TotalSectors16 = NUM_FAT_BLOCKS - 2,
.MediaDescriptor = 0xF8,
.SectorsPerFAT = SECTORS_PER_FAT,
.SectorsPerTrack = 1,
.Heads = 1,
.PhysicalDriveNum = 0x80, // to match MediaDescriptor of 0xF8
.ExtendedBootSig = 0x29,
.VolumeSerialNumber = 0x00420042,
.VolumeLabel = VOLUME_LABEL,
@@ -123,35 +144,37 @@ static FAT_BootBlock const BootBlock = {
static uint32_t current_flash_size(void)
{
static uint32_t flash_sz = 0;
uint32_t result = flash_sz; // presumes atomic 32-bit read/write and static result
// only need to compute once
if ( flash_sz == 0 )
if ( result == 0 )
{
// return 1 block of 256 bytes
if ( !bootloader_app_is_valid(DFU_BANK_0_REGION_START) )
{
flash_sz = 256;
result = 256;
}else
{
bootloader_settings_t const * boot_setting;
bootloader_util_settings_get(&boot_setting);
flash_sz = boot_setting->bank_0_size;
result = boot_setting->bank_0_size;
// Copy size must be multiple of 256 bytes
// else we will got an issue copying current.uf2
if (flash_sz & 0xff)
if (result & 0xff)
{
flash_sz = (flash_sz & ~0xff) + 256;
result = (result & ~0xff) + 256;
}
// if bank0 size is not valid, happens when flashed with jlink
// use maximum application size
if ( (flash_sz == 0) || (flash_sz == 0xFFFFFFFFUL) )
if ( (result == 0) || (result == 0xFFFFFFFFUL) )
{
flash_sz = FLASH_SIZE;
result = FLASH_SIZE;
}
}
flash_sz = result; // presumes atomic 32-bit read/write and static result
}
return flash_sz;
@@ -176,47 +199,73 @@ void read_block(uint32_t block_no, uint8_t *data) {
memset(data, 0, 512);
uint32_t sectionIdx = block_no;
if (block_no == 0) {
if (block_no == 0) { // Requested boot block
memcpy(data, &BootBlock, sizeof(BootBlock));
data[510] = 0x55;
data[511] = 0xaa;
// logval("data[0]", data[0]);
} else if (block_no < START_ROOTDIR) {
} else if (block_no < START_ROOTDIR) { // Requested FAT table sector
sectionIdx -= START_FAT0;
// logval("sidx", sectionIdx);
if (sectionIdx >= SECTORS_PER_FAT)
sectionIdx -= SECTORS_PER_FAT;
sectionIdx -= SECTORS_PER_FAT; // second FAT is same as the first...
if (sectionIdx == 0) {
data[0] = 0xf0;
for (int i = 1; i < NUM_INFO * 2 + 4; ++i) {
data[0] = 0xf8; // first FAT entry must match BPB MediaDescriptor
// WARNING -- code presumes only one NULL .content for .UF2 file
// and all non-NULL .content fit in one sector
// and requires it be the last element of the array
for (int i = 1; i < NUM_FILES * 2 + 4; ++i) {
data[i] = 0xff;
}
}
for (int i = 0; i < 256; ++i) {
for (int i = 0; i < 256; ++i) { // Generate the FAT chain for the firmware "file"
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) {
} else if (block_no < START_CLUSTERS) { // Requested root directory sector
sectionIdx -= START_ROOTDIR;
if (sectionIdx == 0) {
DirEntry *d = (void *)data;
DirEntry *d = (void *)data;
int remainingEntries = DIRENTRIES_PER_SECTOR;
if (sectionIdx == 0) { // volume label first
// volume label is first directory entry
padded_memcpy(d->name, (char const *) BootBlock.VolumeLabel, 11);
d->attrs = 0x28;
for (int i = 0; i < NUM_INFO; ++i) {
d++;
struct TextFile const *inf = &info[i];
d->size = inf->content ? strlen(inf->content) : UF2_SIZE;
d->startCluster = i + 2;
padded_memcpy(d->name, inf->name, 11);
}
d++;
remainingEntries--;
}
for (int i = DIRENTRIES_PER_SECTOR * sectionIdx;
remainingEntries > 0 && i < NUM_FILES;
i++, d++) {
// WARNING -- code presumes all but last file take exactly one sector
uint16_t startCluster = i + 2;
struct TextFile const * inf = &info[i];
padded_memcpy(d->name, inf->name, 11);
d->createTimeFine = __SECONDS_INT__ % 2 * 100;
d->createTime = __DOSTIME__;
d->createDate = __DOSDATE__;
d->lastAccessDate = __DOSDATE__;
d->highStartCluster = startCluster >> 8;
// DIR_WrtTime and DIR_WrtDate must be supported
d->updateTime = __DOSTIME__;
d->updateDate = __DOSDATE__;
d->startCluster = startCluster & 0xFF;
// WARNING -- code presumes only one NULL .content for .UF2 file
// and requires it be the last element of the array
d->size = inf->content ? strlen(inf->content) : UF2_SIZE;
}
} else {
sectionIdx -= START_CLUSTERS;
if (sectionIdx < NUM_INFO - 1) {
if (sectionIdx < NUM_FILES - 1) {
memcpy(data, info[sectionIdx].content, strlen(info[sectionIdx].content));
} else {
sectionIdx -= NUM_INFO - 1;
} else { // generate the UF2 file data on-the-fly
sectionIdx -= NUM_FILES - 1;
uint32_t addr = USER_FLASH_START + sectionIdx * 256;
if (addr < USER_FLASH_START+FLASH_SIZE) {
UF2_Block *bl = (void *)data;
+225
View File
@@ -0,0 +1,225 @@
/**
The MIT License (MIT)
Copyright (c)
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.
*/
#ifndef ARRAYSIZE2_H
#define ARRAYSIZE2_H
#ifndef __has_feature
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#if __cplusplus >= 199711L
#pragma message "using Ivan J. Johnson's ARRAY_SIZE2"
// Works on older compilers, even Visual C++ 6....
// Created by Ivan J. Johnson, March 06, 2007
// See http://drdobbs.com/cpp/197800525?pgno=1
//
// Pseudocode:
// if x is not an array
// issue a compile-time error
// else
// use the traditional (non-typesafe) C99 COUNTOF expression
//
// If the argument is any of:
// object of class type, such as an std::vector
// floating-point type
// function pointer
// pointer-to-member
// then the first reinterpret_cast<> is not legal (compiler error)
//
// The type for check1 is chosen and named to help understand
// the cause of the error, because the class name is likely to
// appear in the compiler error message.
//
// If check1 succeeds, then the argument must be one of:
// an integral type
// an enumerated type
// a pointer to an object
// an array
//
// Check2 expands approximately to sizeof(check_type(x, &x)),
// where check_type is an overloaded function.
// Because this is purely a compile-time computation,
// the function is never really called or even implemented,
// but it lets the compiler apply overload resolution,
// which allows further type discrimination.
// There are three possibilities to consider:
// x is an integral type or enumerated type.
// In this case, neither of the two function overloads
// is a match, resulting in a compiler error.
// x is a pointer to an object.
// In this case, the first argument to check_type()
// is a pointer and the second one is a pointer-to-pointer.
// The best function match is the first overload of check_type,
// the one that returns an incomplete type (Is_pointer).
// However, because Is_pointer is an incomplete type,
// sizeof(Is_pointer) is not a valid expression,
// resulting in a compiler error.
// x is an array.
// In this case, the first argument to check_type()
// is an array and the second is a pointer-to-array.
// A pointer-to-array is *NOT* convertible to a
// pointer-to-pointer, so the first overload of
// check_type() is not a match.
// However, an array IS convertible to a pointer,
// and a pointer-to-array already is a pointer.
// Any pointer is convertible to a void*,
// so the second function overload is a match.
// That overload returns a complete type (Is_array).
// Because it's a complete type,
// sizeof(Is_array) is a valid expression.
// Thus, the compiler has EXCLUDED every possible type
// except arrays via compilation errors before reaching
// the third line.
// Moreover, check1 and check2 are reduced to the value zero,
// while the third line is the old type-unsafe C-style macro,
// now made entirely type-safe.
//
// Additional benefits:
// The result is itself constexpr
//
//
#define ARRAY_SIZE2(arr) ( \
0 * sizeof(reinterpret_cast<const ::Bad_arg_to_COUNTOF*>(arr)) + /*check1*/ \
0 * sizeof(::Bad_arg_to_COUNTOF::check_type((arr), &(arr))) + /*check2*/ \
sizeof(arr) / sizeof((arr)[0]) /* eval */ \
)
struct Bad_arg_to_COUNTOF {
class Is_pointer; // incomplete
class Is_array {};
template <typename T>
static Is_pointer check_type(const T*, const T* const*);
static Is_array check_type(const void*, const void*);
};
#elif __cplusplus >= 201103L || /* any compiler claiming C++11 support */ \
_MSC_VER >= 1900 || /* Visual C++ 2015 or higher */ \
__has_feature(cxx_constexpr) /* CLang versions supporting constexp */
#pragma message "C++11 version ARRAY_SIZE2"
namespace detail
{
template <typename T, std::size_t N>
constexpr std::size_t countof(T const (&)[N]) noexcept
{
return N;
}
} // namespace detail
#define ARRAY_SIZE2(arr) detail::countof(arr)
#elif _MSC_VER // Visual C++ fallback
#pragma message "using Microsoft Visual C++ intrinsic ARRAY_SIZE2"
#define ARRAY_SIZE2(arr) _countof(arr)
#elif __cplusplus >= 199711L && ( /* C++ 98 trick */ \
defined(__INTEL_COMPILER) || \
defined(__clang__) || \
(defined(__GNUC__) && ( \
(__GNUC__ > 4) || \
(__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \
)))
#pragma message "C++98 version ARRAY_SIZE2"
template <typename T, std::size_t N>
char(&_ArraySizeHelperRequiresArray(T(&)[N]))[N];
#define ARRAY_SIZE2(x) sizeof(_ArraySizeHelperRequiresArray(x))
#else
#pragma message "Using type-unsafe version of ARRAY_SIZE2"
// This is the worst-case scenario macro.
// While it is valid C, it is NOT typesafe.
// For example, if the parameter arr is a pointer instead of array,
// the compiler will SILENTLY give a (likely) incorrect result.
#define ARRAY_SIZE2(arr) sizeof(arr) / sizeof(arr[0])
#endif
#endif // ARRAYSIZE2_H
#ifndef COMPILE_DATE_H
#define COMPILE_DATE_H
#define __YEAR_INT__ ((( \
(__DATE__ [ 7u] - '0') * 10u + \
(__DATE__ [ 8u] - '0')) * 10u + \
(__DATE__ [ 9u] - '0')) * 10u + \
(__DATE__ [10u] - '0'))
#define __MONTH_INT__ ( \
(__DATE__ [2u] == 'n' && __DATE__ [1u] == 'a') ? 1u /*Jan*/ \
: (__DATE__ [2u] == 'b' ) ? 2u /*Feb*/ \
: (__DATE__ [2u] == 'r' && __DATE__ [1u] == 'a') ? 3u /*Mar*/ \
: (__DATE__ [2u] == 'r' ) ? 4u /*Apr*/ \
: (__DATE__ [2u] == 'y' ) ? 5u /*May*/ \
: (__DATE__ [2u] == 'n' ) ? 6u /*Jun*/ \
: (__DATE__ [2u] == 'l' ) ? 7u /*Jul*/ \
: (__DATE__ [2u] == 'g' ) ? 8u /*Jul*/ \
: (__DATE__ [2u] == 'p' ) ? 9u /*Jul*/ \
: (__DATE__ [2u] == 't' ) ? 10u /*Jul*/ \
: (__DATE__ [2u] == 'v' ) ? 11u /*Jul*/ \
: 12u /*Dec*/ )
#define __DAY_INT__ ( \
(__DATE__ [4u] == ' ' ? 0u : __DATE__ [4u] - '0') * 10u \
+ (__DATE__ [5u] - '0') )
// __TIME__ expands to an eight-character string constant
// "23:59:01", or (if cannot determine time) "??:??:??"
#define __HOUR_INT__ ( \
(__TIME__ [0u] == '?' ? 0u : __TIME__ [0u] - '0') * 10u \
+ (__TIME__ [1u] == '?' ? 0u : __TIME__ [1u] - '0') )
#define __MINUTE_INT__ ( \
(__TIME__ [3u] == '?' ? 0u : __TIME__ [3u] - '0') * 10u \
+ (__TIME__ [4u] == '?' ? 0u : __TIME__ [4u] - '0') )
#define __SECONDS_INT__ ( \
(__TIME__ [6u] == '?' ? 0u : __TIME__ [6u] - '0') * 10u \
+ (__TIME__ [7u] == '?' ? 0u : __TIME__ [7u] - '0') )
#define __DOSDATE__ ( \
((__YEAR_INT__ - 1980u) << 9u) | \
( __MONTH_INT__ << 5u) | \
( __DAY_INT__ << 0u) )
#define __DOSTIME__ ( \
( __HOUR_INT__ << 11u) | \
( __MONTH_INT__ << 5u) | \
( __DAY_INT__ << 0u) )
#endif // COMPILE_DATE_H