Browse Source

add unit tests to esp-idf

rename nvs host test folder, modify .gitlab-ci.yml

remove unit-test-app build

re-format unit test files

remove extra newlines in project.mk

some refactoring for unit test part in project.mk

add build files of unit-test-app in gitignore

add README.md for unit test app

correct headings in README.md

remove files and make minor tweaks in unit test app

update .gitlab-ci.yml to use unit test app

delete unused lines in component_wrapper.mk

delete periph_i2s.h and lcd test

add text floating point in components/esp32/test/Kconfig

correct idf test build paths in .gitlab-ci.yml
antti 9 years ago
parent
commit
d390449371
59 changed files with 5215 additions and 15 deletions
  1. 5 0
      .gitignore
  2. 6 7
      .gitlab-ci.yml
  3. 1 1
      components/bootloader/Makefile.projbuild
  4. 9 0
      components/esp32/test/Kconfig
  5. 17 0
      components/esp32/test/component.mk
  6. BIN
      components/esp32/test/logo.jpg
  7. 293 0
      components/esp32/test/test_ahb_arb.c
  8. 51 0
      components/esp32/test/test_ahb_arb_asm.S
  9. 132 0
      components/esp32/test/test_fastbus.c
  10. 32 0
      components/esp32/test/test_fastbus_asm.S
  11. 195 0
      components/esp32/test/test_fp.c
  12. 77 0
      components/esp32/test/test_miniz.c
  13. 91 0
      components/esp32/test/test_tjpgd.c
  14. 205 0
      components/esp32/test/test_unal_dma.c
  15. 5 0
      components/freertos/test/component.mk
  16. 229 0
      components/freertos/test/test_freertos.c
  17. 105 0
      components/freertos/test/test_freertos_eventgroups.c
  18. 22 0
      components/freertos/test/test_freertos_task_delete.c
  19. 60 0
      components/freertos/test/test_newlib_reent.c
  20. 26 0
      components/freertos/test/test_panic.c
  21. 197 0
      components/freertos/test/test_ringbuf.c
  22. 58 0
      components/freertos/test/test_tls_deletecb.c
  23. 5 0
      components/mbedtls/test/component.mk
  24. 134 0
      components/mbedtls/test/test_mbedtls.c
  25. 5 0
      components/newlib/test/component.mk
  26. 102 0
      components/newlib/test/test_newlib.c
  27. 5 0
      components/nvs_flash/test/component.mk
  28. 54 0
      components/nvs_flash/test/test_nvs.c
  29. 0 0
      components/nvs_flash/test_nvs_host/Makefile
  30. 0 0
      components/nvs_flash/test_nvs_host/catch.hpp
  31. 0 0
      components/nvs_flash/test_nvs_host/crc.cpp
  32. 0 0
      components/nvs_flash/test_nvs_host/crc.h
  33. 0 0
      components/nvs_flash/test_nvs_host/main.cpp
  34. 0 0
      components/nvs_flash/test_nvs_host/sdkconfig.h
  35. 0 0
      components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp
  36. 0 0
      components/nvs_flash/test_nvs_host/spi_flash_emulation.h
  37. 0 0
      components/nvs_flash/test_nvs_host/test_compressed_enum_table.cpp
  38. 0 0
      components/nvs_flash/test_nvs_host/test_intrusive_list.cpp
  39. 0 0
      components/nvs_flash/test_nvs_host/test_nvs.cpp
  40. 0 0
      components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp
  41. 5 0
      components/partition_table/test/component.mk
  42. 95 0
      components/partition_table/test/test_partition.c
  43. 5 0
      components/spi_flash/test/component.mk
  44. 83 0
      components/spi_flash/test/test_mmap.c
  45. 92 0
      components/spi_flash/test/test_spi_flash.c
  46. 0 3
      make/component_wrapper.mk
  47. 11 4
      make/project.mk
  48. 9 0
      tools/unit-test-app/Makefile
  49. 12 0
      tools/unit-test-app/README.md
  50. 3 0
      tools/unit-test-app/components/unity/component.mk
  51. 292 0
      tools/unit-test-app/components/unity/include/unity.h
  52. 75 0
      tools/unit-test-app/components/unity/include/unity_config.h
  53. 772 0
      tools/unit-test-app/components/unity/include/unity_internals.h
  54. 21 0
      tools/unit-test-app/components/unity/license.txt
  55. 1306 0
      tools/unit-test-app/components/unity/unity.c
  56. 165 0
      tools/unit-test-app/components/unity/unity_platform.c
  57. 18 0
      tools/unit-test-app/main/app_main.c
  58. 5 0
      tools/unit-test-app/main/component.mk
  59. 125 0
      tools/unit-test-app/sdkconfig

+ 5 - 0
.gitignore

@@ -24,3 +24,8 @@ examples/*/build
 docs/_build/
 docs/doxygen-warning-log.txt
 docs/xml/
+
+# Unit test app files
+tools/unit-test-app/sdkconfig
+tools/unit-test-app/sdkconfig.old
+tools/unit-test-app/build

+ 6 - 7
.gitlab-ci.yml

@@ -78,15 +78,14 @@ build_esp_idf_tests:
   <<: *build_template
   artifacts:
     paths:
-      - ./esp-idf-tests/build/*.bin
-      - ./esp-idf-tests/build/*.elf
-      - ./esp-idf-tests/build/*.map
-      - ./esp-idf-tests/build/bootloader/*.bin
+      - ./tools/unit-test-app/build/*.bin
+      - ./tools/unit-test-app/build/*.elf
+      - ./tools/unit-test-app/build/*.map
+      - ./tools/unit-test-app/build/bootloader/*.bin
     expire_in: 6 mos
 
   script:
-    - git clone $GITLAB_SSH_SERVER/idf/esp-idf-tests.git
-    - cd esp-idf-tests
+    - cd tools/unit-test-app
     - git checkout ${CI_BUILD_REF_NAME} || echo "Using default branch..."
     - make defconfig
     - make
@@ -131,7 +130,7 @@ test_nvs_on_host:
   tags:
     - nvs_host_test
   script:
-    - cd components/nvs_flash/test
+    - cd components/nvs_flash/test_nvs_host
     - make test
 
 test_build_system:

+ 1 - 1
components/bootloader/Makefile.projbuild

@@ -20,7 +20,7 @@ export SECURE_BOOT_SIGNING_KEY  # used by bootloader_support component
 
 # Custom recursive make for bootloader sub-project
 BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \
-	V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR)
+	V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) TEST_COMPONENTS=
 
 .PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
 

+ 9 - 0
components/esp32/test/Kconfig

@@ -0,0 +1,9 @@
+menu "TESTS"
+
+config FP_TEST_ENABLE
+    bool "Enable test fp"
+    default "y"
+    help
+        For FPGA single core CPU which has no floating point support, floating point test should be disabled.
+
+endmenu

+ 17 - 0
components/esp32/test/component.mk

@@ -0,0 +1,17 @@
+#
+#Component Makefile
+#
+
+COMPONENT_EXTRA_CLEAN := test_tjpgd_logo.h
+
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
+
+COMPONENT_SRCDIRS := . test_vectors
+
+include $(IDF_PATH)/make/component_common.mk
+
+test_tjpgd.o: test_tjpgd_logo.h
+
+test_tjpgd_logo.h: $(COMPONENT_PATH)/logo.jpg
+	$(summary) XXD logo.jpg
+	$(Q) cd $(COMPONENT_PATH); xxd -i logo.jpg $(COMPONENT_BUILD_DIR)/test_tjpgd_logo.h

BIN
components/esp32/test/logo.jpg


+ 293 - 0
components/esp32/test/test_ahb_arb.c

@@ -0,0 +1,293 @@
+
+#include <esp_types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "rom/ets_sys.h"
+#include "rom/lldesc.h"
+#include "rom/gpio.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+
+#include "unity.h"
+
+#include "soc/uart_reg.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+#include "soc/gpio_sig_map.h"
+#include "soc/gpio_reg.h"
+#include "soc/i2s_reg.h"
+
+
+#define DPORT_I2S0_CLK_EN   (BIT(4))
+#define DPORT_I2S0_RST   (BIT(4))
+
+
+/*
+This test tests the s32c1i instruction when the AHB bus is also used. To create some AHB traffic, we use the I2S interface
+to copy bytes over from one memory location to another. DO NOT USE the i2s routines inhere, they've been trial-and-error'ed until
+the point where they happened to do what I want.
+*/
+
+static void lcdIfaceInit()
+{
+    SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
+    CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
+
+    //Init pins to i2s functions
+    SET_PERI_REG_MASK(GPIO_ENABLE_W1TS_REG, (1 << 11) | (1 << 3) | (1 << 0) | (1 << 2) | (1 << 5) | (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); //ENABLE GPIO oe_enable
+
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO18_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO20_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 2); //11
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, 0); //RS
+
+    WRITE_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG, (148 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC2_OUT_SEL_CFG_REG, (149 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC5_OUT_SEL_CFG_REG, (150 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC16_OUT_SEL_CFG_REG, (151 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC17_OUT_SEL_CFG_REG, (152 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC18_OUT_SEL_CFG_REG, (153 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC19_OUT_SEL_CFG_REG, (154 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC20_OUT_SEL_CFG_REG, (155 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC26_OUT_SEL_CFG_REG, (156 << GPIO_FUNC0_OUT_SEL_S)); //RS
+    WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, (I2S0O_WS_OUT_IDX << GPIO_FUNC0_OUT_SEL_S));
+//  WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG, (I2S0O_BCK_OUT_IDX<<GPIO_GPIO_FUNC0_OUT_SEL_S));
+
+    //GPIO_SET_GPIO_FUNC11_OUT_INV_SEL(1); //old
+    WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, READ_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG) | GPIO_FUNC11_OUT_INV_SEL);
+
+    //Reset I2S subsystem
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
+    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
+
+    WRITE_PERI_REG(I2S_CONF_REG(0), 0);//I2S_SIG_LOOPBACK);
+    WRITE_PERI_REG(I2S_CONF2_REG(0), 0);
+
+    WRITE_PERI_REG(I2S_SAMPLE_RATE_CONF_REG(0),
+                   (16 << I2S_RX_BITS_MOD_S) |
+                   (16 << I2S_TX_BITS_MOD_S) |
+                   (1 << I2S_RX_BCK_DIV_NUM_S) |
+                   (1 << I2S_TX_BCK_DIV_NUM_S));
+    WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
+                   I2S_CLKA_ENA | I2S_CLK_EN |
+                   (1 << I2S_CLKM_DIV_A_S) |
+                   (1 << I2S_CLKM_DIV_B_S) |
+                   (1 << I2S_CLKM_DIV_NUM_S));
+    WRITE_PERI_REG(I2S_FIFO_CONF_REG(0),
+                   (32 << I2S_TX_DATA_NUM_S) |     //Low watermark for IRQ
+                   (32 << I2S_RX_DATA_NUM_S));
+
+    WRITE_PERI_REG(I2S_CONF1_REG(0), I2S_RX_PCM_BYPASS | I2S_TX_PCM_BYPASS);
+
+    WRITE_PERI_REG(I2S_CONF_CHAN_REG(0), (2 << I2S_TX_CHAN_MOD_S) | (2 << I2S_RX_CHAN_MOD_S));
+
+    //Invert WS to active-low
+    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RIGHT_FIRST | I2S_RX_RIGHT_FIRST);
+    WRITE_PERI_REG(I2S_TIMING_REG(0), 0);
+}
+
+
+static volatile lldesc_t dmaDesc[2];
+
+static void finishDma()
+{
+    //No need to finish if no DMA transfer going on
+    if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) {
+        return;
+    }
+
+    //Wait till fifo done
+    while (!(READ_PERI_REG(I2S_INT_RAW_REG(0))&I2S_TX_REMPTY_INT_RAW)) ;
+    //Wait for last bytes to leave i2s xmit thing
+    //ToDo: poll bit in next hw
+//  for (i=0; i<(1<<8); i++);
+    while (!(READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_IDLE));
+
+    //Reset I2S for next transfer
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
+    CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START | I2S_INLINK_START);
+
+    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
+
+//  for (i=0; i<(1<<8); i++);
+    while ((READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_FIFO_RESET_BACK));
+}
+
+
+/*
+This is a very, very, very hacked up LCD routine which ends up basically doing a memcpy from sbuf to rbuf.
+*/
+static void sendRecvBufDma(uint16_t *sbuf, uint16_t *rbuf, int len)
+{
+    //Fill DMA descriptor
+    dmaDesc[0].length = len * 2;
+    dmaDesc[0].size = len * 2;
+    dmaDesc[0].owner = 1;
+    dmaDesc[0].sosf = 0;
+    dmaDesc[0].buf = (uint8_t *)sbuf;
+    dmaDesc[0].offset = 0; //unused in hw
+    dmaDesc[0].empty = 0;
+    dmaDesc[0].eof = 1;
+    dmaDesc[1].length = len * 2;
+    dmaDesc[1].size = len * 2;
+    dmaDesc[1].owner = 1;
+    dmaDesc[1].sosf = 0;
+    dmaDesc[1].buf = (uint8_t *)rbuf;
+    dmaDesc[1].offset = 0; //unused in hw
+    dmaDesc[1].empty = 0;
+    dmaDesc[1].eof = 1;
+
+    //Reset DMA
+    SET_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
+    CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
+
+    //Reset I2S FIFO
+    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
+
+    //Set desc addr
+    CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_ADDR);
+    SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), ((uint32_t)(&dmaDesc[0]))&I2S_OUTLINK_ADDR);
+    CLEAR_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_ADDR);
+    SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), ((uint32_t)(&dmaDesc[1]))&I2S_INLINK_ADDR);
+
+    SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(0), I2S_DSCR_EN); //Enable DMA mode
+
+    WRITE_PERI_REG(I2S_RXEOF_NUM_REG(0), len);
+
+    //Enable and configure DMA
+    WRITE_PERI_REG(I2S_LC_CONF_REG(0), I2S_OUT_DATA_BURST_EN  |
+                   I2S_OUT_EOF_MODE | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN |
+                   I2S_INDSCR_BURST_EN | I2S_MEM_TRANS_EN);
+
+    //Start transmission
+    SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START);
+    SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_START);
+
+    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
+    //Clear int flags
+    WRITE_PERI_REG(I2S_INT_CLR_REG(0), 0xFFFFFFFF);
+}
+
+
+#define DMALEN (2048-2)
+
+static void tskLcd(void *pvParameters)
+{
+    uint16_t *sbuf = malloc(DMALEN * 2);
+    uint16_t *rbuf = malloc(DMALEN * 2);
+    uint16_t xorval = 0;
+    int x;
+    lcdIfaceInit();
+//  lcdFlush();
+    while (1) {
+        for (x = 0; x < DMALEN; x++) {
+            sbuf[x] = x ^ xorval;
+        }
+        for (x = 0; x < DMALEN; x++) {
+            rbuf[x] = 0;    //clear rbuf
+        }
+        sendRecvBufDma(sbuf, rbuf, DMALEN);
+        vTaskDelay(20 / portTICK_PERIOD_MS);
+        finishDma();
+        for (x = 0; x < DMALEN; x++) if (rbuf[x] != (x ^ xorval)) {
+                printf("Rxbuf err! pos %d val %x xor %x", x, (int)rbuf[x], (int)xorval);
+            }
+        printf(".");
+        fflush(stdout);
+        xorval++;
+    }
+}
+
+
+
+void test_s32c1i_lock(volatile int *lockvar, int lockval, int unlockval, volatile int *ctr);
+
+static volatile int ctr = 0, state = 0;
+static volatile int lock = 0;
+
+static void tskOne(void *pvParameters)
+{
+    int x;
+    int err = 0, run = 0;
+    while (1) {
+        ctr = 0; lock = 0;
+        state = 1;
+        for (x = 0; x < 16 * 1024; x++) {
+            test_s32c1i_lock(&lock, 1, 0, &ctr);
+        }
+        vTaskDelay(60 / portTICK_PERIOD_MS);
+        state = 2;
+        if (ctr != 16 * 1024 * 2) {
+            printf("Lock malfunction detected! Ctr=0x%x instead of %x\n", ctr, 16 * 1024 * 2);
+            err++;
+        }
+        run++;
+        printf("Run %d err %d\n", run, err);
+        vTaskDelay(20 / portTICK_PERIOD_MS);
+    }
+}
+
+#define FB2ADDR 0x40098000
+
+static void tskTwo(void *pvParameters)
+{
+    int x;
+    int *p = (int *)FB2ADDR;
+    int *s = (int *)test_s32c1i_lock;
+    void (*test_s32c1i_lock2)(volatile int * lockvar, int lockval, int unlockval, volatile int * ctr) = (void *)FB2ADDR;
+    volatile int w;
+    int delay;
+    for (x = 0; x < 100; x++) {
+        *p++ = *s++;    //copy routine to different pool
+    }
+
+    while (1) {
+        while (state != 1) ;
+        for (x = 0; x < 16 * 1024; x++) {
+            test_s32c1i_lock2(&lock, 2, 0, &ctr);
+            //Some random delay to increase chance of weirdness
+            if ((x & 0x1f) == 0) {
+                delay = rand() & 0x1f;
+                for (w = 0; w < delay; w++);
+            }
+        }
+        while (state != 2);
+    }
+}
+
+
+TEST_CASE("S32C1I vs AHB test (needs I2S)", "[hw]")
+{
+    int i;
+    TaskHandle_t th[3];
+    state = 0;
+
+    printf("Creating tasks\n");
+    xTaskCreatePinnedToCore(tskTwo  , "tsktwo"  , 2048, NULL, 3, &th[1], 1);
+    xTaskCreatePinnedToCore(tskOne  , "tskone"  , 2048, NULL, 3, &th[0], 0);
+    xTaskCreatePinnedToCore(tskLcd  , "tsklcd"  , 2048, NULL, 3, &th[2], 0);
+
+    // Let stuff run for 20s
+    while (1) {
+        vTaskDelay(20000 / portTICK_PERIOD_MS);
+    }
+
+    //Shut down all the tasks
+    for (i = 0; i < 3; i++) {
+        vTaskDelete(th[i]);
+    }
+}
+

+ 51 - 0
components/esp32/test/test_ahb_arb_asm.S

@@ -0,0 +1,51 @@
+/*
+This little bit of code is executed in-place by one CPU, but copied to a different memory region
+by the other CPU. Make sure it stays position-independent.
+*/
+    .text
+    .align  4
+    .global test_s32c1i_lock
+    .type   test_s32c1i_lock,@function
+//Args:
+//a2 - lock addr
+//a3 - val to lock with
+//a4 - val to unlock with
+//a5 - addr to increase
+test_s32c1i_lock:
+	entry a1, 64
+	wsr a4, SCOMPARE1
+lockloop:
+	mov a6, a3
+	s32c1i a6, a2, 0
+	bne a4, a6, lockloop
+
+	l32i a6, a5, 0
+	//Give other CPU the time to mess up the inc if the lock somehow malfunctions
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	addi a6, a6, 1
+	s32i a6, a5, 0
+
+
+//No need to actually let this loop but hey, a hang indicates an error, right?
+	wsr a3, SCOMPARE1
+unlockloop:
+	mov a6, a4
+	s32c1i a6, a2, 0
+	bne a3, a6, unlockloop
+	
+	retw

+ 132 - 0
components/esp32/test/test_fastbus.c

@@ -0,0 +1,132 @@
+
+#include <esp_types.h>
+#include <stdio.h>
+#include "rom/ets_sys.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "unity.h"
+#include "soc/uart_reg.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+
+
+/*
+This test tests the 'fast' peripherial bus at 0x3ff40000. This bus is connected directly to the core, and as such
+can receive 'speculative' reads, that is, reads that may or may not actually be executed in the code flow. This
+may mess with any FIFOs mapped in the region: if a byte gets dropped due to a missed speculative read, the fifo
+may advance to the next byte anyway.
+
+This code tests reading/writing from the UART1 FIFO, using both cores. For this to work, it's required that the
+UARTs RX and TX lines are connected.
+*/
+
+
+void test_fastbus_cp(int fifo_addr, unsigned char *buf, int len, int *dummy);
+
+static volatile int state = 0;
+static volatile int xor = 0;
+static unsigned char res[128];
+
+static void tskOne(void *pvParameters)
+{
+    int run = 0, err = 0;
+    int x;
+    int ct[256];
+    volatile int w;
+    int dummy;
+    while (1) {
+        state = 1;
+        for (x = 0; x < 64; x++) {
+            WRITE_PERI_REG(UART_FIFO_REG(1), x ^ xor);
+        }
+        for (w = 0; w < (1 << 14); w++); //delay
+        state = 2;
+        test_fastbus_cp(UART_FIFO_REG(1), &res[0], 64, &dummy);
+        for (w = 0; w < (1 << 10); w++);    //delay
+        for (x = 0; x < 255; x++) {
+            ct[x] = 0;    //zero ctrs
+        }
+        for (x = 0; x < 128; x++) {
+            ct[(int)res[x]^xor]++;    //count values
+        }
+        for (x = 0; x < 255; x++) {         //check counts
+            if (ct[x] != (x < 128 ? 1 : 0)) {
+                //Disregard first few loops; there may be crap in the fifo.
+                if (run > 2) {
+                    err++;
+                    printf("Error! Received value %d %d times!\n", x, ct[x]);
+                }
+            }
+        }
+        run++;
+        if ((run & 255) == 0) {
+            printf("Loop %d errct %d\n", run, err);
+        }
+        xor = (xor + 1) & 0xff;
+    }
+}
+
+#define FB2ADDR 0x40098000
+
+static void tskTwo(void *pvParameters)
+{
+    int x;
+    int dummy;
+    int *p = (int *)FB2ADDR;
+    int *s = (int *)test_fastbus_cp;
+    for (x = 0; x < 100; x++) {
+        *p++ = *s++;
+    }
+    void (*test_fastbus_cp2)(int fifo_addr, unsigned char * buf, int len, int * dummy) = (void *)FB2ADDR;
+
+
+    while (1) {
+        while (state != 1) ;
+        for (x = 64; x < 128; x++) {
+            WRITE_PERI_REG(UART_FIFO_REG(1), x ^ xor);
+        }
+        while (state != 2);
+        test_fastbus_cp2(UART_FIFO_REG(1), &res[64], 64, &dummy);
+    }
+}
+
+
+// TODO: split this thing into separate orthogonal tests
+TEST_CASE("Fast I/O bus test", "[hw]")
+{
+    int i;
+    if ((REG_UART_BASE(0) >> 16) != 0x3ff4) {
+        printf("Error! Uart base isn't on fast bus.\n");
+        TEST_ASSERT(0);
+    }
+
+    PIN_PULLUP_DIS(PERIPHS_IO_MUX_SD_DATA3_U);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA2_U, FUNC_SD_DATA2_U1RXD);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA3_U, FUNC_SD_DATA3_U1TXD);
+
+    int reg_val = (1 << UART_RXFIFO_FULL_THRHD_S);
+    WRITE_PERI_REG(UART_CONF1_REG(1), reg_val);
+    WRITE_PERI_REG(UART_CLKDIV_REG(1), 0x30); //semi-random
+//  CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(1), UART_TXFIFO_EMPTY_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+
+    TaskHandle_t th[2];
+    printf("Creating tasks\n");
+    xTaskCreatePinnedToCore(tskOne  , "tskone"  , 2048, NULL, 3, &th[0], 0);
+    xTaskCreatePinnedToCore(tskTwo  , "tsktwo"  , 2048, NULL, 3, &th[1], 1);
+
+    // Let stuff run for 20s
+    while (1) {
+        vTaskDelay(20000 / portTICK_PERIOD_MS);
+    }
+
+    //Shut down all the tasks
+    for (i = 0; i < 2; i++) {
+        vTaskDelete(th[i]);
+    }
+    xt_ints_off(1 << ETS_UART0_INUM);
+}
+

+ 32 - 0
components/esp32/test/test_fastbus_asm.S

@@ -0,0 +1,32 @@
+/*
+This little bit of code is executed in-place by one CPU, but copied to a different memory region
+by the other CPU. Make sure it stays position-independent.
+*/
+    .text
+    .align  4
+    .global test_fastbus_cp
+    .type   test_fastbus_cp,@function
+//Args:
+//a2 - fifo addr
+//a3 - buf addr
+//a4 - len
+//a5 - ptr to int to use
+test_fastbus_cp:
+	entry a1,64
+back:
+	beqi a4, 0, out		//check if loop done
+	s32i a4, a5, 0		//store value, for shits and/or giggles
+	memw				//make sure write happens
+	l32i a4, a5, 0		//load value again, to thwart any prediction in the pipeline
+	bbsi a4, 0, pred	//Random jump to check predictive reads. Both branches should do the same.
+	l32i a6, a2, 0		//read from fifo 1
+	j predout
+pred:
+	l32i a6, a2, 0		//read from fifo 2
+predout:
+	s8i a6, a3, 0		//store result
+	addi a3, a3, 1		//inc ptr
+	addi a4, a4, -1		//next
+	j back				//loop again
+out:
+	retw				//and we are done

+ 195 - 0
components/esp32/test/test_fp.c

@@ -0,0 +1,195 @@
+#include <math.h>
+#include <stdio.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "unity.h"
+
+#if CONFIG_FP_TEST_ENABLE
+static float addsf(float a, float b)
+{
+    float result;
+    asm volatile (
+        "wfr f0, %1\n"
+        "wfr f1, %2\n"
+        "add.s f2, f0, f1\n"
+        "rfr %0, f2\n"
+        :"=r"(result):"r"(a), "r"(b)
+    );
+    return result;
+}
+
+static float mulsf(float a, float b)
+{
+    float result;
+    asm volatile (
+        "wfr f0, %1\n"
+        "wfr f1, %2\n"
+        "mul.s f2, f0, f1\n"
+        "rfr %0, f2\n"
+        :"=r"(result):"r"(a), "r"(b)
+    );
+    return result;
+}
+
+static float divsf(float a, float b)
+{
+    float result;
+    asm volatile (
+        "wfr f0, %1\n"
+        "wfr f1, %2\n"
+        "div0.s f3, f1 \n"
+        "nexp01.s f4, f1 \n"
+        "const.s f5, 1 \n"
+        "maddn.s f5, f4, f3 \n"
+        "mov.s f6, f3 \n"
+        "mov.s f7, f1 \n"
+        "nexp01.s f8, f0 \n"
+        "maddn.s f6, f5, f3 \n"
+        "const.s f5, 1 \n"
+        "const.s f2, 0 \n"
+        "neg.s f9, f8 \n"
+        "maddn.s f5,f4,f6 \n"
+        "maddn.s f2, f0, f3 \n"
+        "mkdadj.s f7, f0 \n"
+        "maddn.s f6,f5,f6 \n"
+        "maddn.s f9,f4,f2 \n"
+        "const.s f5, 1 \n"
+        "maddn.s f5,f4,f6 \n"
+        "maddn.s f2,f9,f6 \n"
+        "neg.s f9, f8 \n"
+        "maddn.s f6,f5,f6 \n"
+        "maddn.s f9,f4,f2 \n"
+        "addexpm.s f2, f7 \n"
+        "addexp.s f6, f7 \n"
+        "divn.s f2,f9,f6\n"
+        "rfr %0, f2\n"
+        :"=r"(result):"r"(a), "r"(b)
+    );
+    return result;
+}
+
+static float sqrtsf(float a)
+{
+    float result;
+    asm volatile (
+        "wfr f0, %1\n"
+        "sqrt0.s f2, f0\n"
+        "const.s f5, 0\n"
+        "maddn.s f5, f2, f2\n"
+        "nexp01.s f3, f0\n"
+        "const.s f4, 3\n"
+        "addexp.s f3, f4\n"
+        "maddn.s f4, f5, f3\n"
+        "nexp01.s f5, f0\n"
+        "neg.s f6, f5\n"
+        "maddn.s f2, f4, f2\n"
+        "const.s f1, 0\n"
+        "const.s f4, 0\n"
+        "const.s f7, 0\n"
+        "maddn.s f1, f6, f2\n"
+        "maddn.s f4, f2, f3\n"
+        "const.s f6, 3\n"
+        "maddn.s f7, f6, f2\n"
+        "maddn.s f5, f1, f1\n"
+        "maddn.s f6, f4, f2\n"
+        "neg.s f3, f7\n"
+        "maddn.s f1, f5, f3\n"
+        "maddn.s f7, f6, f7\n"
+        "mksadj.s f2, f0\n"
+        "nexp01.s f5, f0\n"
+        "maddn.s f5, f1, f1\n"
+        "neg.s f3, f7\n"
+        "addexpm.s f1, f2\n"
+        "addexp.s f3, f2\n"
+        "divn.s f1, f5, f3\n"
+        "rfr %0, f1\n"
+        :"=r"(result):"r"(a)
+    );
+    return result;
+}
+
+TEST_CASE("test FP add", "[fp]")
+{
+    float a = 100.0f;
+    float b = 0.5f;
+    float c = addsf(a, b);
+    float eps = c - 100.5f;
+    printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
+    TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
+}
+
+TEST_CASE("test FP mul", "[fp]")
+{
+    float a = 100.0f;
+    float b = 0.05f;
+    float c = mulsf(a, b);
+    float eps = c - 5.0f;
+    printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
+    TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
+}
+
+TEST_CASE("test FP div", "[fp]")
+{
+    float a = 100.0f;
+    float b = 5.0f;
+    float c = divsf(a, b);
+    float eps = c - 20.0f;
+    printf("a=%g b=%g c=%g eps=%g\r\n", a, b, c, eps);
+    TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
+}
+
+TEST_CASE("test FP sqrt", "[fp]")
+{
+    float a = 100.0f;
+    float c = sqrtsf(a);
+    float eps = c - 10.0f;
+    printf("a=%g c=%g eps=%g\r\n", a, c, eps);
+    TEST_ASSERT_TRUE(fabs(eps) < 0.000001);
+}
+
+
+struct TestFPState {
+    int fail;
+    int done;
+};
+
+static const int testFpIter = 100000;
+
+static void tskTestFP(void *pvParameters)
+{
+    struct TestFPState *state = (struct TestFPState *) pvParameters;
+    for (int i = 0; i < testFpIter; ++i) {
+        // calculate zero in a slightly obscure way
+        float y = sqrtsf(addsf(1.0f, divsf(mulsf(sqrtsf(2), sqrtsf(2)), 2.0f)));
+        y = mulsf(y, y);
+        y = addsf(y, -2.0f);
+        // check that result is not far from zero
+        float eps = fabs(y);
+        if (eps > 1e-6f) {
+            state->fail++;
+            printf("%s: i=%d y=%f eps=%f\r\n", __func__, i, y, eps);
+        }
+    }
+    state->done++;
+    vTaskDelete(NULL);
+}
+
+TEST_CASE("context switch saves FP registers", "[fp]")
+{
+    struct TestFPState state;
+    state.done = 0;
+    state.fail = 0;
+    xTaskCreatePinnedToCore(tskTestFP, "tsk1", 2048, &state, 3, NULL, 0);
+    xTaskCreatePinnedToCore(tskTestFP, "tsk2", 2048, &state, 3, NULL, 0);
+    xTaskCreatePinnedToCore(tskTestFP, "tsk3", 2048, &state, 3, NULL, 1);
+    xTaskCreatePinnedToCore(tskTestFP, "tsk4", 2048, &state, 3, NULL, 0);
+    while (state.done != 4) {
+        vTaskDelay(100 / portTICK_PERIOD_MS);
+    }
+    if (state.fail) {
+        const int total = testFpIter * 4;
+        printf("Failed: %d, total: %d\r\n", state.fail, total);
+    }
+    TEST_ASSERT(state.fail == 0);
+}
+#endif

+ 77 - 0
components/esp32/test/test_miniz.c

@@ -0,0 +1,77 @@
+
+
+#include <stdio.h>
+#include "rom/miniz.h"
+#include "unity.h"
+
+
+#define DATASIZE (1024*64)
+
+TEST_CASE("Test miniz compression/decompression", "[miniz]")
+{
+    int x;
+    char b;
+    char *inbuf, *outbuf;
+    tdefl_compressor *comp;
+    tinfl_decompressor *decomp;
+    tdefl_status status;
+    size_t inbytes = 0, outbytes = 0, inpos = 0, outpos = 0, compsz;
+    printf("Allocating data buffer and filling it with semi-random data\n");
+    inbuf = malloc(DATASIZE);
+    TEST_ASSERT(inbuf != NULL);
+    srand(0);
+    for (x = 0; x < DATASIZE; x++) {
+        inbuf[x] = (x & 1) ? rand() & 0xff : 0;
+    }
+    printf("Allocating compressor & outbuf (%d bytes)\n", sizeof(tdefl_compressor));
+    comp = malloc(sizeof(tdefl_compressor));
+    TEST_ASSERT(comp != NULL);
+    outbuf = malloc(DATASIZE);
+    TEST_ASSERT(outbuf != NULL);
+    printf("Compressing...\n");
+    status = tdefl_init(comp, NULL, NULL, TDEFL_WRITE_ZLIB_HEADER | 1500);
+    TEST_ASSERT(status == TDEFL_STATUS_OKAY);
+    while (inbytes != DATASIZE) {
+        outbytes = DATASIZE - outpos;
+        inbytes = DATASIZE - inpos;
+        tdefl_compress(comp, &inbuf[inpos], &inbytes, &outbuf[outpos], &outbytes, TDEFL_FINISH);
+        printf("...Compressed %d into %d bytes\n", inbytes, outbytes);
+        inpos += inbytes; outpos += outbytes;
+    }
+    compsz = outpos;
+    free(comp);
+    //Kill inbuffer
+    for (x = 0; x < DATASIZE; x++) {
+        inbuf[x] = 0;
+    }
+    free(inbuf);
+
+    inbuf = outbuf;
+    outbuf = malloc(DATASIZE);
+    TEST_ASSERT(outbuf != NULL);
+    printf("Reinflating...\n");
+    decomp = malloc(sizeof(tinfl_decompressor));
+    TEST_ASSERT(decomp != NULL);
+    tinfl_init(decomp);
+    inpos = 0; outpos = 0;
+    while (inbytes != compsz) {
+        outbytes = DATASIZE - outpos;
+        inbytes = compsz - inpos;
+        tinfl_decompress(decomp, (const mz_uint8 *)&inbuf[inpos], &inbytes, (uint8_t *)outbuf, (mz_uint8 *)&outbuf[outpos], &outbytes, TINFL_FLAG_PARSE_ZLIB_HEADER);
+        printf("...Decompressed %d into %d bytes\n", inbytes, outbytes);
+        inpos += inbytes; outpos += outbytes;
+    }
+    printf("Checking if same...\n");
+    srand(0);
+    for (x = 0; x < DATASIZE; x++) {
+        b = (x & 1) ? rand() & 0xff : 0;
+        if (outbuf[x] != b) {
+            printf("Pos %x: %hhx!=%hhx\n", x, outbuf[x], b);
+            TEST_ASSERT(0);
+        }
+    }
+    printf("Great Success!\n");
+    free(inbuf);
+    free(outbuf);
+    free(decomp);
+}

+ 91 - 0
components/esp32/test/test_tjpgd.c

@@ -0,0 +1,91 @@
+
+
+#include <stdio.h>
+#include "rom/tjpgd.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "unity.h"
+
+#include "test_tjpgd_logo.h"
+
+typedef struct {
+    const unsigned char *inData;
+    int inPos;
+    unsigned char *outData;
+    int outW;
+    int outH;
+} JpegDev;
+
+
+static UINT infunc(JDEC *decoder, BYTE *buf, UINT len)
+{
+    JpegDev *jd = (JpegDev *)decoder->device;
+    printf("Reading %d bytes from pos %d\n", len, jd->inPos);
+    if (buf != NULL) {
+        memcpy(buf, jd->inData + jd->inPos, len);
+    }
+    jd->inPos += len;
+    return len;
+}
+
+
+static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect)
+{
+    unsigned char *in = (unsigned char *)bitmap;
+    unsigned char *out;
+    int y;
+    printf("Rect %d,%d - %d,%d\n", rect->top, rect->left, rect->bottom, rect->right);
+    JpegDev *jd = (JpegDev *)decoder->device;
+    for (y = rect->top; y <= rect->bottom; y++) {
+        out = jd->outData + ((jd->outW * y) + rect->left) * 3;
+        memcpy(out, in, ((rect->right - rect->left) + 1) * 3);
+        in += ((rect->right - rect->left) + 1) * 3;
+    }
+    return 1;
+}
+
+#define TESTW 48
+#define TESTH 48
+#define WORKSZ 3100
+
+TEST_CASE("Test JPEG decompression library", "[tjpgd]")
+{
+    char aapix[] = " .:;+=xX$$";
+    unsigned char *decoded, *p;
+    char *work;
+    int r;
+    int x, y, v;
+    JDEC decoder;
+    JpegDev jd;
+    decoded = malloc(48 * 48 * 3);
+    for (x = 0; x < 48 * 48 * 3; x += 2) {
+        decoded[x] = 0; decoded[x + 1] = 0xff;
+    }
+    work = malloc(WORKSZ);
+    memset(work, 0, WORKSZ);
+
+    jd.inData = logo_jpg;
+    jd.inPos = 0;
+    jd.outData = decoded;
+    jd.outW = TESTW;
+    jd.outH = TESTH;
+
+    r = jd_prepare(&decoder, infunc, work, WORKSZ, (void *)&jd);
+    TEST_ASSERT_EQUAL(r, JDR_OK);
+    r = jd_decomp(&decoder, outfunc, 0);
+    TEST_ASSERT_EQUAL(r, JDR_OK);
+
+    p = decoded + 2;
+    for (y = 0; y < TESTH; y++) {
+        for (x = 0; x < TESTH; x++) {
+            v = ((*p) * (sizeof(aapix) - 2) * 2) / 256;
+            printf("%c%c", aapix[v / 2], aapix[(v + 1) / 2]);
+            p += 3;
+        }
+        printf("%c%c", ' ', '\n');
+    }
+
+    free(work);
+    free(decoded);
+}

+ 205 - 0
components/esp32/test/test_unal_dma.c

@@ -0,0 +1,205 @@
+
+#include <esp_types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rom/ets_sys.h"
+#include "rom/lldesc.h"
+#include "rom/gpio.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "unity.h"
+
+#include "soc/uart_reg.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+#include "soc/gpio_sig_map.h"
+#include "soc/gpio_reg.h"
+#include "soc/i2s_reg.h"
+
+
+#define DPORT_I2S0_CLK_EN   (BIT(4))
+#define DPORT_I2S0_RST   (BIT(4))
+
+static volatile lldesc_t dmaDesc[2];
+
+
+//hacked up routine to essentially do a memcpy() using dma. Supports max 4K-1 bytes.
+static void dmaMemcpy(void *in, void *out, int len)
+{
+    volatile int i;
+    SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
+    CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
+
+    //Init pins to i2s functions
+    SET_PERI_REG_MASK(GPIO_ENABLE_W1TS_REG, (1 << 11) | (1 << 3) | (1 << 0) | (1 << 2) | (1 << 5) | (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19) | (1 << 20)); //ENABLE GPIO oe_enable
+
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO18_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO20_U, 0);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 2); //11
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, 0); //RS
+
+    WRITE_PERI_REG(GPIO_FUNC0_OUT_SEL_CFG_REG, (148 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC2_OUT_SEL_CFG_REG, (149 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC5_OUT_SEL_CFG_REG, (150 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC16_OUT_SEL_CFG_REG, (151 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC17_OUT_SEL_CFG_REG, (152 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC18_OUT_SEL_CFG_REG, (153 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC19_OUT_SEL_CFG_REG, (154 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC20_OUT_SEL_CFG_REG, (155 << GPIO_FUNC0_OUT_SEL_S));
+    WRITE_PERI_REG(GPIO_FUNC26_OUT_SEL_CFG_REG, (156 << GPIO_FUNC0_OUT_SEL_S)); //RS
+    WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, (I2S0O_WS_OUT_IDX << GPIO_FUNC0_OUT_SEL_S));
+//  WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG, (I2S0O_BCK_OUT_IDX<<GPIO_GPIO_FUNC0_OUT_SEL_S));
+
+    //GPIO_SET_GPIO_FUNC11_OUT_INV_SEL(1); //old
+    WRITE_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG, READ_PERI_REG(GPIO_FUNC11_OUT_SEL_CFG_REG) | GPIO_FUNC11_OUT_INV_SEL);
+
+    //Reset I2S subsystem
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
+    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET);
+
+    WRITE_PERI_REG(I2S_CONF_REG(0), 0);//I2S_I2S_SIG_LOOPBACK);
+    WRITE_PERI_REG(I2S_CONF2_REG(0), 0);
+
+    WRITE_PERI_REG(I2S_SAMPLE_RATE_CONF_REG(0),
+                   (16 << I2S_RX_BITS_MOD_S) |
+                   (16 << I2S_TX_BITS_MOD_S) |
+                   (1 << I2S_RX_BCK_DIV_NUM_S) |
+                   (1 << I2S_TX_BCK_DIV_NUM_S));
+    WRITE_PERI_REG(I2S_CLKM_CONF_REG(0),
+                   I2S_CLKA_ENA | I2S_CLK_EN |
+                   (1 << I2S_CLKM_DIV_A_S) |
+                   (1 << I2S_CLKM_DIV_B_S) |
+                   (1 << I2S_CLKM_DIV_NUM_S));
+    WRITE_PERI_REG(I2S_FIFO_CONF_REG(0),
+                   (32 << I2S_TX_DATA_NUM_S) |     //Low watermark for IRQ
+                   (32 << I2S_RX_DATA_NUM_S));
+
+    WRITE_PERI_REG(I2S_CONF1_REG(0), I2S_RX_PCM_BYPASS | I2S_TX_PCM_BYPASS);
+
+    WRITE_PERI_REG(I2S_CONF_CHAN_REG(0), (2 << I2S_TX_CHAN_MOD_S) | (2 << I2S_RX_CHAN_MOD_S));
+
+    //Invert WS to active-low
+    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RIGHT_FIRST | I2S_RX_RIGHT_FIRST);
+    WRITE_PERI_REG(I2S_TIMING_REG(0), 0);
+
+//--
+    //Fill DMA descriptor
+    dmaDesc[0].length = len;
+    dmaDesc[0].size = len;
+    dmaDesc[0].owner = 1;
+    dmaDesc[0].sosf = 0;
+    dmaDesc[0].buf = (uint8_t *)in;
+    dmaDesc[0].offset = 0; //unused in hw
+    dmaDesc[0].empty = 0;
+    dmaDesc[0].eof = 1;
+    dmaDesc[1].length = len;
+    dmaDesc[1].size = len;
+    dmaDesc[1].owner = 1;
+    dmaDesc[1].sosf = 0;
+    dmaDesc[1].buf = (uint8_t *)out;
+    dmaDesc[1].offset = 0; //unused in hw
+    dmaDesc[1].empty = 0;
+    dmaDesc[1].eof = 1;
+
+    //Reset DMA
+    SET_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
+    CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(0), I2S_IN_RST | I2S_OUT_RST | I2S_AHBM_RST | I2S_AHBM_FIFO_RST);
+
+    //Reset I2S FIFO
+    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_RX_RESET | I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_FIFO_RESET);
+
+    //Set desc addr
+    CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_ADDR);
+    SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), ((uint32_t)(&dmaDesc[0]))&I2S_OUTLINK_ADDR);
+    CLEAR_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_ADDR);
+    SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), ((uint32_t)(&dmaDesc[1]))&I2S_INLINK_ADDR);
+
+    SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(0), I2S_DSCR_EN); //Enable DMA mode
+
+    WRITE_PERI_REG(I2S_RXEOF_NUM_REG(0), len);
+
+    //Enable and configure DMA
+    WRITE_PERI_REG(I2S_LC_CONF_REG(0), I2S_OUT_DATA_BURST_EN  |
+                   I2S_OUT_EOF_MODE | I2S_OUTDSCR_BURST_EN | I2S_OUT_DATA_BURST_EN |
+                   I2S_INDSCR_BURST_EN | I2S_MEM_TRANS_EN);
+
+    //Start transmission
+    SET_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START);
+    SET_PERI_REG_MASK(I2S_IN_LINK_REG(0), I2S_INLINK_START);
+
+    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
+    //Clear int flags
+    WRITE_PERI_REG(I2S_INT_CLR_REG(0), 0xFFFFFFFF);
+//--
+    //No need to finish if no DMA transfer going on
+    if (!(READ_PERI_REG(I2S_FIFO_CONF_REG(0))&I2S_DSCR_EN)) {
+        return;
+    }
+
+    //Wait till fifo done
+    while (!(READ_PERI_REG(I2S_INT_RAW_REG(0))&I2S_TX_REMPTY_INT_RAW)) ;
+    //Wait for last bytes to leave i2s xmit thing
+    //ToDo: poll bit in next hw
+    for (i = 0; i < (1 << 8); i++);
+    while (!(READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_IDLE));
+
+    //Reset I2S for next transfer
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_START | I2S_RX_START);
+    CLEAR_PERI_REG_MASK(I2S_OUT_LINK_REG(0), I2S_OUTLINK_START | I2S_INLINK_START);
+
+    SET_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
+    CLEAR_PERI_REG_MASK(I2S_CONF_REG(0), I2S_TX_RESET | I2S_TX_FIFO_RESET | I2S_RX_RESET | I2S_RX_FIFO_RESET);
+
+//  for (i=0; i<(1<<8); i++);
+    while ((READ_PERI_REG(I2S_STATE_REG(0))&I2S_TX_FIFO_RESET_BACK));
+
+}
+
+
+int mymemcmp(char *a, char *b, int len)
+{
+    int x;
+    for (x = 0; x < len; x++) {
+        if (a[x] != b[x]) {
+            printf("Not equal at byte %d. a=%x, b=%x\n", x, (int)a[x], (int)b[x]);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+
+
+TEST_CASE("Unaligned DMA test (needs I2S)", "[hw]")
+{
+    int x;
+    char src[2049], dest[2049];
+    for (x = 0; x < sizeof(src); x++) {
+        src[x] = x & 0xff;
+    }
+
+    printf("Aligned dma\n");
+    memset(dest, 0, 2049);
+    dmaMemcpy(src, dest, 2048 + 1);
+    TEST_ASSERT(mymemcmp(src, dest, 2048) == 0);
+    printf("Src unaligned\n");
+    dmaMemcpy(src + 1, dest, 2048 + 1);
+    TEST_ASSERT(mymemcmp(src + 1, dest, 2048) == 0);
+    printf("Dst unaligned\n");
+    dmaMemcpy(src, dest + 1, 2048 + 2);
+    TEST_ASSERT(mymemcmp(src, dest + 1, 2048) == 0);
+}
+

+ 5 - 0
components/freertos/test/component.mk

@@ -0,0 +1,5 @@
+#
+#Component Makefile
+#
+
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

+ 229 - 0
components/freertos/test/test_freertos.c

@@ -0,0 +1,229 @@
+/*
+ Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc.
+*/
+
+#include <esp_types.h>
+#include <stdio.h>
+#include "rom/ets_sys.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "unity.h"
+#include "soc/uart_reg.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+
+
+void ets_isr_unmask(uint32_t unmask);
+
+static xQueueHandle myQueue;
+static xQueueHandle uartRxQueue;
+
+int ctr;
+
+#if 1
+//Idle-loop for delay. Tests involuntary yielding
+static void cvTaskDelay(int dummy)
+{
+    volatile int i;
+    for (i = 0; i < (1 << 17); i++);
+}
+#else
+//Delay task execution using FreeRTOS methods. Tests voluntary yielding.
+#define cvTaskDelay(x) vTaskDelay(x)
+#endif
+
+#if 0
+static void dosegfault3(int i)
+{
+    volatile char *p = (volatile char *)0;
+    *p = i;
+}
+
+static void dosegfault2(int i)
+{
+    if (i > 3) {
+        dosegfault3(i);
+    }
+}
+
+static void dosegfault(int i)
+{
+    if (i < 5) {
+        dosegfault(i + 1);
+    }
+    dosegfault2(i);
+}
+#endif
+
+static void queueSender(void *pvParameters)
+{
+    int myCtr = xPortGetCoreID() * 100000;
+    while (1) {
+        printf("Core %d: Send to queue: %d\n", xPortGetCoreID(), myCtr);
+        xQueueSend(myQueue, (void *)(&myCtr), portMAX_DELAY);
+        printf("Send to queue done.\n");
+        cvTaskDelay(100);
+        myCtr++;
+    }
+}
+
+static void queueReceiver(void *pvParameters)
+{
+    int theCtr;
+    while (1) {
+        xQueueReceive(myQueue, &theCtr, portMAX_DELAY);
+        printf("Core %d: Receive from queue: %d\n", xPortGetCoreID(), theCtr);
+    }
+}
+
+
+static void tskone(void *pvParameters)
+{
+//  char *p=(char *)0;
+    while (1) {
+        ctr++;
+//      if (ctr>60) dosegfault(3);
+        printf("Task1, core %d, ctr=%d\n", xPortGetCoreID(), ctr);
+        cvTaskDelay(500);
+    }
+}
+
+static void tsktwo(void *pvParameters)
+{
+    while (1) {
+        ctr++;
+        printf("Task2, core %d, ctr=%d\n", xPortGetCoreID(), ctr);
+        cvTaskDelay(500);
+    }
+}
+
+static void tskthree(void *pvParameters)
+{
+    while (1) {
+        ctr++;
+        printf("Task3, core %d, ctr=%d\n", xPortGetCoreID(), ctr);
+        cvTaskDelay(500);
+    }
+}
+
+static void tskfour(void *pvParameters)
+{
+    while (1) {
+        ctr++;
+        printf("Task4, core %d, ctr=%d\n", xPortGetCoreID(), ctr);
+        cvTaskDelay(500);
+    }
+}
+
+static void tskfive(void *pvParameters)
+{
+    while (1) {
+        ctr++;
+        printf("Task5, core %d, ctr=%d\n", xPortGetCoreID(), ctr);
+        cvTaskDelay(500);
+    }
+}
+
+static void tskyield(void *pvParameters)
+{
+    while (1) {
+        portYIELD();
+    }
+}
+
+static void  tskUartRecv(void *pvParameters)
+{
+    char c;
+    while (1) {
+        xQueueReceive(uartRxQueue, &c, portMAX_DELAY);
+        printf("Uart received %c!\n", c);
+    }
+}
+
+
+static void uartIsrHdl(void *arg)
+{
+    char c;
+    BaseType_t xHigherPriorityTaskWoken;
+    SET_PERI_REG_MASK(UART_INT_CLR_REG(0), UART_RXFIFO_FULL_INT_CLR);
+    while (READ_PERI_REG(UART_STATUS_REG(0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
+        c = READ_PERI_REG(UART_FIFO_REG(0));
+        xQueueSendFromISR(uartRxQueue, &c, &xHigherPriorityTaskWoken);
+        printf("ISR: %c\n", c);
+    }
+    if (xHigherPriorityTaskWoken) {
+        portYIELD_FROM_ISR();
+    }
+}
+
+static void uartRxInit(xQueueHandle q)
+{
+    uint32_t reg_val;
+
+    PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);
+
+
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
+
+//  reg_val = READ_PERI_REG(UART_CONF1(0));
+    reg_val = (1 << UART_RXFIFO_FULL_THRHD_S);
+    WRITE_PERI_REG(UART_CONF1_REG(0), reg_val);
+    CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_TXFIFO_EMPTY_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
+    SET_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_RXFIFO_FULL_INT_ENA);
+
+    printf("Enabling int %d\n", ETS_UART0_INUM);
+    REG_SET_FIELD(DPORT_PRO_UART_INTR_MAP_REG, DPORT_PRO_UART_INTR_MAP, ETS_UART0_INUM);
+    REG_SET_FIELD(DPORT_PRO_UART1_INTR_MAP_REG, DPORT_PRO_UART1_INTR_MAP, ETS_UART0_INUM);
+
+    xt_set_interrupt_handler(ETS_UART0_INUM, uartIsrHdl, NULL);
+    xt_ints_on(1 << ETS_UART0_INUM);
+
+}
+
+// TODO: split this thing into separate orthogonal tests
+TEST_CASE("Bunch of FreeRTOS tests", "[freertos]")
+{
+    char *tst;
+    TaskHandle_t th[12];
+    int i;
+    printf("%s\n", __FUNCTION__);
+    tst = pvPortMalloc(16);
+    printf("Test malloc returns addr %p\n", tst);
+    printf("Free heap: %u\n", xPortGetFreeHeapSize());
+    myQueue = xQueueCreate(10, sizeof(int));
+    uartRxQueue = xQueueCreate(256, sizeof(char));
+    printf("Free heap: %u\n", xPortGetFreeHeapSize());
+
+    printf("Creating tasks\n");
+    xTaskCreatePinnedToCore(tskyield  , "tskyield1"  , 2048, NULL, 3, &th[0], 0);
+    xTaskCreatePinnedToCore(tskyield  , "tskyield2"  , 2048, NULL, 3, &th[1], 1);
+
+    xTaskCreatePinnedToCore(tskone  , "tskone"  , 2048, NULL, 3, &th[2], 0);
+    xTaskCreatePinnedToCore(tsktwo  , "tsktwo"  , 2048, NULL, 3, &th[3], 1);
+    xTaskCreatePinnedToCore(tskthree, "tskthree", 2048, NULL, 3, &th[4], 0);
+    xTaskCreatePinnedToCore(tskfour , "tskfour" , 2048, NULL, 3, &th[5], tskNO_AFFINITY);
+    xTaskCreatePinnedToCore(tskfive , "tskfive" , 2048, NULL, 3, &th[6], tskNO_AFFINITY);
+    xTaskCreatePinnedToCore(queueSender , "qsend1" , 2048, NULL, 3, &th[7], 0);
+    xTaskCreatePinnedToCore(queueSender , "qsend2" , 2048, NULL, 3, &th[8], 1);
+    xTaskCreatePinnedToCore(queueReceiver , "qrecv1" , 2048, NULL, 3, &th[9], 1);
+    xTaskCreatePinnedToCore(queueReceiver , "qrecv2" , 2048, NULL, 3, &th[10], 0);
+    xTaskCreatePinnedToCore(tskUartRecv , "tskuart" , 2048, NULL, 4, &th[11], 1);
+    printf("Free heap: %u\n", xPortGetFreeHeapSize());
+    uartRxInit(uartRxQueue);
+
+    // Let stuff run for 20s
+    vTaskDelay(20000 / portTICK_PERIOD_MS);
+
+    //Shut down all the tasks
+    for (i = 0; i < 12; i++) {
+        vTaskDelete(th[i]);
+    }
+    xt_ints_off(1 << ETS_UART0_INUM);
+}
+

+ 105 - 0
components/freertos/test/test_freertos_eventgroups.c

@@ -0,0 +1,105 @@
+#include <stdio.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/event_groups.h"
+#include "unity.h"
+
+#define BIT_CALL (1 << 0)
+#define BIT_RESPONSE(TASK) (1 << (TASK+1))
+#define ALL_RESPONSE_BITS (((1 << NUM_TASKS) - 1) << 1)
+
+static const int NUM_TASKS = 4;
+static const int COUNT = 4000;
+static EventGroupHandle_t eg;
+
+static void task_event_group_call_response(void *param)
+{
+    int task_num = (int)param;
+
+    printf("Started %d\n", task_num);
+
+    for (int i = 0; i < COUNT; i++) {
+        /* Wait until the common "call" bit is set, starts off all tasks
+           (clear on return) */
+        while (!xEventGroupWaitBits(eg, BIT_CALL, true, false, portMAX_DELAY)) {
+        }
+
+        /* Set our individual "response" bit */
+        xEventGroupSetBits(eg, BIT_RESPONSE(task_num));
+    }
+
+    printf("Task %d done\n", task_num);
+
+    /* Delay is due to not-yet-fixed bug with deleting tasks at same time */
+    vTaskDelay(100 / portTICK_RATE_MS);
+    vTaskDelete(NULL);
+}
+
+TEST_CASE("FreeRTOS Event Groups", "[freertos]")
+{
+    eg = xEventGroupCreate();
+
+    /* Note: task_event_group_call_response all have higher priority than us, so will block together.
+
+       This is important because we need to know they'll all have blocked on BIT_CALL each time we
+       signal it, or they get out of sync.
+     */
+    for (int c = 0; c < NUM_TASKS; c++) {
+        xTaskCreatePinnedToCore(task_event_group_call_response, "tsk_call_resp", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS);
+    }
+    /* Scheduler weirdness, if we don't sleep a few ticks here then the tasks on the other CPU aren't running yet... */
+    vTaskDelay(10);
+
+    for (int i = 0; i < COUNT; i++) {
+        if (i % 100 == 0) {
+            //printf("Call %d\n", i);
+        }
+        /* signal all tasks with "CALL" bit... */
+        xEventGroupSetBits(eg, BIT_CALL);
+
+        while (xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, portMAX_DELAY) != ALL_RESPONSE_BITS) {
+        }
+    }
+}
+
+
+#define BIT_DONE(X) (1<<(NUM_TASKS+1+X))
+
+static void task_test_sync(void *param)
+{
+    int task_num = (int)param;
+
+    printf("Started %d\n", task_num);
+
+    for (int i = 0; i < COUNT; i++) {
+        /* set our bit, and wait on all tasks to set their bits */
+        xEventGroupSync(eg, BIT_RESPONSE(task_num), ALL_RESPONSE_BITS, portMAX_DELAY);
+        /* clear our bit */
+        xEventGroupClearBits(eg, BIT_RESPONSE(task_num));
+    }
+    int after_done = xEventGroupSetBits(eg, BIT_DONE(task_num));
+
+    printf("Done %d = %x\n", task_num, after_done);
+
+    /* Delay is due to not-yet-fixed bug with deleting tasks at same time */
+    vTaskDelay(100 / portTICK_RATE_MS);
+    vTaskDelete(NULL);
+}
+
+TEST_CASE("FreeRTOS Event Group Sync", "[freertos]")
+{
+    eg = xEventGroupCreate();
+
+    for (int c = 0; c < NUM_TASKS; c++) {
+        xTaskCreatePinnedToCore(task_test_sync, "task_test_sync", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS);
+    }
+
+    for (int c = 0; c < NUM_TASKS; c++) {
+        printf("Waiting on %d (%x)\n", c, BIT_DONE(c));
+        xEventGroupWaitBits(eg, BIT_DONE(c), false, false, portMAX_DELAY);
+    }
+}
+

+ 22 - 0
components/freertos/test/test_freertos_task_delete.c

@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/event_groups.h"
+#include "unity.h"
+
+static void task_delete_self(void *param)
+{
+    printf("Task %p running on core %d. Deleting shortly...\n", xTaskGetCurrentTaskHandle(), xPortGetCoreID());
+    vTaskDelete(NULL);
+}
+
+TEST_CASE("FreeRTOS Delete Tasks", "[freertos]")
+{
+    xTaskCreatePinnedToCore(task_delete_self, "tsk_self_a", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0);
+    xTaskCreatePinnedToCore(task_delete_self, "tsk_self_a", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0);
+    vTaskDelay(200 / portTICK_PERIOD_MS);
+    printf("Done?\n");
+}

+ 60 - 0
components/freertos/test/test_newlib_reent.c

@@ -0,0 +1,60 @@
+/*
+ Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc.
+*/
+
+#include <esp_types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "rom/ets_sys.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "unity.h"
+#include "soc/uart_reg.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+
+
+volatile static int done;
+volatile static int error;
+
+static void tskTestRand(void *pvParameters)
+{
+    int l;
+    srand(0x1234);
+    vTaskDelay((int)pvParameters / portTICK_PERIOD_MS);
+    l = rand();
+    printf("Rand1: %d\n", l);
+    if (l != 869320854) {
+        error++;
+    }
+    vTaskDelay((int)pvParameters / portTICK_PERIOD_MS);
+    l = rand();
+    printf("Rand2: %d\n", l);
+    if (l != 1148737841) {
+        error++;
+    }
+    done++;
+    vTaskDelete(NULL);
+}
+
+
+
+// TODO: split this thing into separate orthogonal tests
+TEST_CASE("Test for per-task non-reentrant tasks", "[freertos]")
+{
+    done = 0;
+    error = 0;
+    xTaskCreatePinnedToCore(tskTestRand, "tsk1", 2048, (void *)100, 3, NULL, 0);
+    xTaskCreatePinnedToCore(tskTestRand, "tsk2", 2048, (void *)200, 3, NULL, 0);
+    xTaskCreatePinnedToCore(tskTestRand, "tsk3", 2048, (void *)300, 3, NULL, 1);
+    xTaskCreatePinnedToCore(tskTestRand, "tsk4", 2048, (void *)400, 3, NULL, 0);
+    while (done != 4) {
+        vTaskDelay(1000 / portTICK_PERIOD_MS);
+    }
+    TEST_ASSERT(error == 0);
+}
+

+ 26 - 0
components/freertos/test/test_panic.c

@@ -0,0 +1,26 @@
+/*
+ Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc.
+*/
+
+#include <esp_types.h>
+#include <stdio.h>
+#include "rom/ets_sys.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "unity.h"
+#include "soc/uart_reg.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+
+
+TEST_CASE("Panic handler", "[freertos]")
+{
+    volatile int *i;
+    i = (volatile int *)0x0;
+    *i = 1;
+}
+

+ 197 - 0
components/freertos/test/test_ringbuf.c

@@ -0,0 +1,197 @@
+/*
+ Test for multicore FreeRTOS ringbuffer.
+*/
+
+#include <esp_types.h>
+#include <stdio.h>
+#include "rom/ets_sys.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/ringbuf.h"
+#include "freertos/xtensa_api.h"
+#include "unity.h"
+#include "soc/uart_reg.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+
+#include <string.h>
+#include <stdio.h>
+
+void ets_isr_unmask(uint32_t unmask);
+
+static RingbufHandle_t rb;
+typedef enum {
+    TST_MOSTLYFILLED,
+    TST_MOSTLYEMPTY,
+    TST_INTTOTASK,
+    TST_TASKTOINT,
+} testtype_t;
+
+static volatile testtype_t testtype;
+
+static void task1(void *arg)
+{
+    testtype_t oldtest;
+    char buf[100];
+    int i = 0;
+    int x, r;
+    while (1) {
+        oldtest = testtype;
+        if (testtype == TST_MOSTLYFILLED || testtype == TST_MOSTLYEMPTY) {
+            for (x = 0; x < 10; x++) {
+                sprintf(buf, "This is test %d item %d.", (int)testtype,  i++);
+                ets_printf("TSK w");
+                xRingbufferPrintInfo(rb);
+                r = xRingbufferSend(rb, buf, strlen(buf) + 1, 2000 / portTICK_PERIOD_MS);
+                if (!r) {
+                    printf("Test %d: Timeout on send!\n", (int)testtype);
+                }
+                if (testtype == TST_MOSTLYEMPTY) {
+                    vTaskDelay(1000 / portTICK_PERIOD_MS);
+                }
+            }
+            //Send NULL event to stop other side.
+            r = xRingbufferSend(rb, NULL, 0, 10000 / portTICK_PERIOD_MS);
+        }
+        while (oldtest == testtype) {
+            vTaskDelay(1000 / portTICK_PERIOD_MS);
+        }
+    }
+}
+
+static void task2(void *arg)
+{
+    testtype_t oldtest;
+    char *buf;
+    size_t len;
+    while (1) {
+        oldtest = testtype;
+        if (testtype == TST_MOSTLYFILLED || testtype == TST_MOSTLYEMPTY) {
+            while (1) {
+                ets_printf("TSK r");
+                xRingbufferPrintInfo(rb);
+                buf = xRingbufferReceive(rb, &len, 2000 / portTICK_PERIOD_MS);
+                if (buf == NULL) {
+                    printf("Test %d: Timeout on recv!\n", (int)testtype);
+                } else if (len == 0) {
+                    printf("End packet received.\n");
+                    vRingbufferReturnItem(rb, buf);
+                    break;
+                } else {
+                    printf("Received: %s (%d bytes, %p)\n", buf, len, buf);
+                    vRingbufferReturnItem(rb, buf);
+                }
+                if (testtype == TST_MOSTLYFILLED) {
+                    vTaskDelay(1000 / portTICK_PERIOD_MS);
+                }
+            }
+        }
+        while (oldtest == testtype) {
+            vTaskDelay(1000 / portTICK_PERIOD_MS);
+        }
+    }
+}
+
+
+
+static void uartIsrHdl(void *arg)
+{
+    char c;
+    char buf[50];
+    char *item;
+    int r;
+    size_t len;
+    BaseType_t xHigherPriorityTaskWoken;
+    SET_PERI_REG_MASK(UART_INT_CLR_REG(0), UART_RXFIFO_FULL_INT_CLR);
+    while (READ_PERI_REG(UART_STATUS_REG(0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
+        c = READ_PERI_REG(UART_FIFO_REG(0));
+        if (c == 'r') {
+            ets_printf("ISR r");
+            xRingbufferPrintInfo(rb);
+            item = xRingbufferReceiveFromISR(rb, &len);
+            if (item == NULL) {
+                ets_printf("ISR recv fail!\n");
+            } else if (len == 0) {
+                ets_printf("ISR recv NULL!\n");
+                vRingbufferReturnItemFromISR(rb, item, &xHigherPriorityTaskWoken);
+            } else {
+                ets_printf("ISR recv '%s' (%d bytes, %p)\n", buf, len, buf);
+                vRingbufferReturnItemFromISR(rb, item, &xHigherPriorityTaskWoken);
+            }
+        } else {
+            sprintf(buf, "UART: %c", c);
+            ets_printf("ISR w");
+            xRingbufferPrintInfo(rb);
+            r = xRingbufferSendFromISR(rb, buf, strlen(buf) + 1, &xHigherPriorityTaskWoken);
+            if (!r) {
+                ets_printf("ISR send fail\n");
+            }
+        }
+    }
+    if (xHigherPriorityTaskWoken) {
+        portYIELD_FROM_ISR();
+    }
+}
+
+static void uartRxInit()
+{
+    uint32_t reg_val;
+    PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
+    PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);
+
+//  reg_val = READ_PERI_REG(UART_CONF1(0));
+    reg_val = (1 << UART_RXFIFO_FULL_THRHD_S);
+    WRITE_PERI_REG(UART_CONF1_REG(0), reg_val);
+    CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_TXFIFO_EMPTY_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
+    SET_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_RXFIFO_FULL_INT_ENA);
+
+    printf("Enabling int %d\n", ETS_UART0_INUM);
+    REG_SET_FIELD(DPORT_PRO_UART_INTR_MAP_REG, DPORT_PRO_UART_INTR_MAP, ETS_UART0_INUM);
+    REG_SET_FIELD(DPORT_PRO_UART1_INTR_MAP_REG, DPORT_PRO_UART1_INTR_MAP, ETS_UART0_INUM);
+
+    xt_set_interrupt_handler(ETS_UART0_INUM, uartIsrHdl, NULL);
+    xt_ints_on(1 << ETS_UART0_INUM);
+
+}
+
+static void testRingbuffer(int type)
+{
+    TaskHandle_t th[2];
+    int i;
+    rb = xRingbufferCreate(32 * 3, type);
+
+    testtype = TST_MOSTLYFILLED;
+
+    xTaskCreatePinnedToCore(task1  , "tskone"  , 2048, NULL, 3, &th[0], 0);
+    xTaskCreatePinnedToCore(task2  , "tsktwo"  , 2048, NULL, 3, &th[1], 0);
+    uartRxInit();
+
+    printf("Press 'r' to read an event in isr, any other key to write one.\n");
+    printf("Test: mostlyfilled; putting 10 items in ringbuff ASAP, reading 1 a second\n");
+    vTaskDelay(15000 / portTICK_PERIOD_MS);
+    printf("Test: mostlyempty; putting 10 items in ringbuff @ 1/sec, reading as fast as possible\n");
+    testtype = TST_MOSTLYEMPTY;
+    vTaskDelay(15000 / portTICK_PERIOD_MS);
+
+    //Shut down all the tasks
+    for (i = 0; i < 2; i++) {
+        vTaskDelete(th[i]);
+    }
+    xt_ints_off(1 << ETS_UART0_INUM);
+}
+
+// TODO: split this thing into separate orthogonal tests
+TEST_CASE("FreeRTOS ringbuffer test, no splitting items", "[freertos]")
+{
+    testRingbuffer(0);
+}
+
+TEST_CASE("FreeRTOS ringbuffer test, w/ splitting items", "[freertos]")
+{
+    testRingbuffer(1);
+}
+

+ 58 - 0
components/freertos/test/test_tls_deletecb.c

@@ -0,0 +1,58 @@
+#include <esp_types.h>
+#include <stdio.h>
+#include "rom/ets_sys.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "unity.h"
+#include "soc/uart_reg.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+
+
+
+static void tskdelcb(int no, void *arg)
+{
+    printf("Delete callback: %d = %p!\n", no,  arg);
+}
+
+
+static void tska(void *pvParameters)
+{
+    vTaskSetThreadLocalStoragePointerAndDelCallback(xTaskGetCurrentTaskHandle(), 0, (void *)0xAAAAAAAA, tskdelcb);
+    while (1) {
+        vTaskDelay(10000000 / portTICK_PERIOD_MS);
+    }
+}
+
+static void tskb(void *pvParameters)
+{
+    vTaskSetThreadLocalStoragePointerAndDelCallback(xTaskGetCurrentTaskHandle(), 0, (void *)0xBBBBBBBB, tskdelcb);
+    vTaskDelay(2000 / portTICK_PERIOD_MS);
+    TaskHandle_t a = (TaskHandle_t)pvParameters;
+    printf("Killing task A\n");
+    vTaskDelete(a);
+    while (1) {
+        vTaskDelay(10000000 / portTICK_PERIOD_MS);
+    }
+}
+
+
+// TODO: split this thing into separate orthogonal tests
+TEST_CASE("Freertos TLS delete cb", "[freertos]")
+{
+    TaskHandle_t a, b;
+
+    xTaskCreatePinnedToCore(tska  , "tska"  , 2048, NULL, 3, &a, 0);
+    xTaskCreatePinnedToCore(tskb  , "tska"  , 2048, a, 3, &b, 0);
+
+    // Let stuff run for 20s
+    vTaskDelay(5000 / portTICK_PERIOD_MS);
+    printf("Killing task B\n");
+    //Shut down b
+    vTaskDelete(b);
+}
+

+ 5 - 0
components/mbedtls/test/component.mk

@@ -0,0 +1,5 @@
+#
+#Component Makefile
+#
+
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

+ 134 - 0
components/mbedtls/test/test_mbedtls.c

@@ -0,0 +1,134 @@
+/* mbedTLS internal tests wrapped into Unity
+
+   Focus on testing functionality where we use ESP32 hardware
+   accelerated crypto features.
+
+   See also test_hwcrypto.c
+*/
+#include <string.h>
+#include <stdio.h>
+#include "mbedtls/sha1.h"
+#include "mbedtls/sha256.h"
+#include "mbedtls/sha512.h"
+#include "mbedtls/aes.h"
+#include "mbedtls/bignum.h"
+#include "unity.h"
+
+static int mbedtls_alt_sha256_self_test( int verbose );
+
+TEST_CASE("mbedtls SHA self-tests", "[mbedtls]")
+{
+    TEST_ASSERT_FALSE_MESSAGE(mbedtls_sha1_self_test(1), "SHA1 self-tests should pass.");
+    TEST_ASSERT_FALSE_MESSAGE(mbedtls_alt_sha256_self_test(1), "SHA256 self-tests should pass.");
+    TEST_ASSERT_FALSE_MESSAGE(mbedtls_sha512_self_test(1), "SHA512 self-tests should pass.");
+}
+
+TEST_CASE("mbedtls AES self-tests", "[aes]")
+{
+    TEST_ASSERT_FALSE_MESSAGE(mbedtls_aes_self_test(1), "AES self-tests should pass.");
+}
+
+TEST_CASE("mbedtls MPI self-tests", "[bignum]")
+{
+    TEST_ASSERT_FALSE_MESSAGE(mbedtls_mpi_self_test(1), "MPI self-tests should pass.");
+}
+
+
+/* Following code is a copy of the mbedtls_sha256 test vectors,
+   with the SHA-224 support removed as we don't currently support this hash.
+*/
+
+/*
+ * FIPS-180-2 test vectors
+ */
+static const unsigned char sha256_test_buf[3][57] = {
+    { "abc" },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+    { "" }
+};
+
+static const int sha256_test_buflen[3] = {
+    3, 56, 1000
+};
+
+static const unsigned char sha256_test_sum[6][32] = {
+    /*
+     * SHA-256 test vectors
+     */
+    {
+        0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+        0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+        0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+        0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD
+    },
+    {
+        0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
+        0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
+        0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
+        0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1
+    },
+    {
+        0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
+        0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
+        0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
+        0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0
+    }
+};
+
+/*
+ * Checkup routine
+ */
+static int mbedtls_alt_sha256_self_test( int verbose )
+{
+    int j, n, buflen, ret = 0;
+    unsigned char buf[1024];
+    unsigned char sha256sum[32];
+    mbedtls_sha256_context ctx;
+
+    for ( j = 0; j < 3; j++ ) {
+        mbedtls_sha256_init( &ctx );
+
+        if ( verbose != 0 ) {
+            printf( "  SHA-%d test #%d: ", 256, j + 1 );
+        }
+
+        mbedtls_sha256_starts( &ctx, 0 );
+
+        if ( j == 2 ) {
+            memset( buf, 'a', buflen = 1000 );
+
+            for ( n = 0; n < 1000; n++ ) {
+                mbedtls_sha256_update( &ctx, buf, buflen );
+            }
+        } else
+            mbedtls_sha256_update( &ctx, sha256_test_buf[j],
+                                   sha256_test_buflen[j] );
+
+        mbedtls_sha256_finish( &ctx, sha256sum );
+
+        if ( memcmp( sha256sum, sha256_test_sum[j], 32 ) != 0 ) {
+            if ( verbose != 0 ) {
+                printf( "failed\n" );
+            }
+
+            mbedtls_sha256_free( &ctx );
+
+            ret = 1;
+            goto exit;
+        }
+
+        if ( verbose != 0 ) {
+            printf( "passed\n" );
+        }
+
+        mbedtls_sha256_free( &ctx );
+    }
+
+    if ( verbose != 0 ) {
+        printf( "\n" );
+    }
+
+exit:
+
+    return ( ret );
+}

+ 5 - 0
components/newlib/test/component.mk

@@ -0,0 +1,5 @@
+#
+#Component Makefile
+#
+
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

+ 102 - 0
components/newlib/test/test_newlib.c

@@ -0,0 +1,102 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include "unity.h"
+
+
+TEST_CASE("test ctype functions", "[newlib]")
+{
+    TEST_ASSERT_TRUE( isalnum('a') && isalnum('A') && isalnum('z') && isalnum('Z') && isalnum('0') && isalnum('9') );
+    TEST_ASSERT_FALSE( isalnum('(') || isalnum('-') || isalnum(' ') || isalnum('\x81') || isalnum('.') || isalnum('\\') );
+    TEST_ASSERT_TRUE( isalpha('a') && isalpha('A') && isalpha('z') && isalpha('Z') );
+    TEST_ASSERT_FALSE( isalpha('0') || isalpha('9') || isalpha(')') || isalpha('\t') || isalpha(' ') || isalpha('\x81') );
+    TEST_ASSERT_TRUE( isspace(' ') && isspace('\t') && isspace('\n') && isspace('\r') );
+    TEST_ASSERT_FALSE( isspace('0') || isspace('9') || isspace(')') || isspace('A') || isspace('*') || isspace('\x81') || isspace('a'));
+}
+
+TEST_CASE("test atoX functions", "[newlib]")
+{
+    TEST_ASSERT_EQUAL_INT(-2147483648, atoi("-2147483648"));
+    TEST_ASSERT_EQUAL_INT(2147483647, atoi("2147483647"));
+    TEST_ASSERT_EQUAL_INT(42, atoi("000000042"));
+    TEST_ASSERT_EQUAL_INT(0, strtol("foo", NULL, 10));
+}
+
+TEST_CASE("test sprintf function", "[newlib]")
+{
+    char *res = NULL;
+    asprintf(&res, "%d %011i %lu %p %x %c %.4f\n", 42, 2147483647, 2147483648UL, (void *) 0x40010000, 0x40020000, 'Q', 1.0f / 137.0f);
+    TEST_ASSERT_NOT_NULL(res);
+    TEST_ASSERT_EQUAL_STRING(res, "42 02147483647 2147483648 0x40010000 40020000 Q 0.0073\n");
+    free(res);
+}
+
+TEST_CASE("test sscanf function", "[newlib]")
+{
+    const char *src = "42 02147483647 2147483648 0x40010000 40020000 Q 0.0073\n";
+    int fourty_two;
+    int int_max;
+    unsigned long int_max_plus_one;
+    void *iram_ptr;
+    int irom_ptr;
+    char department;
+    float inv_fine_structure_constant;
+    int res = sscanf(src, "%d %d %lu %p %x %c %f", &fourty_two, &int_max, &int_max_plus_one, &iram_ptr, &irom_ptr, &department, &inv_fine_structure_constant);
+    TEST_ASSERT_EQUAL(7, res);
+    TEST_ASSERT_EQUAL(42, fourty_two);
+    TEST_ASSERT_EQUAL(2147483647, int_max);
+    TEST_ASSERT_EQUAL_UINT32(2147483648UL, int_max_plus_one);
+    TEST_ASSERT_EQUAL(0x40010000, iram_ptr);
+    TEST_ASSERT_EQUAL(0x40020000, irom_ptr);
+    TEST_ASSERT_EQUAL('Q', department);
+    TEST_ASSERT_TRUE(1.0f / inv_fine_structure_constant > 136 && 1.0f / inv_fine_structure_constant < 138);
+}
+
+TEST_CASE("test time functions", "[newlib]")
+{
+    time_t now = 1464248488;
+    setenv("TZ", "UTC-8", 1);
+    struct tm *tm_utc = gmtime(&now);
+    TEST_ASSERT_EQUAL( 28, tm_utc->tm_sec);
+    TEST_ASSERT_EQUAL( 41, tm_utc->tm_min);
+    TEST_ASSERT_EQUAL(  7, tm_utc->tm_hour);
+    TEST_ASSERT_EQUAL( 26, tm_utc->tm_mday);
+    TEST_ASSERT_EQUAL(  4, tm_utc->tm_mon);
+    TEST_ASSERT_EQUAL(116, tm_utc->tm_year);
+    TEST_ASSERT_EQUAL(  4, tm_utc->tm_wday);
+    TEST_ASSERT_EQUAL(146, tm_utc->tm_yday);
+
+    struct tm *tm_local = localtime(&now);
+    TEST_ASSERT_EQUAL( 28, tm_local->tm_sec);
+    TEST_ASSERT_EQUAL( 41, tm_local->tm_min);
+    TEST_ASSERT_EQUAL( 15, tm_local->tm_hour);
+    TEST_ASSERT_EQUAL( 26, tm_local->tm_mday);
+    TEST_ASSERT_EQUAL(  4, tm_local->tm_mon);
+    TEST_ASSERT_EQUAL(116, tm_local->tm_year);
+    TEST_ASSERT_EQUAL(  4, tm_local->tm_wday);
+    TEST_ASSERT_EQUAL(146, tm_local->tm_yday);
+
+}
+
+
+static int checkFnRom(void *fn, char *name)
+{
+    int fnaddr = (int)fn;
+    printf("%s: 0X%x\n", name, fnaddr);
+    if ((fnaddr >= 0x40000000) && (fnaddr < 0x40070000)) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+
+TEST_CASE("check if ROM is used for functions", "[newlib]")
+{
+    TEST_ASSERT(checkFnRom(printf, "printf"));
+    TEST_ASSERT(checkFnRom(sscanf, "sscanf"));
+    TEST_ASSERT(checkFnRom(atoi, "atoi"));
+    TEST_ASSERT(checkFnRom(strtol, "strtol"));
+}

+ 5 - 0
components/nvs_flash/test/component.mk

@@ -0,0 +1,5 @@
+#
+#Component Makefile
+#
+
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

+ 54 - 0
components/nvs_flash/test/test_nvs.c

@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include "unity.h"
+#include "nvs.h"
+#include "nvs_flash.h"
+#include "esp_spi_flash.h"
+#include <string.h>
+
+#define NVS_FLASH_SECTOR 6
+#define NVS_FLASH_SECTOR_COUNT_MIN 3
+#define NVS_FLASH_SECTOR_COUNT_MAX 10
+
+TEST_CASE("various nvs tests", "[nvs]")
+{
+    nvs_handle handle_1;
+    TEST_ESP_ERR(nvs_open("namespace1", NVS_READWRITE, &handle_1), ESP_ERR_NVS_NOT_INITIALIZED);
+    for (uint16_t i = NVS_FLASH_SECTOR; i < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) {
+        spi_flash_erase_sector(i);
+    }
+    TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN));
+
+    TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
+
+    // TEST_ESP_ERR(nvs_set_i32(handle_1, "foo", 0x12345678), ESP_ERR_NVS_READ_ONLY);
+    // nvs_close(handle_1);
+
+    TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle_1));
+    TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x12345678));
+    TEST_ESP_OK(nvs_set_i32(handle_1, "foo", 0x23456789));
+
+    nvs_handle handle_2;
+    TEST_ESP_OK(nvs_open("namespace2", NVS_READWRITE, &handle_2));
+    TEST_ESP_OK(nvs_set_i32(handle_2, "foo", 0x3456789a));
+    const char *str = "value 0123456789abcdef0123456789abcdef";
+    TEST_ESP_OK(nvs_set_str(handle_2, "key", str));
+
+    int32_t v1;
+    TEST_ESP_OK(nvs_get_i32(handle_1, "foo", &v1));
+    TEST_ASSERT_EQUAL_INT32(0x23456789, v1);
+
+    int32_t v2;
+    TEST_ESP_OK(nvs_get_i32(handle_2, "foo", &v2));
+    TEST_ASSERT_EQUAL_INT32(0x3456789a, v2);
+
+    char buf[strlen(str) + 1];
+    size_t buf_len = sizeof(buf);
+
+    TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len));
+
+    TEST_ASSERT_EQUAL_INT32(0, strcmp(buf, str));
+}

+ 0 - 0
components/nvs_flash/test/Makefile → components/nvs_flash/test_nvs_host/Makefile


+ 0 - 0
components/nvs_flash/test/catch.hpp → components/nvs_flash/test_nvs_host/catch.hpp


+ 0 - 0
components/nvs_flash/test/crc.cpp → components/nvs_flash/test_nvs_host/crc.cpp


+ 0 - 0
components/nvs_flash/test/crc.h → components/nvs_flash/test_nvs_host/crc.h


+ 0 - 0
components/nvs_flash/test/main.cpp → components/nvs_flash/test_nvs_host/main.cpp


+ 0 - 0
components/nvs_flash/test/sdkconfig.h → components/nvs_flash/test_nvs_host/sdkconfig.h


+ 0 - 0
components/nvs_flash/test/spi_flash_emulation.cpp → components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp


+ 0 - 0
components/nvs_flash/test/spi_flash_emulation.h → components/nvs_flash/test_nvs_host/spi_flash_emulation.h


+ 0 - 0
components/nvs_flash/test/test_compressed_enum_table.cpp → components/nvs_flash/test_nvs_host/test_compressed_enum_table.cpp


+ 0 - 0
components/nvs_flash/test/test_intrusive_list.cpp → components/nvs_flash/test_nvs_host/test_intrusive_list.cpp


+ 0 - 0
components/nvs_flash/test/test_nvs.cpp → components/nvs_flash/test_nvs_host/test_nvs.cpp


+ 0 - 0
components/nvs_flash/test/test_spi_flash_emulation.cpp → components/nvs_flash/test_nvs_host/test_spi_flash_emulation.cpp


+ 5 - 0
components/partition_table/test/component.mk

@@ -0,0 +1,5 @@
+#
+#Component Makefile
+#
+
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

+ 95 - 0
components/partition_table/test/test_partition.c

@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "unity.h"
+#include "esp_partition.h"
+
+
+TEST_CASE("Can read partition table", "[partition]")
+{
+
+    const esp_partition_t *p = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL);
+    TEST_ASSERT_NOT_NULL(p);
+    TEST_ASSERT_EQUAL(p->address, 0x10000);
+    TEST_ASSERT_EQUAL(p->subtype, ESP_PARTITION_SUBTYPE_APP_FACTORY);
+
+    esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);
+    TEST_ASSERT_NOT_NULL(it);
+    int count = 0;
+    for (; it != NULL; it = esp_partition_next(it)) {
+        const esp_partition_t *p = esp_partition_get(it);
+        TEST_ASSERT_NOT_NULL(p);
+        ++count;
+    }
+    esp_partition_iterator_release(it);
+    TEST_ASSERT_EQUAL(count, 2);
+
+    printf("%d\n", __builtin_clz(count));
+}
+
+TEST_CASE("Can write, read, mmap partition", "[partition]")
+{
+    const esp_partition_t *p = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);
+    TEST_ASSERT_NOT_NULL(p);
+    const size_t max_size = 2 * SPI_FLASH_SEC_SIZE;
+    uint8_t *data = (uint8_t *) malloc(max_size);
+    TEST_ASSERT_NOT_NULL(data);
+
+    TEST_ASSERT_EQUAL(ESP_OK, esp_partition_erase_range(p, 0, p->size));
+
+    srand(0);
+    size_t block_size;
+    for (size_t offset = 0; offset < p->size; offset += block_size) {
+        block_size = ((rand() + 4) % max_size) & (~0x3);
+        size_t left = p->size - offset;
+        if (block_size > left) {
+            block_size = left;
+        }
+        for (size_t i = 0; i < block_size / 4; ++i) {
+            ((uint32_t *) (data))[i] = rand();
+            if (i == 0 && offset == 0) {
+                printf("write: %08x\n", ((uint32_t *) (data))[i]);
+            }
+        }
+        TEST_ASSERT_EQUAL(ESP_OK, esp_partition_write(p, offset, data, block_size));
+    }
+
+    srand(0);
+    for (size_t offset = 0; offset < p->size; offset += block_size) {
+        block_size = ((rand() + 4) % max_size) & (~0x3);
+        size_t left = p->size - offset;
+        if (block_size > left) {
+            block_size = left;
+        }
+        TEST_ASSERT_EQUAL(ESP_OK, esp_partition_read(p, offset, data, block_size));
+        for (size_t i = 0; i < block_size / 4; ++i) {
+            TEST_ASSERT_EQUAL(rand(), ((uint32_t *) data)[i]);
+        }
+    }
+
+    free(data);
+
+    const uint32_t *mmap_data;
+    spi_flash_mmap_handle_t mmap_handle;
+    size_t begin = 3000;
+    size_t size = 12000;
+    TEST_ASSERT_EQUAL(ESP_OK, esp_partition_mmap(p, begin, size, SPI_FLASH_MMAP_DATA,
+                      (const void **)&mmap_data, &mmap_handle));
+    srand(0);
+    for (size_t offset = 0; offset < p->size; offset += block_size) {
+        block_size = ((rand() + 4) % max_size) & (~0x3);
+        size_t left = p->size - offset;
+        if (block_size > left) {
+            block_size = left;
+        }
+        for (size_t i = 0; i < block_size / 4; ++i) {
+            size_t pos = offset + i * 4;
+            uint32_t expected = rand();
+            if (pos < begin || pos >= (begin + size)) {
+                continue;
+            }
+            TEST_ASSERT_EQUAL(expected, mmap_data[(pos - begin) / 4]);
+        }
+    }
+
+    spi_flash_munmap(mmap_handle);
+}

+ 5 - 0
components/spi_flash/test/component.mk

@@ -0,0 +1,5 @@
+#
+#Component Makefile
+#
+
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

+ 83 - 0
components/spi_flash/test/test_mmap.c

@@ -0,0 +1,83 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <freertos/FreeRTOS.h>
+#include <freertos/task.h>
+#include <freertos/semphr.h>
+
+#include <unity.h>
+#include <esp_spi_flash.h>
+#include <esp_attr.h>
+
+uint32_t buffer[1024];
+
+static const uint32_t start = 0x200000;
+static const uint32_t end = 0x300000;
+
+
+
+TEST_CASE("Prepare data for mmap tests", "[mmap]")
+{
+    srand(0);
+    for (int block = start / 0x10000; block < end / 0x10000; ++block) {
+        printf("Writing block %d\n", block);
+        for (int sector = 0; sector < 16; ++sector) {
+            for (uint32_t word = 0; word < 1024; ++word) {
+                uint32_t val = rand();
+                if (block == start / 0x10000 && sector == 0 && word == 0) {
+                    printf("first word: %08x\n", val);
+                }
+                buffer[word] = val;
+            }
+            uint32_t abs_sector = (block) * 16 + sector;
+            printf("Writing sector %d\n", abs_sector);
+            ESP_ERROR_CHECK( spi_flash_erase_sector((uint16_t) abs_sector) );
+            ESP_ERROR_CHECK( spi_flash_write(abs_sector * SPI_FLASH_SEC_SIZE, (const uint8_t *) buffer, sizeof(buffer)) );
+        }
+    }
+}
+
+TEST_CASE("Can mmap into data address space", "[mmap]")
+{
+
+    printf("Mapping %x (+%x)\n", start, end - start);
+    spi_flash_mmap_handle_t handle1;
+    const void *ptr1;
+    ESP_ERROR_CHECK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) );
+    printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1);
+
+    spi_flash_mmap_dump();
+
+    srand(0);
+    const uint32_t *data = (const uint32_t *) ptr1;
+    for (int block = 0; block < (end - start) / 0x10000; ++block) {
+        for (int sector = 0; sector < 16; ++sector) {
+            for (uint32_t word = 0; word < 1024; ++word) {
+                TEST_ASSERT_EQUAL_UINT32(rand(), data[(block * 16 + sector) * 1024 + word]);
+            }
+        }
+    }
+    printf("Mapping %x (+%x)\n", start - 0x10000, 0x20000);
+    spi_flash_mmap_handle_t handle2;
+    const void *ptr2;
+    ESP_ERROR_CHECK( spi_flash_mmap(start - 0x10000, 0x20000, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) );
+    printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2);
+    spi_flash_mmap_dump();
+
+    printf("Mapping %x (+%x)\n", start, 0x10000);
+    spi_flash_mmap_handle_t handle3;
+    const void *ptr3;
+    ESP_ERROR_CHECK( spi_flash_mmap(start, 0x10000, SPI_FLASH_MMAP_DATA, &ptr3, &handle3) );
+    printf("mmap_res: handle=%d ptr=%p\n", handle3, ptr3);
+    spi_flash_mmap_dump();
+
+    printf("Unmapping handle1\n");
+    spi_flash_munmap(handle1);
+    spi_flash_mmap_dump();
+
+    printf("Unmapping handle2\n");
+    spi_flash_munmap(handle2);
+    spi_flash_mmap_dump();
+
+    printf("Unmapping handle3\n");
+    spi_flash_munmap(handle3);
+}

+ 92 - 0
components/spi_flash/test/test_spi_flash.c

@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <freertos/FreeRTOS.h>
+#include <freertos/task.h>
+#include <freertos/semphr.h>
+
+#include <unity.h>
+#include <esp_spi_flash.h>
+#include <esp_attr.h>
+
+struct flash_test_ctx {
+    uint32_t offset[2];
+    bool fail[2];
+    SemaphoreHandle_t done;
+};
+
+static void flash_test_task(void *arg)
+{
+    const uint32_t coreid = xPortGetCoreID();
+    ets_printf("t%d\n", coreid);
+    struct flash_test_ctx *ctx = (struct flash_test_ctx *) arg;
+    vTaskDelay(100 / portTICK_PERIOD_MS);
+    const uint32_t sector = ctx->offset[coreid];
+    ets_printf("es%d\n", coreid);
+    if (spi_flash_erase_sector(sector) != ESP_OK) {
+        ctx->fail[coreid] = true;
+        ets_printf("Erase failed\r\n");
+        xSemaphoreGive(ctx->done);
+        vTaskDelete(NULL);
+    }
+    ets_printf("ed%d\n", coreid);
+
+    vTaskDelay(0 / portTICK_PERIOD_MS);
+
+    uint32_t val = 0xabcd1234;
+    const uint32_t n = 4096;
+    for (uint32_t offset = 0; offset < n; offset += 4) {
+        if (spi_flash_write(sector * SPI_FLASH_SEC_SIZE + offset, (const uint8_t *) &val, 4) != ESP_OK) {
+            ets_printf("Write failed at offset=%d\r\n", offset);
+            ctx->fail[coreid] = true;
+            break;
+        }
+    }
+    ets_printf("wd%d\n", coreid);
+
+    vTaskDelay(0 / portTICK_PERIOD_MS);
+
+    uint32_t val_read;
+    for (uint32_t offset = 0; offset < n; offset += 4) {
+        if (spi_flash_read(sector * SPI_FLASH_SEC_SIZE + offset, (uint8_t *) &val_read, 4) != ESP_OK) {
+            ets_printf("Read failed at offset=%d\r\n", offset);
+            ctx->fail[coreid] = true;
+            break;
+        }
+        if (val_read != val) {
+            ets_printf("Read invalid value=%08x at offset=%d\r\n", val_read, offset);
+            ctx->fail[coreid] = true;
+            break;
+        }
+    }
+    ets_printf("td%d\n", coreid);
+    xSemaphoreGive(ctx->done);
+    vTaskDelete(NULL);
+}
+
+TEST_CASE("flash write and erase work both on PRO CPU and on APP CPU", "[spi_flash]")
+{
+    TaskHandle_t procpu_task;
+    TaskHandle_t appcpu_task;
+    struct flash_test_ctx ctx;
+
+    ctx.offset[0] = 6;
+    ctx.offset[1] = 7;
+    ctx.fail[0] = 0;
+    ctx.fail[1] = 0;
+    ctx.done = xSemaphoreCreateBinary();
+
+    xTaskCreatePinnedToCore(flash_test_task, "1", 2048, &ctx, 3, &procpu_task, 0);
+    if (portNUM_PROCESSORS == 2) {
+        xTaskCreatePinnedToCore(flash_test_task, "2", 2048, &ctx, 3, &appcpu_task, 1);
+    }
+
+    xSemaphoreTake(ctx.done, portMAX_DELAY);
+    if (portNUM_PROCESSORS == 2) {
+        xSemaphoreTake(ctx.done, portMAX_DELAY);
+    }
+
+    TEST_ASSERT_EQUAL(false, ctx.fail[0]);
+    if (portNUM_PROCESSORS == 2) {
+        TEST_ASSERT_EQUAL(false, ctx.fail[1]);
+    }
+}
+

+ 0 - 3
make/component_wrapper.mk

@@ -32,9 +32,6 @@ include $(IDF_PATH)/make/common.mk
 # Some of the following defaults may be overriden by the component's component.mk makefile,
 # during the next step:
 
-# Name of the component
-COMPONENT_NAME := $(lastword $(subst /, ,$(realpath $(COMPONENT_PATH))))
-
 # Absolute path of the .a file
 COMPONENT_LIBRARY = lib$(COMPONENT_NAME).a
 

+ 11 - 4
make/project.mk

@@ -94,6 +94,12 @@ COMPONENT_PATHS += $(abspath $(SRCDIRS))
 # A component is buildable if it has a component.mk makefile in it
 COMPONENT_PATHS_BUILDABLE := $(foreach cp,$(COMPONENT_PATHS),$(if $(wildcard $(cp)/component.mk),$(cp)))
 
+# If TEST_COMPONENTS is set on the command line, create variables for building unit tests
+ifdef TEST_COMPONENTS
+TEST_COMPONENT_PATHS := $(foreach comp,$(TEST_COMPONENTS),$(IDF_PATH)/components/$(comp)/test)
+TEST_COMPONENT_NAMES := $(foreach comp,$(TEST_COMPONENTS),$(comp)_test)
+endif
+
 # Initialise project-wide variables which can be added to by
 # each component.
 #
@@ -113,7 +119,7 @@ COMPONENT_SUBMODULES :=
 # dependencies.
 #
 # See the component_project_vars.mk target in component_wrapper.mk
-COMPONENT_PROJECT_VARS := $(addsuffix /component_project_vars.mk,$(notdir $(COMPONENT_PATHS_BUILDABLE)))
+COMPONENT_PROJECT_VARS := $(addsuffix /component_project_vars.mk,$(notdir $(COMPONENT_PATHS_BUILDABLE) ) $(TEST_COMPONENT_NAMES))
 COMPONENT_PROJECT_VARS := $(addprefix $(BUILD_DIR_BASE)/,$(COMPONENT_PROJECT_VARS))
 # this line is -include instead of include to prevent a spurious error message on make 3.81
 -include $(COMPONENT_PROJECT_VARS)
@@ -140,7 +146,7 @@ endif
 LDFLAGS ?= -nostdlib \
 	-L$(IDF_PATH)/lib \
 	-L$(IDF_PATH)/ld \
-	$(addprefix -L$(BUILD_DIR_BASE)/,$(COMPONENTS) $(SRCDIRS)) \
+	$(addprefix -L$(BUILD_DIR_BASE)/,$(COMPONENTS) $(TEST_COMPONENT_NAMES) $(SRCDIRS) ) \
 	-u call_user_start_cpu0	\
 	$(EXTRA_LDFLAGS) \
 	-Wl,--gc-sections	\
@@ -257,7 +263,7 @@ endif
 # A "component" library is any library in the LDFLAGS where
 # the name of the library is also a name of the component
 APP_LIBRARIES = $(patsubst -l%,%,$(filter -l%,$(LDFLAGS)))
-COMPONENT_LIBRARIES = $(filter $(notdir $(COMPONENT_PATHS_BUILDABLE)),$(APP_LIBRARIES))
+COMPONENT_LIBRARIES = $(filter $(notdir $(COMPONENT_PATHS_BUILDABLE)) $(TEST_COMPONENT_NAMES),$(APP_LIBRARIES))
 
 # ELF depends on the library archive files for COMPONENT_LIBRARIES
 # the rules to build these are emitted as part of GenerateComponentTarget below
@@ -282,7 +288,7 @@ $(BUILD_DIR_BASE):
 #
 # Is recursively expanded by the GenerateComponentTargets macro
 define ComponentMake
-+$(MAKE) -C $(BUILD_DIR_BASE)/$(2) -f $(IDF_PATH)/make/component_wrapper.mk COMPONENT_MAKEFILE=$(1)/component.mk
++$(MAKE) -C $(BUILD_DIR_BASE)/$(2) -f $(IDF_PATH)/make/component_wrapper.mk COMPONENT_MAKEFILE=$(1)/component.mk COMPONENT_NAME=$(2)
 endef
 
 # Generate top-level component-specific targets for each component
@@ -325,6 +331,7 @@ $(BUILD_DIR_BASE)/$(2)/component_project_vars.mk: $(1)/component.mk $(COMMON_MAK
 endef
 
 $(foreach component,$(COMPONENT_PATHS_BUILDABLE),$(eval $(call GenerateComponentTargets,$(component),$(notdir $(component)))))
+$(foreach component,$(TEST_COMPONENT_PATHS),$(eval $(call GenerateComponentTargets,$(component),$(lastword $(subst /, ,$(dir $(component))))_test)))
 
 app-clean: $(addsuffix -clean,$(notdir $(COMPONENT_PATHS_BUILDABLE)))
 	$(summary) RM $(APP_ELF)

+ 9 - 0
tools/unit-test-app/Makefile

@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := unit-test-app
+
+include $(IDF_PATH)/make/project.mk
+

+ 12 - 0
tools/unit-test-app/README.md

@@ -0,0 +1,12 @@
+# Unit Test App
+
+ESP-IDF unit tests are run using Unit Test App. The app can be built with the unit tests for a specific component. Unit tests are in `test` subdirectories of respective components.
+
+# Building Unit Test App
+
+* Follow the setup instructions in the top-level esp-idf README.
+* Set IDF_PATH environment variable to point to the path to the esp-idf top-level directory.
+* Change into `tools/unit-test-app` directory
+* `make menuconfig` to configure the Unit Test App.
+* `make TEST_COMPONENTS=` with `TEST_COMPONENTS` set to names of the components to be included in the test app.
+* Follow the printed instructions to flash, or run `make flash`.

+ 3 - 0
tools/unit-test-app/components/unity/component.mk

@@ -0,0 +1,3 @@
+#
+# Component Makefile
+#

+ 292 - 0
tools/unit-test-app/components/unity/include/unity.h

@@ -0,0 +1,292 @@
+/* ==========================================
+    Unity Project - A Test Framework for C
+    Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams
+    [Released under MIT License. Please refer to license.txt for details]
+========================================== */
+
+#ifndef UNITY_FRAMEWORK_H
+#define UNITY_FRAMEWORK_H
+#define UNITY
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define UNITY_INCLUDE_CONFIG_H
+#include "unity_internals.h"
+
+void setUp(void);
+void tearDown(void);
+
+/*-------------------------------------------------------
+ * Configuration Options
+ *-------------------------------------------------------
+ * All options described below should be passed as a compiler flag to all files using Unity. If you must add #defines, place them BEFORE the #include above.
+
+ * Integers/longs/pointers
+ *     - Unity attempts to automatically discover your integer sizes
+ *       - define UNITY_EXCLUDE_STDINT_H to stop attempting to look in <stdint.h>
+ *       - define UNITY_EXCLUDE_LIMITS_H to stop attempting to look in <limits.h>
+ *       - define UNITY_EXCLUDE_SIZEOF to stop attempting to use sizeof in macros
+ *     - If you cannot use the automatic methods above, you can force Unity by using these options:
+ *       - define UNITY_SUPPORT_64
+ *       - define UNITY_INT_WIDTH
+ *       - UNITY_LONG_WIDTH
+ *       - UNITY_POINTER_WIDTH
+
+ * Floats
+ *     - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons
+ *     - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT
+ *     - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats
+ *     - define UNITY_FLOAT_VERBOSE to print floating point values in errors (uses sprintf)
+ *     - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons
+ *     - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default)
+ *     - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE
+ *     - define UNITY_DOUBLE_TYPE to specify something other than double
+ *     - define UNITY_DOUBLE_VERBOSE to print floating point values in errors (uses sprintf)
+ *     - define UNITY_VERBOSE_NUMBER_MAX_LENGTH to change maximum length of printed numbers (used by sprintf)
+
+ * Output
+ *     - by default, Unity prints to standard out with putchar.  define UNITY_OUTPUT_CHAR(a) with a different function if desired
+ *     - define UNITY_DIFFERENTIATE_FINAL_FAIL to print FAILED (vs. FAIL) at test end summary - for automated search for failure
+
+ * Optimization
+ *     - by default, line numbers are stored in unsigned shorts.  Define UNITY_LINE_TYPE with a different type if your files are huge
+ *     - by default, test and failure counters are unsigned shorts.  Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests.
+
+ * Test Cases
+ *     - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script
+
+ * Parameterized Tests
+ *     - you'll want to create a define of TEST_CASE(...) which basically evaluates to nothing
+
+ *-------------------------------------------------------
+ * Basic Fail and Ignore
+ *-------------------------------------------------------*/
+
+#define TEST_FAIL_MESSAGE(message)                                                                 UNITY_TEST_FAIL(__LINE__, (message))
+#define TEST_FAIL()                                                                                UNITY_TEST_FAIL(__LINE__, NULL)
+#define TEST_IGNORE_MESSAGE(message)                                                               UNITY_TEST_IGNORE(__LINE__, (message))
+#define TEST_IGNORE()                                                                              UNITY_TEST_IGNORE(__LINE__, NULL)
+#define TEST_ONLY()
+
+/* It is not necessary for you to call PASS. A PASS condition is assumed if nothing fails.
+ * This method allows you to abort a test immediately with a PASS state, ignoring the remainder of the test. */
+#define TEST_PASS()                                                                                longjmp(Unity.AbortFrame, 1)
+
+/*-------------------------------------------------------
+ * Test Asserts (simple)
+ *-------------------------------------------------------*/
+
+/* Boolean */
+#define TEST_ASSERT(condition)                                                                     UNITY_TEST_ASSERT(       (condition), __LINE__, " Expression Evaluated To FALSE")
+#define TEST_ASSERT_TRUE(condition)                                                                UNITY_TEST_ASSERT(       (condition), __LINE__, " Expected TRUE Was FALSE")
+#define TEST_ASSERT_UNLESS(condition)                                                              UNITY_TEST_ASSERT(      !(condition), __LINE__, " Expression Evaluated To TRUE")
+#define TEST_ASSERT_FALSE(condition)                                                               UNITY_TEST_ASSERT(      !(condition), __LINE__, " Expected FALSE Was TRUE")
+#define TEST_ASSERT_NULL(pointer)                                                                  UNITY_TEST_ASSERT_NULL(    (pointer), __LINE__, " Expected NULL")
+#define TEST_ASSERT_NOT_NULL(pointer)                                                              UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL")
+
+/* Integers (of all sizes) */
+#define TEST_ASSERT_EQUAL_INT(expected, actual)                                                    UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_INT8(expected, actual)                                                   UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_INT16(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_INT32(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_INT64(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL(expected, actual)                                                        UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_NOT_EQUAL(expected, actual)                                                    UNITY_TEST_ASSERT(((expected) !=  (actual)), __LINE__, " Expected Not-Equal")
+#define TEST_ASSERT_EQUAL_UINT(expected, actual)                                                   UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_UINT8(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_UINT16(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_UINT32(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_UINT64(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_HEX(expected, actual)                                                    UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_HEX8(expected, actual)                                                   UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_HEX16(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_HEX32(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_HEX64(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_BITS(mask, expected, actual)                                                   UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_BITS_HIGH(mask, actual)                                                        UNITY_TEST_ASSERT_BITS((mask), (_UU32)(-1), (actual), __LINE__, NULL)
+#define TEST_ASSERT_BITS_LOW(mask, actual)                                                         UNITY_TEST_ASSERT_BITS((mask), (_UU32)(0), (actual), __LINE__, NULL)
+#define TEST_ASSERT_BIT_HIGH(bit, actual)                                                          UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(-1), (actual), __LINE__, NULL)
+#define TEST_ASSERT_BIT_LOW(bit, actual)                                                           UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(0), (actual), __LINE__, NULL)
+
+/* Integer Ranges (of all sizes) */
+#define TEST_ASSERT_INT_WITHIN(delta, expected, actual)                                            UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_INT8_WITHIN(delta, expected, actual)                                           UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_INT16_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_INT32_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_INT64_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual)                                           UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_UINT8_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual)                                         UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual)                                         UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual)                                         UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual)                                            UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual)                                           UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+
+/* Structs and Strings */
+#define TEST_ASSERT_EQUAL_PTR(expected, actual)                                                    UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_STRING(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len)                                        UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len)                                            UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, NULL)
+
+/* Arrays */
+#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements)                               UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements)                                UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements)                        UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL)
+
+/* Floating Point (If Enabled) */
+#define TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual)                                          UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_FLOAT(expected, actual)                                                  UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements)                              UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_FLOAT_IS_INF(actual)                                                           UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, NULL)
+#define TEST_ASSERT_FLOAT_IS_NEG_INF(actual)                                                       UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, NULL)
+#define TEST_ASSERT_FLOAT_IS_NAN(actual)                                                           UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, NULL)
+#define TEST_ASSERT_FLOAT_IS_DETERMINATE(actual)                                                   UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, NULL)
+#define TEST_ASSERT_FLOAT_IS_NOT_INF(actual)                                                       UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, NULL)
+#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual)                                                   UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, NULL)
+#define TEST_ASSERT_FLOAT_IS_NOT_NAN(actual)                                                       UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, NULL)
+#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual)                                               UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, NULL)
+
+/* Double (If Enabled) */
+#define TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual)                                         UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_DOUBLE(expected, actual)                                                 UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, NULL)
+#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements)                             UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, NULL)
+#define TEST_ASSERT_DOUBLE_IS_INF(actual)                                                          UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, NULL)
+#define TEST_ASSERT_DOUBLE_IS_NEG_INF(actual)                                                      UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, NULL)
+#define TEST_ASSERT_DOUBLE_IS_NAN(actual)                                                          UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, NULL)
+#define TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual)                                                  UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, NULL)
+#define TEST_ASSERT_DOUBLE_IS_NOT_INF(actual)                                                      UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, NULL)
+#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual)                                                  UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, NULL)
+#define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual)                                                      UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, NULL)
+#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual)                                              UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, NULL)
+
+/*-------------------------------------------------------
+ * Test Asserts (with additional messages)
+ *-------------------------------------------------------*/
+
+/* Boolean */
+#define TEST_ASSERT_MESSAGE(condition, message)                                                    UNITY_TEST_ASSERT(       (condition), __LINE__, (message))
+#define TEST_ASSERT_TRUE_MESSAGE(condition, message)                                               UNITY_TEST_ASSERT(       (condition), __LINE__, (message))
+#define TEST_ASSERT_UNLESS_MESSAGE(condition, message)                                             UNITY_TEST_ASSERT(      !(condition), __LINE__, (message))
+#define TEST_ASSERT_FALSE_MESSAGE(condition, message)                                              UNITY_TEST_ASSERT(      !(condition), __LINE__, (message))
+#define TEST_ASSERT_NULL_MESSAGE(pointer, message)                                                 UNITY_TEST_ASSERT_NULL(    (pointer), __LINE__, (message))
+#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message)                                             UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, (message))
+
+/* Integers (of all sizes) */
+#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message)                                   UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message)                                  UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message)                                       UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message)                                   UNITY_TEST_ASSERT(((expected) !=  (actual)), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message)                                  UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message)                                   UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message)                                  UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message)                                  UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message)                                       UNITY_TEST_ASSERT_BITS((mask), (_UU32)(-1), (actual), __LINE__, (message))
+#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message)                                        UNITY_TEST_ASSERT_BITS((mask), (_UU32)(0), (actual), __LINE__, (message))
+#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message)                                         UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(-1), (actual), __LINE__, (message))
+#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message)                                          UNITY_TEST_ASSERT_BITS(((_UU32)1 << (bit)), (_UU32)(0), (actual), __LINE__, (message))
+
+/* Integer Ranges (of all sizes) */
+#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message)                           UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message)                          UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_INT16_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_INT16_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_INT32_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_INT32_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_INT64_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_INT64_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message)                          UNITY_TEST_ASSERT_UINT_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_UINT8_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_UINT8_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message)                        UNITY_TEST_ASSERT_UINT16_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message)                        UNITY_TEST_ASSERT_UINT32_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message)                        UNITY_TEST_ASSERT_UINT64_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message)                           UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message)                          UNITY_TEST_ASSERT_HEX8_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_HEX16_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_HEX32_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_HEX64_WITHIN((delta), (expected), (actual), __LINE__, (message))
+
+/* Structs and Strings */
+#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message)                                   UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_STRING((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_STRING_LEN_MESSAGE(expected, actual, len, message)                       UNITY_TEST_ASSERT_EQUAL_STRING_LEN((expected), (actual), (len), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message)                           UNITY_TEST_ASSERT_EQUAL_MEMORY((expected), (actual), (len), __LINE__, (message))
+
+/* Arrays */
+#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EQUAL_INT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message)              UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message)               UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE(expected, actual, len, num_elements, message)       UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, (message))
+
+/* Floating Point (If Enabled) */
+#define TEST_ASSERT_FLOAT_WITHIN_MESSAGE(delta, expected, actual, message)                         UNITY_TEST_ASSERT_FLOAT_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_FLOAT_MESSAGE(expected, actual, message)                                 UNITY_TEST_ASSERT_EQUAL_FLOAT((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_FLOAT_ARRAY_MESSAGE(expected, actual, num_elements, message)             UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_FLOAT_IS_INF_MESSAGE(actual, message)                                          UNITY_TEST_ASSERT_FLOAT_IS_INF((actual), __LINE__, (message))
+#define TEST_ASSERT_FLOAT_IS_NEG_INF_MESSAGE(actual, message)                                      UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF((actual), __LINE__, (message))
+#define TEST_ASSERT_FLOAT_IS_NAN_MESSAGE(actual, message)                                          UNITY_TEST_ASSERT_FLOAT_IS_NAN((actual), __LINE__, (message))
+#define TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(actual, message)                                  UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE((actual), __LINE__, (message))
+#define TEST_ASSERT_FLOAT_IS_NOT_INF_MESSAGE(actual, message)                                      UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF((actual), __LINE__, (message))
+#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF_MESSAGE(actual, message)                                  UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF((actual), __LINE__, (message))
+#define TEST_ASSERT_FLOAT_IS_NOT_NAN_MESSAGE(actual, message)                                      UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN((actual), __LINE__, (message))
+#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE_MESSAGE(actual, message)                              UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE((actual), __LINE__, (message))
+
+/* Double (If Enabled) */
+#define TEST_ASSERT_DOUBLE_WITHIN_MESSAGE(delta, expected, actual, message)                        UNITY_TEST_ASSERT_DOUBLE_WITHIN((delta), (expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_DOUBLE_MESSAGE(expected, actual, message)                                UNITY_TEST_ASSERT_EQUAL_DOUBLE((expected), (actual), __LINE__, (message))
+#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY_MESSAGE(expected, actual, num_elements, message)            UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY((expected), (actual), (num_elements), __LINE__, (message))
+#define TEST_ASSERT_DOUBLE_IS_INF_MESSAGE(actual, message)                                         UNITY_TEST_ASSERT_DOUBLE_IS_INF((actual), __LINE__, (message))
+#define TEST_ASSERT_DOUBLE_IS_NEG_INF_MESSAGE(actual, message)                                     UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF((actual), __LINE__, (message))
+#define TEST_ASSERT_DOUBLE_IS_NAN_MESSAGE(actual, message)                                         UNITY_TEST_ASSERT_DOUBLE_IS_NAN((actual), __LINE__, (message))
+#define TEST_ASSERT_DOUBLE_IS_DETERMINATE_MESSAGE(actual, message)                                 UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE((actual), __LINE__, (message))
+#define TEST_ASSERT_DOUBLE_IS_NOT_INF_MESSAGE(actual, message)                                     UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF((actual), __LINE__, (message))
+#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF_MESSAGE(actual, message)                                 UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF((actual), __LINE__, (message))
+#define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message)                                     UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN((actual), __LINE__, (message))
+#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message)                             UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE((actual), __LINE__, (message))
+
+/* end of UNITY_FRAMEWORK_H */
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 75 - 0
tools/unit-test-app/components/unity/include/unity_config.h

@@ -0,0 +1,75 @@
+#ifndef UNITY_CONFIG_H
+#define UNITY_CONFIG_H
+
+// This file gets included from unity.h via unity_internals.h
+// It is inside #ifdef __cplusplus / extern "C" block, so we can
+// only use C features here
+
+// Adapt Unity to our environment, disable FP support
+
+#include <esp_err.h>
+
+#define UNITY_EXCLUDE_FLOAT
+#define UNITY_EXCLUDE_DOUBLE
+
+#define UNITY_OUTPUT_CHAR unity_putc
+#define UNITY_OUTPUT_FLUSH unity_flush
+
+// Define helpers to register test cases from multiple files
+
+#define UNITY_EXPAND2(a, b) a ## b
+#define UNITY_EXPAND(a, b) UNITY_EXPAND2(a, b)
+#define UNITY_TEST_UID(what) UNITY_EXPAND(what, __LINE__)
+
+#define UNITY_TEST_REG_HELPER reg_helper ## UNITY_TEST_UID
+#define UNITY_TEST_DESC_UID desc ## UNITY_TEST_UID
+struct test_desc_t
+{
+	const char* name;
+	const char* desc;
+	void (*fn)(void);
+	const char* file;
+	int line;
+	struct test_desc_t* next;
+};
+
+void unity_testcase_register(struct test_desc_t* desc);
+
+void unity_run_menu();
+
+void unity_run_tests_with_filter(const char* filter);
+
+void unity_run_all_tests();
+
+/*  Test case macro, a-la CATCH framework.
+	First argument is a free-form description, 
+	second argument is (by convention) a list of identifiers, each one in square brackets.
+	Identifiers are used to group related tests, or tests with specific properties.
+    Use like:
+
+	TEST_CASE("Frobnicator forbnicates", "[frobnicator][rom]")
+	{
+		// test goes here
+	}
+*/
+#define TEST_CASE(name_, desc_) \
+	static void UNITY_TEST_UID(test_func_) (void); \
+	static void __attribute__((constructor)) UNITY_TEST_UID(test_reg_helper_) () \
+	{ \
+		static struct test_desc_t UNITY_TEST_UID(test_desc_) = { \
+			.name = name_, \
+			.desc = desc_, \
+			.fn = &UNITY_TEST_UID(test_func_), \
+			.file = __FILE__, \
+			.line = __LINE__ \
+		}; \
+		unity_testcase_register( & UNITY_TEST_UID(test_desc_) ); \
+	}\
+	static void UNITY_TEST_UID(test_func_) (void)
+
+// shorthand to check esp_err_t return code
+#define TEST_ESP_OK(rc)	TEST_ASSERT_EQUAL_INT32(ESP_OK, rc)
+#define TEST_ESP_ERR(err, rc) TEST_ASSERT_EQUAL_INT32(err, rc)
+
+
+#endif //UNITY_CONFIG_H

+ 772 - 0
tools/unit-test-app/components/unity/include/unity_internals.h

@@ -0,0 +1,772 @@
+/* ==========================================
+    Unity Project - A Test Framework for C
+    Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams
+    [Released under MIT License. Please refer to license.txt for details]
+========================================== */
+
+#ifndef UNITY_INTERNALS_H
+#define UNITY_INTERNALS_H
+
+#ifdef UNITY_INCLUDE_CONFIG_H
+#include "unity_config.h"
+#endif
+
+#include <setjmp.h>
+
+/* Unity Attempts to Auto-Detect Integer Types
+ * Attempt 1: UINT_MAX, ULONG_MAX, etc in <stdint.h>
+ * Attempt 2: UINT_MAX, ULONG_MAX, etc in <limits.h>
+ * Attempt 3: Deduced from sizeof() macros */
+#ifndef UNITY_EXCLUDE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifndef UNITY_EXCLUDE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef UNITY_EXCLUDE_SIZEOF
+#ifndef UINT_MAX
+#define UINT_MAX     (sizeof(unsigned int) * 256 - 1)
+#endif
+#ifndef ULONG_MAX
+#define ULONG_MAX    (sizeof(unsigned long) * 256 - 1)
+#endif
+#ifndef UINTPTR_MAX
+/* apparently this is not a constant expression: (sizeof(unsigned int *) * 256 - 1) so we have to just let this fall through */
+#endif
+#endif
+
+#ifndef UNITY_EXCLUDE_MATH_H
+#include <math.h>
+#endif
+
+/*-------------------------------------------------------
+ * Guess Widths If Not Specified
+ *-------------------------------------------------------*/
+
+/* Determine the size of an int, if not already specificied.
+ * We cannot use sizeof(int), because it is not yet defined
+ * at this stage in the trnslation of the C program.
+ * Therefore, infer it from UINT_MAX if possible. */
+#ifndef UNITY_INT_WIDTH
+  #ifdef UINT_MAX
+    #if (UINT_MAX == 0xFFFF)
+      #define UNITY_INT_WIDTH (16)
+    #elif (UINT_MAX == 0xFFFFFFFF)
+      #define UNITY_INT_WIDTH (32)
+    #elif (UINT_MAX == 0xFFFFFFFFFFFFFFFF)
+      #define UNITY_INT_WIDTH (64)
+    #endif
+  #endif
+#endif
+#ifndef UNITY_INT_WIDTH
+  #define UNITY_INT_WIDTH (32)
+#endif
+
+/* Determine the size of a long, if not already specified,
+ * by following the process used above to define
+ * UNITY_INT_WIDTH. */
+#ifndef UNITY_LONG_WIDTH
+  #ifdef ULONG_MAX
+    #if (ULONG_MAX == 0xFFFF)
+      #define UNITY_LONG_WIDTH (16)
+    #elif (ULONG_MAX == 0xFFFFFFFF)
+      #define UNITY_LONG_WIDTH (32)
+    #elif (ULONG_MAX == 0xFFFFFFFFFFFFFFFF)
+      #define UNITY_LONG_WIDTH (64)
+    #endif
+  #endif
+#endif
+#ifndef UNITY_LONG_WIDTH
+  #define UNITY_LONG_WIDTH (32)
+#endif
+
+/* Determine the size of a pointer, if not already specified,
+ * by following the process used above to define
+ * UNITY_INT_WIDTH. */
+#ifndef UNITY_POINTER_WIDTH
+  #ifdef UINTPTR_MAX
+    #if (UINTPTR_MAX+0 <= 0xFFFF)
+      #define UNITY_POINTER_WIDTH (16)
+    #elif (UINTPTR_MAX+0 <= 0xFFFFFFFF)
+      #define UNITY_POINTER_WIDTH (32)
+    #elif (UINTPTR_MAX+0 <= 0xFFFFFFFFFFFFFFFF)
+      #define UNITY_POINTER_WIDTH (64)
+    #endif
+  #endif
+#endif
+#ifndef UNITY_POINTER_WIDTH
+  #ifdef INTPTR_MAX
+    #if (INTPTR_MAX+0 <= 0x7FFF)
+      #define UNITY_POINTER_WIDTH (16)
+    #elif (INTPTR_MAX+0 <= 0x7FFFFFFF)
+      #define UNITY_POINTER_WIDTH (32)
+    #elif (INTPTR_MAX+0 <= 0x7FFFFFFFFFFFFFFF)
+      #define UNITY_POINTER_WIDTH (64)
+    #endif
+  #endif
+#endif
+#ifndef UNITY_POINTER_WIDTH
+  #define UNITY_POINTER_WIDTH UNITY_LONG_WIDTH
+#endif
+
+/*-------------------------------------------------------
+ * Int Support (Define types based on detected sizes)
+ *-------------------------------------------------------*/
+
+#if (UNITY_INT_WIDTH == 32)
+    typedef unsigned char   _UU8;
+    typedef unsigned short  _UU16;
+    typedef unsigned int    _UU32;
+    typedef signed char     _US8;
+    typedef signed short    _US16;
+    typedef signed int      _US32;
+#elif (UNITY_INT_WIDTH == 16)
+    typedef unsigned char   _UU8;
+    typedef unsigned int    _UU16;
+    typedef unsigned long   _UU32;
+    typedef signed char     _US8;
+    typedef signed int      _US16;
+    typedef signed long     _US32;
+#else
+    #error Invalid UNITY_INT_WIDTH specified! (16 or 32 are supported)
+#endif
+
+/*-------------------------------------------------------
+ * 64-bit Support
+ *-------------------------------------------------------*/
+
+#ifndef UNITY_SUPPORT_64
+#if UNITY_LONG_WIDTH > 32
+#define UNITY_SUPPORT_64
+#endif
+#endif
+#ifndef UNITY_SUPPORT_64
+#if UNITY_POINTER_WIDTH > 32
+#define UNITY_SUPPORT_64
+#endif
+#endif
+
+#ifndef UNITY_SUPPORT_64
+
+/* No 64-bit Support */
+typedef _UU32 _U_UINT;
+typedef _US32 _U_SINT;
+
+#else
+
+/* 64-bit Support */
+#if (UNITY_LONG_WIDTH == 32)
+    typedef unsigned long long _UU64;
+    typedef signed long long   _US64;
+#elif (UNITY_LONG_WIDTH == 64)
+    typedef unsigned long      _UU64;
+    typedef signed long        _US64;
+#else
+    #error Invalid UNITY_LONG_WIDTH specified! (32 or 64 are supported)
+#endif
+typedef _UU64 _U_UINT;
+typedef _US64 _U_SINT;
+
+#endif
+
+/*-------------------------------------------------------
+ * Pointer Support
+ *-------------------------------------------------------*/
+
+#if (UNITY_POINTER_WIDTH == 32)
+    typedef _UU32 _UP;
+#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32
+#elif (UNITY_POINTER_WIDTH == 64)
+    typedef _UU64 _UP;
+#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64
+#elif (UNITY_POINTER_WIDTH == 16)
+    typedef _UU16 _UP;
+#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16
+#else
+    #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported)
+#endif
+
+#ifndef UNITY_PTR_ATTRIBUTE
+#define UNITY_PTR_ATTRIBUTE
+#endif
+
+#ifndef UNITY_INTERNAL_PTR
+#define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const void*
+/* #define UNITY_INTERNAL_PTR UNITY_PTR_ATTRIBUTE const _UU8* */
+#endif
+
+/*-------------------------------------------------------
+ * Float Support
+ *-------------------------------------------------------*/
+
+#ifdef UNITY_EXCLUDE_FLOAT
+
+/* No Floating Point Support */
+#undef UNITY_INCLUDE_FLOAT
+#undef UNITY_FLOAT_PRECISION
+#undef UNITY_FLOAT_TYPE
+#undef UNITY_FLOAT_VERBOSE
+
+#else
+
+#ifndef UNITY_INCLUDE_FLOAT
+#define UNITY_INCLUDE_FLOAT
+#endif
+
+/* Floating Point Support */
+#ifndef UNITY_FLOAT_PRECISION
+#define UNITY_FLOAT_PRECISION (0.00001f)
+#endif
+#ifndef UNITY_FLOAT_TYPE
+#define UNITY_FLOAT_TYPE float
+#endif
+typedef UNITY_FLOAT_TYPE _UF;
+
+#ifndef isinf
+#define isinf(n) (((1.0f / f_zero) == n) ? 1 : 0) || (((-1.0f / f_zero) == n) ? 1 : 0)
+#define UNITY_FLOAT_NEEDS_ZERO
+#endif
+
+#ifndef isnan
+#define isnan(n) ((n != n) ? 1 : 0)
+#endif
+
+#ifndef isneg
+#define isneg(n) ((n < 0.0f) ? 1 : 0)
+#endif
+
+#ifndef ispos
+#define ispos(n) ((n > 0.0f) ? 1 : 0)
+#endif
+
+#endif
+
+/*-------------------------------------------------------
+ * Double Float Support
+ *-------------------------------------------------------*/
+
+/* unlike FLOAT, we DON'T include by default */
+#ifndef UNITY_EXCLUDE_DOUBLE
+#ifndef UNITY_INCLUDE_DOUBLE
+#define UNITY_EXCLUDE_DOUBLE
+#endif
+#endif
+
+#ifdef UNITY_EXCLUDE_DOUBLE
+
+/* No Floating Point Support */
+#undef UNITY_DOUBLE_PRECISION
+#undef UNITY_DOUBLE_TYPE
+#undef UNITY_DOUBLE_VERBOSE
+
+#ifdef UNITY_INCLUDE_DOUBLE
+#undef UNITY_INCLUDE_DOUBLE
+#endif
+
+#else
+
+/* Double Floating Point Support */
+#ifndef UNITY_DOUBLE_PRECISION
+#define UNITY_DOUBLE_PRECISION (1e-12f)
+#endif
+#ifndef UNITY_DOUBLE_TYPE
+#define UNITY_DOUBLE_TYPE double
+#endif
+typedef UNITY_DOUBLE_TYPE _UD;
+
+#endif
+
+#ifdef UNITY_DOUBLE_VERBOSE
+#ifndef UNITY_FLOAT_VERBOSE
+#define UNITY_FLOAT_VERBOSE
+#endif
+#endif
+
+/*-------------------------------------------------------
+ * Output Method: stdout (DEFAULT)
+ *-------------------------------------------------------*/
+#ifndef UNITY_OUTPUT_CHAR
+/* Default to using putchar, which is defined in stdio.h */
+#include <stdio.h>
+#define UNITY_OUTPUT_CHAR(a) (void)putchar(a)
+#else
+  /* If defined as something else, make sure we declare it here so it's ready for use */
+  #ifndef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION
+extern void UNITY_OUTPUT_CHAR(int);
+  #endif
+#endif
+
+#ifndef UNITY_OUTPUT_FLUSH
+/* Default to using putchar, which is defined in stdio.h */
+#include <stdio.h>
+#define UNITY_OUTPUT_FLUSH() (void)fflush(stdout)
+#else
+  /* If defined as something else, make sure we declare it here so it's ready for use */
+  #ifndef UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION
+extern void UNITY_OUTPUT_FLUSH(void);
+  #endif
+#endif
+
+#ifndef UNITY_PRINT_EOL
+#define UNITY_PRINT_EOL()    UNITY_OUTPUT_CHAR('\n')
+#endif
+
+#ifndef UNITY_OUTPUT_START
+#define UNITY_OUTPUT_START()
+#endif
+
+#ifndef UNITY_OUTPUT_COMPLETE
+#define UNITY_OUTPUT_COMPLETE()
+#endif
+
+/*-------------------------------------------------------
+ * Footprint
+ *-------------------------------------------------------*/
+
+#ifndef UNITY_LINE_TYPE
+#define UNITY_LINE_TYPE _U_UINT
+#endif
+
+#ifndef UNITY_COUNTER_TYPE
+#define UNITY_COUNTER_TYPE _U_UINT
+#endif
+
+/*-------------------------------------------------------
+ * Language Features Available
+ *-------------------------------------------------------*/
+#if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA)
+#   ifdef __GNUC__ /* includes clang */
+#       if !(defined(__WIN32__) && defined(__clang__))
+#           define UNITY_WEAK_ATTRIBUTE __attribute__((weak))
+#       endif
+#   endif
+#endif
+
+#ifdef UNITY_NO_WEAK
+#   undef UNITY_WEAK_ATTRIBUTE
+#   undef UNITY_WEAK_PRAGMA
+#endif
+
+
+/*-------------------------------------------------------
+ * Internal Structs Needed
+ *-------------------------------------------------------*/
+
+typedef void (*UnityTestFunction)(void);
+
+#define UNITY_DISPLAY_RANGE_INT  (0x10)
+#define UNITY_DISPLAY_RANGE_UINT (0x20)
+#define UNITY_DISPLAY_RANGE_HEX  (0x40)
+#define UNITY_DISPLAY_RANGE_AUTO (0x80)
+
+typedef enum
+{
+#if (UNITY_INT_WIDTH == 16)
+    UNITY_DISPLAY_STYLE_INT      = 2 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO,
+#elif (UNITY_INT_WIDTH  == 32)
+    UNITY_DISPLAY_STYLE_INT      = 4 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO,
+#elif (UNITY_INT_WIDTH  == 64)
+    UNITY_DISPLAY_STYLE_INT      = 8 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO,
+#endif
+    UNITY_DISPLAY_STYLE_INT8     = 1 + UNITY_DISPLAY_RANGE_INT,
+    UNITY_DISPLAY_STYLE_INT16    = 2 + UNITY_DISPLAY_RANGE_INT,
+    UNITY_DISPLAY_STYLE_INT32    = 4 + UNITY_DISPLAY_RANGE_INT,
+#ifdef UNITY_SUPPORT_64
+    UNITY_DISPLAY_STYLE_INT64    = 8 + UNITY_DISPLAY_RANGE_INT,
+#endif
+
+#if (UNITY_INT_WIDTH == 16)
+    UNITY_DISPLAY_STYLE_UINT     = 2 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO,
+#elif (UNITY_INT_WIDTH  == 32)
+    UNITY_DISPLAY_STYLE_UINT     = 4 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO,
+#elif (UNITY_INT_WIDTH  == 64)
+    UNITY_DISPLAY_STYLE_UINT     = 8 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO,
+#endif
+    UNITY_DISPLAY_STYLE_UINT8    = 1 + UNITY_DISPLAY_RANGE_UINT,
+    UNITY_DISPLAY_STYLE_UINT16   = 2 + UNITY_DISPLAY_RANGE_UINT,
+    UNITY_DISPLAY_STYLE_UINT32   = 4 + UNITY_DISPLAY_RANGE_UINT,
+#ifdef UNITY_SUPPORT_64
+    UNITY_DISPLAY_STYLE_UINT64   = 8 + UNITY_DISPLAY_RANGE_UINT,
+#endif
+    UNITY_DISPLAY_STYLE_HEX8     = 1 + UNITY_DISPLAY_RANGE_HEX,
+    UNITY_DISPLAY_STYLE_HEX16    = 2 + UNITY_DISPLAY_RANGE_HEX,
+    UNITY_DISPLAY_STYLE_HEX32    = 4 + UNITY_DISPLAY_RANGE_HEX,
+#ifdef UNITY_SUPPORT_64
+    UNITY_DISPLAY_STYLE_HEX64    = 8 + UNITY_DISPLAY_RANGE_HEX,
+#endif
+    UNITY_DISPLAY_STYLE_UNKNOWN
+} UNITY_DISPLAY_STYLE_T;
+
+#ifndef UNITY_EXCLUDE_FLOAT
+typedef enum _UNITY_FLOAT_TRAIT_T
+{
+    UNITY_FLOAT_IS_NOT_INF       = 0,
+    UNITY_FLOAT_IS_INF,
+    UNITY_FLOAT_IS_NOT_NEG_INF,
+    UNITY_FLOAT_IS_NEG_INF,
+    UNITY_FLOAT_IS_NOT_NAN,
+    UNITY_FLOAT_IS_NAN,
+    UNITY_FLOAT_IS_NOT_DET,
+    UNITY_FLOAT_IS_DET,
+    UNITY_FLOAT_INVALID_TRAIT
+} UNITY_FLOAT_TRAIT_T;
+#endif
+
+struct _Unity
+{
+    const char* TestFile;
+    const char* CurrentTestName;
+#ifndef UNITY_EXCLUDE_DETAILS
+    const char* CurrentDetail1;
+    const char* CurrentDetail2;
+#endif
+    UNITY_LINE_TYPE CurrentTestLineNumber;
+    UNITY_COUNTER_TYPE NumberOfTests;
+    UNITY_COUNTER_TYPE TestFailures;
+    UNITY_COUNTER_TYPE TestIgnores;
+    UNITY_COUNTER_TYPE CurrentTestFailed;
+    UNITY_COUNTER_TYPE CurrentTestIgnored;
+    jmp_buf AbortFrame;
+};
+
+extern struct _Unity Unity;
+
+/*-------------------------------------------------------
+ * Test Suite Management
+ *-------------------------------------------------------*/
+
+void UnityBegin(const char* filename);
+int  UnityEnd(void);
+void UnityConcludeTest(void);
+void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum);
+
+/*-------------------------------------------------------
+ * Details Support
+ *-------------------------------------------------------*/
+
+#ifdef UNITY_EXCLUDE_DETAILS
+#define UNITY_CLR_DETAILS()
+#define UNITY_SET_DETAIL(d1)
+#define UNITY_SET_DETAILS(d1,d2)
+#else
+#define UNITY_CLR_DETAILS()      { Unity.CurrentDetail1 = 0;   Unity.CurrentDetail2 = 0;  }
+#define UNITY_SET_DETAIL(d1)     { Unity.CurrentDetail1 = d1;  Unity.CurrentDetail2 = 0;  }
+#define UNITY_SET_DETAILS(d1,d2) { Unity.CurrentDetail1 = d1;  Unity.CurrentDetail2 = d2; }
+
+#ifndef UNITY_DETAIL1_NAME
+#define UNITY_DETAIL1_NAME "Function"
+#endif
+
+#ifndef UNITY_DETAIL2_NAME
+#define UNITY_DETAIL2_NAME "Argument"
+#endif
+#endif
+
+/*-------------------------------------------------------
+ * Test Output
+ *-------------------------------------------------------*/
+
+void UnityPrint(const char* string);
+void UnityPrintMask(const _U_UINT mask, const _U_UINT number);
+void UnityPrintNumberByStyle(const _U_SINT number, const UNITY_DISPLAY_STYLE_T style);
+void UnityPrintNumber(const _U_SINT number);
+void UnityPrintNumberUnsigned(const _U_UINT number);
+void UnityPrintNumberHex(const _U_UINT number, const char nibbles);
+
+#ifdef UNITY_FLOAT_VERBOSE
+void UnityPrintFloat(const _UF number);
+#endif
+
+/*-------------------------------------------------------
+ * Test Assertion Fuctions
+ *-------------------------------------------------------
+ *  Use the macros below this section instead of calling
+ *  these directly. The macros have a consistent naming
+ *  convention and will pull in file and line information
+ *  for you. */
+
+void UnityAssertEqualNumber(const _U_SINT expected,
+                            const _U_SINT actual,
+                            const char* msg,
+                            const UNITY_LINE_TYPE lineNumber,
+                            const UNITY_DISPLAY_STYLE_T style);
+
+void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected,
+                              UNITY_INTERNAL_PTR actual,
+                              const _UU32 num_elements,
+                              const char* msg,
+                              const UNITY_LINE_TYPE lineNumber,
+                              const UNITY_DISPLAY_STYLE_T style);
+
+void UnityAssertBits(const _U_SINT mask,
+                     const _U_SINT expected,
+                     const _U_SINT actual,
+                     const char* msg,
+                     const UNITY_LINE_TYPE lineNumber);
+
+void UnityAssertEqualString(const char* expected,
+                            const char* actual,
+                            const char* msg,
+                            const UNITY_LINE_TYPE lineNumber);
+
+void UnityAssertEqualStringLen(const char* expected,
+                            const char* actual,
+                            const _UU32 length,
+                            const char* msg,
+                            const UNITY_LINE_TYPE lineNumber);
+
+void UnityAssertEqualStringArray( const char** expected,
+                                  const char** actual,
+                                  const _UU32 num_elements,
+                                  const char* msg,
+                                  const UNITY_LINE_TYPE lineNumber);
+
+void UnityAssertEqualMemory( UNITY_INTERNAL_PTR expected,
+                             UNITY_INTERNAL_PTR actual,
+                             const _UU32 length,
+                             const _UU32 num_elements,
+                             const char* msg,
+                             const UNITY_LINE_TYPE lineNumber);
+
+void UnityAssertNumbersWithin(const _U_UINT delta,
+                              const _U_SINT expected,
+                              const _U_SINT actual,
+                              const char* msg,
+                              const UNITY_LINE_TYPE lineNumber,
+                              const UNITY_DISPLAY_STYLE_T style);
+
+void UnityFail(const char* message, const UNITY_LINE_TYPE line);
+
+void UnityIgnore(const char* message, const UNITY_LINE_TYPE line);
+
+#ifndef UNITY_EXCLUDE_FLOAT
+void UnityAssertFloatsWithin(const _UF delta,
+                             const _UF expected,
+                             const _UF actual,
+                             const char* msg,
+                             const UNITY_LINE_TYPE lineNumber);
+
+void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const _UF* expected,
+                                UNITY_PTR_ATTRIBUTE const _UF* actual,
+                                const _UU32 num_elements,
+                                const char* msg,
+                                const UNITY_LINE_TYPE lineNumber);
+
+void UnityAssertFloatSpecial(const _UF actual,
+                             const char* msg,
+                             const UNITY_LINE_TYPE lineNumber,
+                             const UNITY_FLOAT_TRAIT_T style);
+#endif
+
+#ifndef UNITY_EXCLUDE_DOUBLE
+void UnityAssertDoublesWithin(const _UD delta,
+                              const _UD expected,
+                              const _UD actual,
+                              const char* msg,
+                              const UNITY_LINE_TYPE lineNumber);
+
+void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const _UD* expected,
+                                 UNITY_PTR_ATTRIBUTE const _UD* actual,
+                                 const _UU32 num_elements,
+                                 const char* msg,
+                                 const UNITY_LINE_TYPE lineNumber);
+
+void UnityAssertDoubleSpecial(const _UD actual,
+                              const char* msg,
+                              const UNITY_LINE_TYPE lineNumber,
+                              const UNITY_FLOAT_TRAIT_T style);
+#endif
+
+/*-------------------------------------------------------
+ * Error Strings We Might Need
+ *-------------------------------------------------------*/
+
+extern const char UnityStrErrFloat[];
+extern const char UnityStrErrDouble[];
+extern const char UnityStrErr64[];
+
+/*-------------------------------------------------------
+ * Test Running Macros
+ *-------------------------------------------------------*/
+
+#define TEST_PROTECT() (setjmp(Unity.AbortFrame) == 0)
+
+#define TEST_ABORT() {longjmp(Unity.AbortFrame, 1);}
+
+/* This tricky series of macros gives us an optional line argument to treat it as RUN_TEST(func, num=__LINE__) */
+#ifndef RUN_TEST
+#ifdef __STDC_VERSION__
+#if __STDC_VERSION__ >= 199901L
+#define RUN_TEST(...) UnityDefaultTestRun(RUN_TEST_FIRST(__VA_ARGS__), RUN_TEST_SECOND(__VA_ARGS__))
+#define RUN_TEST_FIRST(...) RUN_TEST_FIRST_HELPER(__VA_ARGS__, throwaway)
+#define RUN_TEST_FIRST_HELPER(first, ...) (first), #first
+#define RUN_TEST_SECOND(...) RUN_TEST_SECOND_HELPER(__VA_ARGS__, __LINE__, throwaway)
+#define RUN_TEST_SECOND_HELPER(first, second, ...) (second)
+#endif
+#endif
+#endif
+
+/* If we can't do the tricky version, we'll just have to require them to always include the line number */
+#ifndef RUN_TEST
+#ifdef CMOCK
+#define RUN_TEST(func, num) UnityDefaultTestRun(func, #func, num)
+#else
+#define RUN_TEST(func) UnityDefaultTestRun(func, #func, __LINE__)
+#endif
+#endif
+
+#define TEST_LINE_NUM (Unity.CurrentTestLineNumber)
+#define TEST_IS_IGNORED (Unity.CurrentTestIgnored)
+#define UNITY_NEW_TEST(a) \
+    Unity.CurrentTestName = (a); \
+    Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)(__LINE__); \
+    Unity.NumberOfTests++;
+
+#ifndef UNITY_BEGIN
+#define UNITY_BEGIN() UnityBegin(__FILE__)
+#endif
+
+#ifndef UNITY_END
+#define UNITY_END() UnityEnd()
+#endif
+
+#define UNITY_UNUSED(x) (void)(sizeof(x))
+
+/*-------------------------------------------------------
+ * Basic Fail and Ignore
+ *-------------------------------------------------------*/
+
+#define UNITY_TEST_FAIL(line, message)   UnityFail(   (message), (UNITY_LINE_TYPE)(line))
+#define UNITY_TEST_IGNORE(line, message) UnityIgnore( (message), (UNITY_LINE_TYPE)(line))
+
+/*-------------------------------------------------------
+ * Test Asserts
+ *-------------------------------------------------------*/
+
+#define UNITY_TEST_ASSERT(condition, line, message)                                              if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), (message));}
+#define UNITY_TEST_ASSERT_NULL(pointer, line, message)                                           UNITY_TEST_ASSERT(((pointer) == NULL),  (UNITY_LINE_TYPE)(line), (message))
+#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message)                                       UNITY_TEST_ASSERT(((pointer) != NULL),  (UNITY_LINE_TYPE)(line), (message))
+
+#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message)                             UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)
+#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message)                            UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)
+#define UNITY_TEST_ASSERT_EQUAL_INT16(expected, actual, line, message)                           UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)
+#define UNITY_TEST_ASSERT_EQUAL_INT32(expected, actual, line, message)                           UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)
+#define UNITY_TEST_ASSERT_EQUAL_UINT(expected, actual, line, message)                            UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)
+#define UNITY_TEST_ASSERT_EQUAL_UINT8(expected, actual, line, message)                           UnityAssertEqualNumber((_U_SINT)(_UU8 )(expected), (_U_SINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)
+#define UNITY_TEST_ASSERT_EQUAL_UINT16(expected, actual, line, message)                          UnityAssertEqualNumber((_U_SINT)(_UU16)(expected), (_U_SINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)
+#define UNITY_TEST_ASSERT_EQUAL_UINT32(expected, actual, line, message)                          UnityAssertEqualNumber((_U_SINT)(_UU32)(expected), (_U_SINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)
+#define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message)                            UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)
+#define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message)                           UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)
+#define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message)                           UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)
+#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message)                            UnityAssertBits((_U_SINT)(mask), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line))
+
+#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message)                     UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)
+#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message)                    UnityAssertNumbersWithin((_UU8 )(delta), (_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)
+#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((_UU16)(delta), (_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)
+#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((_UU32)(delta), (_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)
+#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message)                    UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)
+#define UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((_UU8 )(delta), (_U_SINT)(_U_UINT)(_UU8 )(expected), (_U_SINT)(_U_UINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)
+#define UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, line, message)                  UnityAssertNumbersWithin((_UU16)(delta), (_U_SINT)(_U_UINT)(_UU16)(expected), (_U_SINT)(_U_UINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)
+#define UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, line, message)                  UnityAssertNumbersWithin((_UU32)(delta), (_U_SINT)(_U_UINT)(_UU32)(expected), (_U_SINT)(_U_UINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)
+#define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message)                    UnityAssertNumbersWithin((_UU8 )(delta), (_U_SINT)(_U_UINT)(_UU8 )(expected), (_U_SINT)(_U_UINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)
+#define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((_UU16)(delta), (_U_SINT)(_U_UINT)(_UU16)(expected), (_U_SINT)(_U_UINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)
+#define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((_UU32)(delta), (_U_SINT)(_U_UINT)(_UU32)(expected), (_U_SINT)(_U_UINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)
+
+#define UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, line, message)                             UnityAssertEqualNumber((_U_SINT)(_UP)(expected), (_U_SINT)(_UP)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER)
+#define UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, line, message)                          UnityAssertEqualString((const char*)(expected), (const char*)(actual), (message), (UNITY_LINE_TYPE)(line))
+#define UNITY_TEST_ASSERT_EQUAL_STRING_LEN(expected, actual, len, line, message)                 UnityAssertEqualStringLen((const char*)(expected), (const char*)(actual), (_UU32)(len), (message), (UNITY_LINE_TYPE)(line))
+#define UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, line, message)                     UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(len), 1, (message), (UNITY_LINE_TYPE)(line))
+
+#define UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT)
+#define UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8)
+#define UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16)
+#define UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32)
+#define UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT)
+#define UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8)
+#define UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16)
+#define UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32)
+#define UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, line, message)        UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8)
+#define UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16)
+#define UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32)
+#define UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, line, message)         UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(_UP*)(expected), (UNITY_INTERNAL_PTR)(_UP*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_POINTER)
+#define UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualStringArray((const char**)(expected), (const char**)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line))
+#define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(len), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line))
+
+#ifdef UNITY_SUPPORT_64
+#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message)                           UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)
+#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message)                          UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)
+#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message)                           UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)
+#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)
+#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)
+#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)
+#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64)
+#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message)                  UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64)
+#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message)                   UnityAssertNumbersWithin((delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64)
+#else
+#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)
+#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message)                          UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)
+#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)
+#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message)       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)
+#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message)      UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)
+#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message)       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)
+#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)
+#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message)                  UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)
+#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64)
+#endif
+
+#ifdef UNITY_EXCLUDE_FLOAT
+#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message)                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message)       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message)                                    UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message)                                UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message)                                    UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message)                            UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message)                                UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message)                            UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message)                                UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message)                        UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrFloat)
+#else
+#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message)                   UnityAssertFloatsWithin((_UF)(delta), (_UF)(expected), (_UF)(actual), (message), (UNITY_LINE_TYPE)(line))
+#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message)                           UNITY_TEST_ASSERT_FLOAT_WITHIN((_UF)(expected) * (_UF)UNITY_FLOAT_PRECISION, (_UF)(expected), (_UF)(actual), (UNITY_LINE_TYPE)(line), (message))
+#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message)       UnityAssertEqualFloatArray((_UF*)(expected), (_UF*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)(line))
+#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message)                                    UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message)                                UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message)                                    UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN)
+#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message)                            UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message)                                UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message)                            UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message)                                UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN)
+#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message)                        UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET)
+#endif
+
+#ifdef UNITY_EXCLUDE_DOUBLE
+#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message)                  UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message)                          UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message)      UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message)                                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message)                               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message)                                   UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message)                               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message)                           UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message)                               UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message)                       UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErrDouble)
+#else
+#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message)                  UnityAssertDoublesWithin((_UD)(delta), (_UD)(expected), (_UD)(actual), (message), (UNITY_LINE_TYPE)line)
+#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message)                          UNITY_TEST_ASSERT_DOUBLE_WITHIN((_UD)(expected) * (_UD)UNITY_DOUBLE_PRECISION, (_UD)expected, (_UD)actual, (UNITY_LINE_TYPE)(line), message)
+#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message)      UnityAssertEqualDoubleArray((_UD*)(expected), (_UD*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message)                                   UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_INF)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message)                               UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NEG_INF)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message)                                   UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NAN)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message)                           UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_DET)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message)                               UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_INF)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message)                           UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NEG_INF)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message)                               UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_NAN)
+#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message)                       UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_FLOAT_IS_NOT_DET)
+#endif
+
+/* End of UNITY_INTERNALS_H */
+#endif

+ 21 - 0
tools/unit-test-app/components/unity/license.txt

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) <year> 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams
+
+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.

+ 1306 - 0
tools/unit-test-app/components/unity/unity.c

@@ -0,0 +1,1306 @@
+/* =========================================================================
+    Unity Project - A Test Framework for C
+    Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams
+    [Released under MIT License. Please refer to license.txt for details]
+============================================================================ */
+
+#include "unity.h"
+#include <stddef.h>
+
+/* If omitted from header, declare overrideable prototypes here so they're ready for use */
+#ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION
+int UNITY_OUTPUT_CHAR(int);
+#endif
+#ifdef UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION
+int UNITY_OUTPUT_FLUSH(void);
+#endif
+
+/* Helpful macros for us to use here */
+#define UNITY_FAIL_AND_BAIL   { Unity.CurrentTestFailed  = 1; longjmp(Unity.AbortFrame, 1); }
+#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; longjmp(Unity.AbortFrame, 1); }
+
+/* return prematurely if we are already in failure or ignore state */
+#define UNITY_SKIP_EXECUTION  { if ((Unity.CurrentTestFailed != 0) || (Unity.CurrentTestIgnored != 0)) {return;} }
+
+struct _Unity Unity;
+
+static const char UnityStrOk[]                     = "OK";
+static const char UnityStrPass[]                   = "PASS";
+static const char UnityStrFail[]                   = "FAIL";
+static const char UnityStrIgnore[]                 = "IGNORE";
+static const char UnityStrNull[]                   = "NULL";
+static const char UnityStrSpacer[]                 = ". ";
+static const char UnityStrExpected[]               = " Expected ";
+static const char UnityStrWas[]                    = " Was ";
+static const char UnityStrElement[]                = " Element ";
+static const char UnityStrByte[]                   = " Byte ";
+static const char UnityStrMemory[]                 = " Memory Mismatch.";
+static const char UnityStrDelta[]                  = " Values Not Within Delta ";
+static const char UnityStrPointless[]              = " You Asked Me To Compare Nothing, Which Was Pointless.";
+static const char UnityStrNullPointerForExpected[] = " Expected pointer to be NULL";
+static const char UnityStrNullPointerForActual[]   = " Actual pointer was NULL";
+static const char UnityStrNot[]                    = "Not ";
+static const char UnityStrInf[]                    = "Infinity";
+static const char UnityStrNegInf[]                 = "Negative Infinity";
+static const char UnityStrNaN[]                    = "NaN";
+static const char UnityStrDet[]                    = "Determinate";
+static const char UnityStrInvalidFloatTrait[]      = "Invalid Float Trait";
+const char UnityStrErrFloat[]                      = "Unity Floating Point Disabled";
+const char UnityStrErrDouble[]                     = "Unity Double Precision Disabled";
+const char UnityStrErr64[]                         = "Unity 64-bit Support Disabled";
+static const char UnityStrBreaker[]                = "-----------------------";
+static const char UnityStrResultsTests[]           = " Tests ";
+static const char UnityStrResultsFailures[]        = " Failures ";
+static const char UnityStrResultsIgnored[]         = " Ignored ";
+static const char UnityStrDetail1Name[]            = UNITY_DETAIL1_NAME " ";
+static const char UnityStrDetail2Name[]            = " " UNITY_DETAIL2_NAME " ";
+
+#ifdef UNITY_FLOAT_NEEDS_ZERO
+/* Dividing by these constants produces +/- infinity.
+ * The rationale is given in UnityAssertFloatIsInf's body. */
+static const _UF f_zero = 0.0f;
+#endif
+
+/* compiler-generic print formatting masks */
+static const _U_UINT UnitySizeMask[] =
+{
+    255u,         /* 0xFF */
+    65535u,       /* 0xFFFF */
+    65535u,
+    4294967295u,  /* 0xFFFFFFFF */
+    4294967295u,
+    4294967295u,
+    4294967295u
+#ifdef UNITY_SUPPORT_64
+    ,0xFFFFFFFFFFFFFFFF
+#endif
+};
+
+/*-----------------------------------------------
+ * Pretty Printers & Test Result Output Handlers
+ *-----------------------------------------------*/
+
+void UnityPrint(const char* string)
+{
+    const char* pch = string;
+
+    if (pch != NULL)
+    {
+        while (*pch)
+        {
+            /* printable characters plus CR & LF are printed */
+            if ((*pch <= 126) && (*pch >= 32))
+            {
+                UNITY_OUTPUT_CHAR(*pch);
+            }
+            /* write escaped carriage returns */
+            else if (*pch == 13)
+            {
+                UNITY_OUTPUT_CHAR('\\');
+                UNITY_OUTPUT_CHAR('r');
+            }
+            /* write escaped line feeds */
+            else if (*pch == 10)
+            {
+                UNITY_OUTPUT_CHAR('\\');
+                UNITY_OUTPUT_CHAR('n');
+            }
+            /* unprintable characters are shown as codes */
+            else
+            {
+                UNITY_OUTPUT_CHAR('\\');
+                UnityPrintNumberHex((_U_UINT)*pch, 2);
+            }
+            pch++;
+        }
+    }
+}
+
+void UnityPrintLen(const char* string, const _UU32 length);
+void UnityPrintLen(const char* string, const _UU32 length)
+{
+    const char* pch = string;
+
+    if (pch != NULL)
+    {
+        while (*pch && (_UU32)(pch - string) < length)
+        {
+            /* printable characters plus CR & LF are printed */
+            if ((*pch <= 126) && (*pch >= 32))
+            {
+                UNITY_OUTPUT_CHAR(*pch);
+            }
+            /* write escaped carriage returns */
+            else if (*pch == 13)
+            {
+                UNITY_OUTPUT_CHAR('\\');
+                UNITY_OUTPUT_CHAR('r');
+            }
+            /* write escaped line feeds */
+            else if (*pch == 10)
+            {
+                UNITY_OUTPUT_CHAR('\\');
+                UNITY_OUTPUT_CHAR('n');
+            }
+            /* unprintable characters are shown as codes */
+            else
+            {
+                UNITY_OUTPUT_CHAR('\\');
+                UnityPrintNumberHex((_U_UINT)*pch, 2);
+            }
+            pch++;
+        }
+    }
+}
+
+/*-----------------------------------------------*/
+void UnityPrintNumberByStyle(const _U_SINT number, const UNITY_DISPLAY_STYLE_T style)
+{
+    if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT)
+    {
+        UnityPrintNumber(number);
+    }
+    else if ((style & UNITY_DISPLAY_RANGE_UINT) == UNITY_DISPLAY_RANGE_UINT)
+    {
+        UnityPrintNumberUnsigned(  (_U_UINT)number  &  UnitySizeMask[((_U_UINT)style & (_U_UINT)0x0F) - 1]  );
+    }
+    else
+    {
+        UnityPrintNumberHex((_U_UINT)number, (char)((style & 0x000F) << 1));
+    }
+}
+
+/*-----------------------------------------------*/
+void UnityPrintNumber(const _U_SINT number_to_print)
+{
+    _U_UINT number = (_U_UINT)number_to_print;
+
+    if (number_to_print < 0)
+    {
+        /* A negative number, including MIN negative */
+        UNITY_OUTPUT_CHAR('-');
+        number = (_U_UINT)(-number_to_print);
+    }
+    UnityPrintNumberUnsigned(number);
+}
+
+/*-----------------------------------------------
+ * basically do an itoa using as little ram as possible */
+void UnityPrintNumberUnsigned(const _U_UINT number)
+{
+    _U_UINT divisor = 1;
+
+    /* figure out initial divisor */
+    while (number / divisor > 9)
+    {
+        divisor *= 10;
+    }
+
+    /* now mod and print, then divide divisor */
+    do
+    {
+        UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10)));
+        divisor /= 10;
+    }
+    while (divisor > 0);
+}
+
+/*-----------------------------------------------*/
+void UnityPrintNumberHex(const _U_UINT number, const char nibbles_to_print)
+{
+    _U_UINT nibble;
+    char nibbles = nibbles_to_print;
+    UNITY_OUTPUT_CHAR('0');
+    UNITY_OUTPUT_CHAR('x');
+
+    while (nibbles > 0)
+    {
+        nibble = (number >> (--nibbles << 2)) & 0x0000000F;
+        if (nibble <= 9)
+        {
+            UNITY_OUTPUT_CHAR((char)('0' + nibble));
+        }
+        else
+        {
+            UNITY_OUTPUT_CHAR((char)('A' - 10 + nibble));
+        }
+    }
+}
+
+/*-----------------------------------------------*/
+void UnityPrintMask(const _U_UINT mask, const _U_UINT number)
+{
+    _U_UINT current_bit = (_U_UINT)1 << (UNITY_INT_WIDTH - 1);
+    _US32 i;
+
+    for (i = 0; i < UNITY_INT_WIDTH; i++)
+    {
+        if (current_bit & mask)
+        {
+            if (current_bit & number)
+            {
+                UNITY_OUTPUT_CHAR('1');
+            }
+            else
+            {
+                UNITY_OUTPUT_CHAR('0');
+            }
+        }
+        else
+        {
+            UNITY_OUTPUT_CHAR('X');
+        }
+        current_bit = current_bit >> 1;
+    }
+}
+
+/*-----------------------------------------------*/
+#ifdef UNITY_FLOAT_VERBOSE
+#include <stdio.h>
+
+#ifndef UNITY_VERBOSE_NUMBER_MAX_LENGTH
+# ifdef UNITY_DOUBLE_VERBOSE
+#  define UNITY_VERBOSE_NUMBER_MAX_LENGTH 317
+# else
+#  define UNITY_VERBOSE_NUMBER_MAX_LENGTH 47
+# endif
+#endif
+
+void UnityPrintFloat(_UF number)
+{
+    char TempBuffer[UNITY_VERBOSE_NUMBER_MAX_LENGTH + 1];
+    snprintf(TempBuffer, sizeof(TempBuffer), "%.6f", number);
+    UnityPrint(TempBuffer);
+}
+#endif
+
+/*-----------------------------------------------*/
+
+void UnityPrintFail(void);
+void UnityPrintFail(void)
+{
+    UnityPrint(UnityStrFail);
+}
+
+void UnityPrintOk(void);
+void UnityPrintOk(void)
+{
+    UnityPrint(UnityStrOk);
+}
+
+/*-----------------------------------------------*/
+static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line);
+static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line)
+{
+#ifndef UNITY_FIXTURES
+    UnityPrint(file);
+    UNITY_OUTPUT_CHAR(':');
+    UnityPrintNumber((_U_SINT)line);
+    UNITY_OUTPUT_CHAR(':');
+    UnityPrint(Unity.CurrentTestName);
+    UNITY_OUTPUT_CHAR(':');
+#else
+    UNITY_UNUSED(file);
+    UNITY_UNUSED(line);
+#endif
+}
+
+/*-----------------------------------------------*/
+static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line);
+static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line)
+{
+#ifndef UNITY_FIXTURES
+    UnityTestResultsBegin(Unity.TestFile, line);
+#else
+    UNITY_UNUSED(line);
+#endif
+    UnityPrint(UnityStrFail);
+    UNITY_OUTPUT_CHAR(':');
+}
+
+/*-----------------------------------------------*/
+void UnityConcludeTest(void)
+{
+    if (Unity.CurrentTestIgnored)
+    {
+        Unity.TestIgnores++;
+    }
+    else if (!Unity.CurrentTestFailed)
+    {
+        UnityTestResultsBegin(Unity.TestFile, Unity.CurrentTestLineNumber);
+        UnityPrint(UnityStrPass);
+    }
+    else
+    {
+        Unity.TestFailures++;
+    }
+
+    Unity.CurrentTestFailed = 0;
+    Unity.CurrentTestIgnored = 0;
+    UNITY_PRINT_EOL();
+    UNITY_OUTPUT_FLUSH();
+}
+
+/*-----------------------------------------------*/
+static void UnityAddMsgIfSpecified(const char* msg);
+static void UnityAddMsgIfSpecified(const char* msg)
+{
+    if (msg)
+    {
+        UnityPrint(UnityStrSpacer);
+#ifndef UNITY_EXCLUDE_DETAILS
+        if (Unity.CurrentDetail1)
+        {
+            UnityPrint(UnityStrDetail1Name);
+            UnityPrint(Unity.CurrentDetail1);
+            if (Unity.CurrentDetail2)
+            {
+                UnityPrint(UnityStrDetail2Name);
+                UnityPrint(Unity.CurrentDetail2);
+            }
+            UnityPrint(UnityStrSpacer);
+        }
+#endif
+        UnityPrint(msg);
+    }
+}
+
+/*-----------------------------------------------*/
+static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual);
+static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual)
+{
+    UnityPrint(UnityStrExpected);
+    if (expected != NULL)
+    {
+        UNITY_OUTPUT_CHAR('\'');
+        UnityPrint(expected);
+        UNITY_OUTPUT_CHAR('\'');
+    }
+    else
+    {
+      UnityPrint(UnityStrNull);
+    }
+    UnityPrint(UnityStrWas);
+    if (actual != NULL)
+    {
+        UNITY_OUTPUT_CHAR('\'');
+        UnityPrint(actual);
+        UNITY_OUTPUT_CHAR('\'');
+    }
+    else
+    {
+      UnityPrint(UnityStrNull);
+    }
+}
+
+/*-----------------------------------------------*/
+static void UnityPrintExpectedAndActualStringsLen(const char* expected, const char* actual, const _UU32 length)
+{
+    UnityPrint(UnityStrExpected);
+    if (expected != NULL)
+    {
+        UNITY_OUTPUT_CHAR('\'');
+        UnityPrintLen(expected, length);
+        UNITY_OUTPUT_CHAR('\'');
+    }
+    else
+    {
+      UnityPrint(UnityStrNull);
+    }
+    UnityPrint(UnityStrWas);
+    if (actual != NULL)
+    {
+        UNITY_OUTPUT_CHAR('\'');
+        UnityPrintLen(actual, length);
+        UNITY_OUTPUT_CHAR('\'');
+    }
+    else
+    {
+      UnityPrint(UnityStrNull);
+    }
+}
+
+
+
+/*-----------------------------------------------
+ * Assertion & Control Helpers
+ *-----------------------------------------------*/
+
+static int UnityCheckArraysForNull(UNITY_INTERNAL_PTR expected, UNITY_INTERNAL_PTR actual, const UNITY_LINE_TYPE lineNumber, const char* msg)
+{
+    /* return true if they are both NULL */
+    if ((expected == NULL) && (actual == NULL))
+        return 1;
+
+    /* throw error if just expected is NULL */
+    if (expected == NULL)
+    {
+        UnityTestResultsFailBegin(lineNumber);
+        UnityPrint(UnityStrNullPointerForExpected);
+        UnityAddMsgIfSpecified(msg);
+        UNITY_FAIL_AND_BAIL;
+    }
+
+    /* throw error if just actual is NULL */
+    if (actual == NULL)
+    {
+        UnityTestResultsFailBegin(lineNumber);
+        UnityPrint(UnityStrNullPointerForActual);
+        UnityAddMsgIfSpecified(msg);
+        UNITY_FAIL_AND_BAIL;
+    }
+
+    /* return false if neither is NULL */
+    return 0;
+}
+
+/*-----------------------------------------------
+ * Assertion Functions
+ *-----------------------------------------------*/
+
+void UnityAssertBits(const _U_SINT mask,
+                     const _U_SINT expected,
+                     const _U_SINT actual,
+                     const char* msg,
+                     const UNITY_LINE_TYPE lineNumber)
+{
+    UNITY_SKIP_EXECUTION;
+
+    if ((mask & expected) != (mask & actual))
+    {
+        UnityTestResultsFailBegin(lineNumber);
+        UnityPrint(UnityStrExpected);
+        UnityPrintMask((_U_UINT)mask, (_U_UINT)expected);
+        UnityPrint(UnityStrWas);
+        UnityPrintMask((_U_UINT)mask, (_U_UINT)actual);
+        UnityAddMsgIfSpecified(msg);
+        UNITY_FAIL_AND_BAIL;
+    }
+}
+
+/*-----------------------------------------------*/
+void UnityAssertEqualNumber(const _U_SINT expected,
+                            const _U_SINT actual,
+                            const char* msg,
+                            const UNITY_LINE_TYPE lineNumber,
+                            const UNITY_DISPLAY_STYLE_T style)
+{
+    UNITY_SKIP_EXECUTION;
+
+    if (expected != actual)
+    {
+        UnityTestResultsFailBegin(lineNumber);
+        UnityPrint(UnityStrExpected);
+        UnityPrintNumberByStyle(expected, style);
+        UnityPrint(UnityStrWas);
+        UnityPrintNumberByStyle(actual, style);
+        UnityAddMsgIfSpecified(msg);
+        UNITY_FAIL_AND_BAIL;
+    }
+}
+
+#define UnityPrintPointlessAndBail()       \
+{                                          \
+    UnityTestResultsFailBegin(lineNumber); \
+    UnityPrint(UnityStrPointless);         \
+    UnityAddMsgIfSpecified(msg);           \
+    UNITY_FAIL_AND_BAIL; }
+
+/*-----------------------------------------------*/
+void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected,
+                              UNITY_INTERNAL_PTR actual,
+                              const _UU32 num_elements,
+                              const char* msg,
+                              const UNITY_LINE_TYPE lineNumber,
+                              const UNITY_DISPLAY_STYLE_T style)
+{
+    _UU32 elements = num_elements;
+    UNITY_INTERNAL_PTR ptr_exp = (UNITY_INTERNAL_PTR)expected;
+    UNITY_INTERNAL_PTR ptr_act = (UNITY_INTERNAL_PTR)actual;
+
+    UNITY_SKIP_EXECUTION;
+
+    if (elements == 0)
+    {
+        UnityPrintPointlessAndBail();
+    }
+
+    if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1)
+        return;
+
+    /* If style is UNITY_DISPLAY_STYLE_INT, we'll fall into the default case rather than the INT16 or INT32 (etc) case
+     * as UNITY_DISPLAY_STYLE_INT includes a flag for UNITY_DISPLAY_RANGE_AUTO, which the width-specific
+     * variants do not. Therefore remove this flag. */
+    switch(style & (UNITY_DISPLAY_STYLE_T)(~UNITY_DISPLAY_RANGE_AUTO))
+    {
+        case UNITY_DISPLAY_STYLE_HEX8:
+        case UNITY_DISPLAY_STYLE_INT8:
+        case UNITY_DISPLAY_STYLE_UINT8:
+            while (elements--)
+            {
+                if (*(UNITY_PTR_ATTRIBUTE const _US8*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US8*)ptr_act)
+                {
+                    UnityTestResultsFailBegin(lineNumber);
+                    UnityPrint(UnityStrElement);
+                    UnityPrintNumberUnsigned(num_elements - elements - 1);
+                    UnityPrint(UnityStrExpected);
+                    UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US8*)ptr_exp, style);
+                    UnityPrint(UnityStrWas);
+                    UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US8*)ptr_act, style);
+                    UnityAddMsgIfSpecified(msg);
+                    UNITY_FAIL_AND_BAIL;
+                }
+                ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 1);
+                ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 1);
+            }
+            break;
+        case UNITY_DISPLAY_STYLE_HEX16:
+        case UNITY_DISPLAY_STYLE_INT16:
+        case UNITY_DISPLAY_STYLE_UINT16:
+            while (elements--)
+            {
+                if (*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US16*)ptr_act)
+                {
+                    UnityTestResultsFailBegin(lineNumber);
+                    UnityPrint(UnityStrElement);
+                    UnityPrintNumberUnsigned(num_elements - elements - 1);
+                    UnityPrint(UnityStrExpected);
+                    UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_exp, style);
+                    UnityPrint(UnityStrWas);
+                    UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_act, style);
+                    UnityAddMsgIfSpecified(msg);
+                    UNITY_FAIL_AND_BAIL;
+                }
+                ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 2);
+                ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 2);
+            }
+            break;
+#ifdef UNITY_SUPPORT_64
+        case UNITY_DISPLAY_STYLE_HEX64:
+        case UNITY_DISPLAY_STYLE_INT64:
+        case UNITY_DISPLAY_STYLE_UINT64:
+            while (elements--)
+            {
+                if (*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US64*)ptr_act)
+                {
+                    UnityTestResultsFailBegin(lineNumber);
+                    UnityPrint(UnityStrElement);
+                    UnityPrintNumberUnsigned(num_elements - elements - 1);
+                    UnityPrint(UnityStrExpected);
+                    UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_exp, style);
+                    UnityPrint(UnityStrWas);
+                    UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_act, style);
+                    UnityAddMsgIfSpecified(msg);
+                    UNITY_FAIL_AND_BAIL;
+                }
+                ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 8);
+                ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 8);
+            }
+            break;
+#endif
+        default:
+            while (elements--)
+            {
+                if (*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US32*)ptr_act)
+                {
+                    UnityTestResultsFailBegin(lineNumber);
+                    UnityPrint(UnityStrElement);
+                    UnityPrintNumberUnsigned(num_elements - elements - 1);
+                    UnityPrint(UnityStrExpected);
+                    UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_exp, style);
+                    UnityPrint(UnityStrWas);
+                    UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_act, style);
+                    UnityAddMsgIfSpecified(msg);
+                    UNITY_FAIL_AND_BAIL;
+                }
+                ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 4);
+                ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 4);
+            }
+            break;
+    }
+}
+
+/*-----------------------------------------------*/
+#ifndef UNITY_EXCLUDE_FLOAT
+void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const _UF* expected,
+                                UNITY_PTR_ATTRIBUTE const _UF* actual,
+                                const _UU32 num_elements,
+                                const char* msg,
+                                const UNITY_LINE_TYPE lineNumber)
+{
+    _UU32 elements = num_elements;
+    UNITY_PTR_ATTRIBUTE const _UF* ptr_expected = expected;
+    UNITY_PTR_ATTRIBUTE const _UF* ptr_actual = actual;
+    _UF diff, tol;
+
+    UNITY_SKIP_EXECUTION;
+
+    if (elements == 0)
+    {
+        UnityPrintPointlessAndBail();
+    }
+
+    if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1)
+        return;
+
+    while (elements--)
+    {
+        diff = *ptr_expected - *ptr_actual;
+        if (diff < 0.0f)
+            diff = 0.0f - diff;
+        tol = UNITY_FLOAT_PRECISION * *ptr_expected;
+        if (tol < 0.0f)
+            tol = 0.0f - tol;
+
+        /* This first part of this condition will catch any NaN or Infinite values */
+        if (isnan(diff) || isinf(diff) || (diff > tol))
+        {
+            UnityTestResultsFailBegin(lineNumber);
+            UnityPrint(UnityStrElement);
+            UnityPrintNumberUnsigned(num_elements - elements - 1);
+#ifdef UNITY_FLOAT_VERBOSE
+            UnityPrint(UnityStrExpected);
+            UnityPrintFloat(*ptr_expected);
+            UnityPrint(UnityStrWas);
+            UnityPrintFloat(*ptr_actual);
+#else
+            UnityPrint(UnityStrDelta);
+#endif
+            UnityAddMsgIfSpecified(msg);
+            UNITY_FAIL_AND_BAIL;
+        }
+        ptr_expected++;
+        ptr_actual++;
+    }
+}
+
+/*-----------------------------------------------*/
+void UnityAssertFloatsWithin(const _UF delta,
+                             const _UF expected,
+                             const _UF actual,
+                             const char* msg,
+                             const UNITY_LINE_TYPE lineNumber)
+{
+    _UF diff = actual - expected;
+    _UF pos_delta = delta;
+
+    UNITY_SKIP_EXECUTION;
+
+    if (diff < 0.0f)
+    {
+        diff = 0.0f - diff;
+    }
+    if (pos_delta < 0.0f)
+    {
+        pos_delta = 0.0f - pos_delta;
+    }
+
+    /* This first part of this condition will catch any NaN or Infinite values */
+    if (isnan(diff) || isinf(diff) || (pos_delta < diff))
+    {
+        UnityTestResultsFailBegin(lineNumber);
+#ifdef UNITY_FLOAT_VERBOSE
+        UnityPrint(UnityStrExpected);
+        UnityPrintFloat(expected);
+        UnityPrint(UnityStrWas);
+        UnityPrintFloat(actual);
+#else
+        UnityPrint(UnityStrDelta);
+#endif
+        UnityAddMsgIfSpecified(msg);
+        UNITY_FAIL_AND_BAIL;
+    }
+}
+
+/*-----------------------------------------------*/
+void UnityAssertFloatSpecial(const _UF actual,
+                             const char* msg,
+                             const UNITY_LINE_TYPE lineNumber,
+                             const UNITY_FLOAT_TRAIT_T style)
+{
+    const char* trait_names[] = { UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet };
+    _U_SINT should_be_trait   = ((_U_SINT)style & 1);
+    _U_SINT is_trait          = !should_be_trait;
+    _U_SINT trait_index       = (_U_SINT)(style >> 1);
+
+    UNITY_SKIP_EXECUTION;
+
+    switch(style)
+    {
+        /* To determine Inf / Neg Inf, we compare to an Inf / Neg Inf value we create on the fly
+         * We are using a variable to hold the zero value because some compilers complain about dividing by zero otherwise */
+        case UNITY_FLOAT_IS_INF:
+        case UNITY_FLOAT_IS_NOT_INF:
+            is_trait = isinf(actual) & ispos(actual);
+            break;
+        case UNITY_FLOAT_IS_NEG_INF:
+        case UNITY_FLOAT_IS_NOT_NEG_INF:
+            is_trait = isinf(actual) & isneg(actual);
+            break;
+
+        /* NaN is the only floating point value that does NOT equal itself. Therefore if Actual == Actual, then it is NOT NaN. */
+        case UNITY_FLOAT_IS_NAN:
+        case UNITY_FLOAT_IS_NOT_NAN:
+            is_trait = isnan(actual);
+            break;
+
+        /* A determinate number is non infinite and not NaN. (therefore the opposite of the two above) */
+        case UNITY_FLOAT_IS_DET:
+        case UNITY_FLOAT_IS_NOT_DET:
+            if (isinf(actual) | isnan(actual))
+                is_trait = 0;
+            else
+                is_trait = 1;
+            break;
+
+        default:
+            trait_index = 0;
+            trait_names[0] = UnityStrInvalidFloatTrait;
+            break;
+    }
+
+    if (is_trait != should_be_trait)
+    {
+        UnityTestResultsFailBegin(lineNumber);
+        UnityPrint(UnityStrExpected);
+        if (!should_be_trait)
+            UnityPrint(UnityStrNot);
+        UnityPrint(trait_names[trait_index]);
+        UnityPrint(UnityStrWas);
+#ifdef UNITY_FLOAT_VERBOSE
+        UnityPrintFloat(actual);
+#else
+        if (should_be_trait)
+            UnityPrint(UnityStrNot);
+        UnityPrint(trait_names[trait_index]);
+#endif
+        UnityAddMsgIfSpecified(msg);
+        UNITY_FAIL_AND_BAIL;
+    }
+}
+
+#endif /* not UNITY_EXCLUDE_FLOAT */
+
+/*-----------------------------------------------*/
+#ifndef UNITY_EXCLUDE_DOUBLE
+void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const _UD* expected,
+                                 UNITY_PTR_ATTRIBUTE const _UD* actual,
+                                 const _UU32 num_elements,
+                                 const char* msg,
+                                 const UNITY_LINE_TYPE lineNumber)
+{
+    _UU32 elements = num_elements;
+    UNITY_PTR_ATTRIBUTE const _UD* ptr_expected = expected;
+    UNITY_PTR_ATTRIBUTE const _UD* ptr_actual = actual;
+    _UD diff, tol;
+
+    UNITY_SKIP_EXECUTION;
+
+    if (elements == 0)
+    {
+        UnityPrintPointlessAndBail();
+    }
+
+    if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1)
+        return;
+
+    while (elements--)
+    {
+        diff = *ptr_expected - *ptr_actual;
+        if (diff < 0.0)
+          diff = 0.0 - diff;
+        tol = UNITY_DOUBLE_PRECISION * *ptr_expected;
+        if (tol < 0.0)
+            tol = 0.0 - tol;
+
+        /* This first part of this condition will catch any NaN or Infinite values */
+        if (isnan(diff) || isinf(diff) || (diff > tol))
+        {
+            UnityTestResultsFailBegin(lineNumber);
+            UnityPrint(UnityStrElement);
+            UnityPrintNumberUnsigned(num_elements - elements - 1);
+#ifdef UNITY_DOUBLE_VERBOSE
+            UnityPrint(UnityStrExpected);
+            UnityPrintFloat((float)(*ptr_expected));
+            UnityPrint(UnityStrWas);
+            UnityPrintFloat((float)(*ptr_actual));
+#else
+            UnityPrint(UnityStrDelta);
+#endif
+            UnityAddMsgIfSpecified(msg);
+            UNITY_FAIL_AND_BAIL;
+        }
+        ptr_expected++;
+        ptr_actual++;
+    }
+}
+
+/*-----------------------------------------------*/
+void UnityAssertDoublesWithin(const _UD delta,
+                              const _UD expected,
+                              const _UD actual,
+                              const char* msg,
+                              const UNITY_LINE_TYPE lineNumber)
+{
+    _UD diff = actual - expected;
+    _UD pos_delta = delta;
+
+    UNITY_SKIP_EXECUTION;
+
+    if (diff < 0.0)
+    {
+        diff = 0.0 - diff;
+    }
+    if (pos_delta < 0.0)
+    {
+        pos_delta = 0.0 - pos_delta;
+    }
+
+    /* This first part of this condition will catch any NaN or Infinite values */
+    if (isnan(diff) || isinf(diff) || (pos_delta < diff))
+    {
+        UnityTestResultsFailBegin(lineNumber);
+#ifdef UNITY_DOUBLE_VERBOSE
+        UnityPrint(UnityStrExpected);
+        UnityPrintFloat((float)expected);
+        UnityPrint(UnityStrWas);
+        UnityPrintFloat((float)actual);
+#else
+        UnityPrint(UnityStrDelta);
+#endif
+        UnityAddMsgIfSpecified(msg);
+        UNITY_FAIL_AND_BAIL;
+    }
+}
+
+/*-----------------------------------------------*/
+
+void UnityAssertDoubleSpecial(const _UD actual,
+                              const char* msg,
+                              const UNITY_LINE_TYPE lineNumber,
+                              const UNITY_FLOAT_TRAIT_T style)
+{
+    const char* trait_names[] = { UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet };
+    _U_SINT should_be_trait   = ((_U_SINT)style & 1);
+    _U_SINT is_trait          = !should_be_trait;
+    _U_SINT trait_index       = (_U_SINT)(style >> 1);
+
+    UNITY_SKIP_EXECUTION;
+
+     switch(style)
+    {
+        /* To determine Inf / Neg Inf, we compare to an Inf / Neg Inf value we create on the fly
+         * We are using a variable to hold the zero value because some compilers complain about dividing by zero otherwise */
+        case UNITY_FLOAT_IS_INF:
+        case UNITY_FLOAT_IS_NOT_INF:
+            is_trait = isinf(actual) & ispos(actual);
+            break;
+        case UNITY_FLOAT_IS_NEG_INF:
+        case UNITY_FLOAT_IS_NOT_NEG_INF:
+            is_trait = isinf(actual) & isneg(actual);
+            break;
+
+        /* NaN is the only floating point value that does NOT equal itself. Therefore if Actual == Actual, then it is NOT NaN. */
+        case UNITY_FLOAT_IS_NAN:
+        case UNITY_FLOAT_IS_NOT_NAN:
+            is_trait = isnan(actual);
+            break;
+
+        /* A determinate number is non infinite and not NaN. (therefore the opposite of the two above) */
+        case UNITY_FLOAT_IS_DET:
+        case UNITY_FLOAT_IS_NOT_DET:
+            if (isinf(actual) | isnan(actual))
+                is_trait = 0;
+            else
+                is_trait = 1;
+            break;
+
+        default:
+            trait_index = 0;
+            trait_names[0] = UnityStrInvalidFloatTrait;
+            break;
+    }
+
+    if (is_trait != should_be_trait)
+    {
+        UnityTestResultsFailBegin(lineNumber);
+        UnityPrint(UnityStrExpected);
+        if (!should_be_trait)
+            UnityPrint(UnityStrNot);
+        UnityPrint(trait_names[trait_index]);
+        UnityPrint(UnityStrWas);
+#ifdef UNITY_DOUBLE_VERBOSE
+        UnityPrintFloat(actual);
+#else
+        if (should_be_trait)
+            UnityPrint(UnityStrNot);
+        UnityPrint(trait_names[trait_index]);
+#endif
+        UnityAddMsgIfSpecified(msg);
+        UNITY_FAIL_AND_BAIL;
+    }
+}
+
+
+#endif /* not UNITY_EXCLUDE_DOUBLE */
+
+/*-----------------------------------------------*/
+void UnityAssertNumbersWithin( const _U_UINT delta,
+                               const _U_SINT expected,
+                               const _U_SINT actual,
+                               const char* msg,
+                               const UNITY_LINE_TYPE lineNumber,
+                               const UNITY_DISPLAY_STYLE_T style)
+{
+    UNITY_SKIP_EXECUTION;
+
+    if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT)
+    {
+        if (actual > expected)
+            Unity.CurrentTestFailed = ((_U_UINT)(actual - expected) > delta);
+        else
+            Unity.CurrentTestFailed = ((_U_UINT)(expected - actual) > delta);
+    }
+    else
+    {
+        if ((_U_UINT)actual > (_U_UINT)expected)
+            Unity.CurrentTestFailed = ((_U_UINT)(actual - expected) > delta);
+        else
+            Unity.CurrentTestFailed = ((_U_UINT)(expected - actual) > delta);
+    }
+
+    if (Unity.CurrentTestFailed)
+    {
+        UnityTestResultsFailBegin(lineNumber);
+        UnityPrint(UnityStrDelta);
+        UnityPrintNumberByStyle((_U_SINT)delta, style);
+        UnityPrint(UnityStrExpected);
+        UnityPrintNumberByStyle(expected, style);
+        UnityPrint(UnityStrWas);
+        UnityPrintNumberByStyle(actual, style);
+        UnityAddMsgIfSpecified(msg);
+        UNITY_FAIL_AND_BAIL;
+    }
+}
+
+/*-----------------------------------------------*/
+void UnityAssertEqualString(const char* expected,
+                            const char* actual,
+                            const char* msg,
+                            const UNITY_LINE_TYPE lineNumber)
+{
+    _UU32 i;
+
+    UNITY_SKIP_EXECUTION;
+
+    /* if both pointers not null compare the strings */
+    if (expected && actual)
+    {
+        for (i = 0; expected[i] || actual[i]; i++)
+        {
+            if (expected[i] != actual[i])
+            {
+                Unity.CurrentTestFailed = 1;
+                break;
+            }
+        }
+    }
+    else
+    { /* handle case of one pointers being null (if both null, test should pass) */
+        if (expected != actual)
+        {
+            Unity.CurrentTestFailed = 1;
+        }
+    }
+
+    if (Unity.CurrentTestFailed)
+    {
+      UnityTestResultsFailBegin(lineNumber);
+      UnityPrintExpectedAndActualStrings(expected, actual);
+      UnityAddMsgIfSpecified(msg);
+      UNITY_FAIL_AND_BAIL;
+    }
+}
+
+/*-----------------------------------------------*/
+void UnityAssertEqualStringLen(const char* expected,
+                            const char* actual,
+                            const _UU32 length,
+                            const char* msg,
+                            const UNITY_LINE_TYPE lineNumber)
+{
+    _UU32 i;
+
+    UNITY_SKIP_EXECUTION;
+
+    /* if both pointers not null compare the strings */
+    if (expected && actual)
+    {
+        for (i = 0; (expected[i] || actual[i]) && i < length; i++)
+        {
+            if (expected[i] != actual[i])
+            {
+                Unity.CurrentTestFailed = 1;
+                break;
+            }
+        }
+    }
+    else
+    { /* handle case of one pointers being null (if both null, test should pass) */
+        if (expected != actual)
+        {
+            Unity.CurrentTestFailed = 1;
+        }
+    }
+
+    if (Unity.CurrentTestFailed)
+    {
+      UnityTestResultsFailBegin(lineNumber);
+      UnityPrintExpectedAndActualStringsLen(expected, actual, length);
+      UnityAddMsgIfSpecified(msg);
+      UNITY_FAIL_AND_BAIL;
+    }
+}
+
+
+/*-----------------------------------------------*/
+void UnityAssertEqualStringArray( const char** expected,
+                                  const char** actual,
+                                  const _UU32 num_elements,
+                                  const char* msg,
+                                  const UNITY_LINE_TYPE lineNumber)
+{
+    _UU32 i, j = 0;
+
+    UNITY_SKIP_EXECUTION;
+
+    /* if no elements, it's an error */
+    if (num_elements == 0)
+    {
+        UnityPrintPointlessAndBail();
+    }
+
+    if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1)
+        return;
+
+    do
+    {
+        /* if both pointers not null compare the strings */
+        if (expected[j] && actual[j])
+        {
+            for (i = 0; expected[j][i] || actual[j][i]; i++)
+            {
+                if (expected[j][i] != actual[j][i])
+                {
+                    Unity.CurrentTestFailed = 1;
+                    break;
+                }
+            }
+        }
+        else
+        { /* handle case of one pointers being null (if both null, test should pass) */
+            if (expected[j] != actual[j])
+            {
+                Unity.CurrentTestFailed = 1;
+            }
+        }
+
+        if (Unity.CurrentTestFailed)
+        {
+            UnityTestResultsFailBegin(lineNumber);
+            if (num_elements > 1)
+            {
+                UnityPrint(UnityStrElement);
+                UnityPrintNumberUnsigned(j);
+            }
+            UnityPrintExpectedAndActualStrings((const char*)(expected[j]), (const char*)(actual[j]));
+            UnityAddMsgIfSpecified(msg);
+            UNITY_FAIL_AND_BAIL;
+        }
+    } while (++j < num_elements);
+}
+
+/*-----------------------------------------------*/
+void UnityAssertEqualMemory( UNITY_INTERNAL_PTR expected,
+                             UNITY_INTERNAL_PTR actual,
+                             const _UU32 length,
+                             const _UU32 num_elements,
+                             const char* msg,
+                             const UNITY_LINE_TYPE lineNumber)
+{
+    UNITY_PTR_ATTRIBUTE const unsigned char* ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected;
+    UNITY_PTR_ATTRIBUTE const unsigned char* ptr_act = (UNITY_PTR_ATTRIBUTE const unsigned char*)actual;
+    _UU32 elements = num_elements;
+    _UU32 bytes;
+
+    UNITY_SKIP_EXECUTION;
+
+    if ((elements == 0) || (length == 0))
+    {
+        UnityPrintPointlessAndBail();
+    }
+
+    if (UnityCheckArraysForNull((UNITY_INTERNAL_PTR)expected, (UNITY_INTERNAL_PTR)actual, lineNumber, msg) == 1)
+        return;
+
+    while (elements--)
+    {
+        /* /////////////////////////////////// */
+        bytes = length;
+        while (bytes--)
+        {
+            if (*ptr_exp != *ptr_act)
+            {
+                UnityTestResultsFailBegin(lineNumber);
+                UnityPrint(UnityStrMemory);
+                if (num_elements > 1)
+                {
+                    UnityPrint(UnityStrElement);
+                    UnityPrintNumberUnsigned(num_elements - elements - 1);
+                }
+                UnityPrint(UnityStrByte);
+                UnityPrintNumberUnsigned(length - bytes - 1);
+                UnityPrint(UnityStrExpected);
+                UnityPrintNumberByStyle(*ptr_exp, UNITY_DISPLAY_STYLE_HEX8);
+                UnityPrint(UnityStrWas);
+                UnityPrintNumberByStyle(*ptr_act, UNITY_DISPLAY_STYLE_HEX8);
+                UnityAddMsgIfSpecified(msg);
+                UNITY_FAIL_AND_BAIL;
+            }
+            ptr_exp = (UNITY_INTERNAL_PTR)((_UP)ptr_exp + 1);
+            ptr_act = (UNITY_INTERNAL_PTR)((_UP)ptr_act + 1);
+        }
+        /* /////////////////////////////////// */
+
+    }
+}
+
+/*-----------------------------------------------
+ * Control Functions
+ *-----------------------------------------------*/
+
+void UnityFail(const char* msg, const UNITY_LINE_TYPE line)
+{
+    UNITY_SKIP_EXECUTION;
+
+    UnityTestResultsBegin(Unity.TestFile, line);
+    UnityPrintFail();
+    if (msg != NULL)
+    {
+        UNITY_OUTPUT_CHAR(':');
+
+#ifndef UNITY_EXCLUDE_DETAILS
+        if (Unity.CurrentDetail1)
+        {
+            UnityPrint(UnityStrDetail1Name);
+            UnityPrint(Unity.CurrentDetail1);
+            if (Unity.CurrentDetail2)
+            {
+                UnityPrint(UnityStrDetail2Name);
+                UnityPrint(Unity.CurrentDetail2);
+            }
+            UnityPrint(UnityStrSpacer);
+        }
+#endif
+        if (msg[0] != ' ')
+        {
+            UNITY_OUTPUT_CHAR(' ');
+        }
+        UnityPrint(msg);
+    }
+
+    UNITY_FAIL_AND_BAIL;
+}
+
+/*-----------------------------------------------*/
+void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line)
+{
+    UNITY_SKIP_EXECUTION;
+
+    UnityTestResultsBegin(Unity.TestFile, line);
+    UnityPrint(UnityStrIgnore);
+    if (msg != NULL)
+    {
+      UNITY_OUTPUT_CHAR(':');
+      UNITY_OUTPUT_CHAR(' ');
+      UnityPrint(msg);
+    }
+    UNITY_IGNORE_AND_BAIL;
+}
+
+/*-----------------------------------------------*/
+#if defined(UNITY_WEAK_ATTRIBUTE)
+    UNITY_WEAK_ATTRIBUTE void setUp(void) { }
+    UNITY_WEAK_ATTRIBUTE void tearDown(void) { }
+#elif defined(UNITY_WEAK_PRAGMA)
+#   pragma weak setUp
+    void setUp(void) { }
+#   pragma weak tearDown
+    void tearDown(void) { }
+#endif
+/*-----------------------------------------------*/
+void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum)
+{
+    Unity.CurrentTestName = FuncName;
+    Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum;
+    Unity.NumberOfTests++;
+    UNITY_CLR_DETAILS();
+    if (TEST_PROTECT())
+    {
+        setUp();
+        Func();
+    }
+    if (TEST_PROTECT() && !(Unity.CurrentTestIgnored))
+    {
+        tearDown();
+    }
+    UnityConcludeTest();
+}
+
+/*-----------------------------------------------*/
+void UnityBegin(const char* filename)
+{
+    Unity.TestFile = filename;
+    Unity.CurrentTestName = NULL;
+    Unity.CurrentTestLineNumber = 0;
+    Unity.NumberOfTests = 0;
+    Unity.TestFailures = 0;
+    Unity.TestIgnores = 0;
+    Unity.CurrentTestFailed = 0;
+    Unity.CurrentTestIgnored = 0;
+
+    UNITY_CLR_DETAILS();
+    UNITY_OUTPUT_START();
+}
+
+/*-----------------------------------------------*/
+int UnityEnd(void)
+{
+    UNITY_PRINT_EOL();
+    UnityPrint(UnityStrBreaker);
+    UNITY_PRINT_EOL();
+    UnityPrintNumber((_U_SINT)(Unity.NumberOfTests));
+    UnityPrint(UnityStrResultsTests);
+    UnityPrintNumber((_U_SINT)(Unity.TestFailures));
+    UnityPrint(UnityStrResultsFailures);
+    UnityPrintNumber((_U_SINT)(Unity.TestIgnores));
+    UnityPrint(UnityStrResultsIgnored);
+    UNITY_PRINT_EOL();
+    if (Unity.TestFailures == 0U)
+    {
+        UnityPrintOk();
+    }
+    else
+    {
+        UnityPrintFail();
+#ifdef UNITY_DIFFERENTIATE_FINAL_FAIL
+        UNITY_OUTPUT_CHAR('E'); UNITY_OUTPUT_CHAR('D');
+#endif
+    }
+    UNITY_PRINT_EOL();
+    UNITY_OUTPUT_FLUSH();
+    UNITY_OUTPUT_COMPLETE();
+    return (int)(Unity.TestFailures);
+}
+
+/*-----------------------------------------------*/

+ 165 - 0
tools/unit-test-app/components/unity/unity_platform.c

@@ -0,0 +1,165 @@
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "unity.h"
+#include "rom/ets_sys.h"
+
+#define unity_printf ets_printf
+
+// Functions which are defined in ROM, linker script provides addresses for these:
+int uart_tx_one_char(uint8_t c);
+void uart_tx_wait_idle(uint8_t uart_no);
+int UartRxString(uint8_t* dst, uint8_t max_length);
+
+// Pointers to the head and tail of linked list of test description structs:
+static struct test_desc_t* s_unity_tests_first = NULL;
+static struct test_desc_t* s_unity_tests_last = NULL;
+
+
+void unity_putc(int c)
+{
+    if (c == '\n') 
+    {
+        uart_tx_one_char('\n');
+        uart_tx_one_char('\r');
+    }
+    else if (c == '\r') 
+    {
+    }
+    else 
+    {
+        uart_tx_one_char(c);
+    }
+}
+
+void unity_flush()
+{
+    uart_tx_wait_idle(0);   // assume that output goes to UART0
+}
+
+void unity_testcase_register(struct test_desc_t* desc)
+{
+    if (!s_unity_tests_first) 
+    {
+        s_unity_tests_first = desc;
+    }
+    else 
+    {
+        s_unity_tests_last->next = desc;
+    }
+    s_unity_tests_last = desc;
+    desc->next = NULL;
+}
+
+static void unity_run_single_test(const struct test_desc_t* test)
+{
+    Unity.TestFile = test->file;
+    Unity.CurrentDetail1 = test->desc;
+    UnityDefaultTestRun(test->fn, test->name, test->line);
+}
+
+static void unity_run_single_test_by_index(int index)
+{
+    const struct test_desc_t* test;
+    for (test = s_unity_tests_first; test != NULL && index != 0; test = test->next, --index)
+    {
+    }
+    if (test != NULL)
+    {
+        unity_run_single_test(test);
+    }
+    
+}
+
+static void unity_run_single_test_by_name(const char* filter)
+{  
+    char tmp[256];
+    strncpy(tmp, filter + 1, sizeof(tmp) - 1);
+    tmp[strlen(filter) - 2] = 0;
+    for (const struct test_desc_t* test = s_unity_tests_first; test != NULL; test = test->next)
+    {
+        if (strstr(test->name, tmp) != NULL)
+        {
+            unity_run_single_test(test);
+        }
+    }    
+}
+
+void unity_run_all_tests()
+{
+    for (const struct test_desc_t* test = s_unity_tests_first; test != NULL; test = test->next)
+    {
+        unity_run_single_test(test);
+    }
+}
+
+void unity_run_tests_with_filter(const char* filter)
+{
+    for (const struct test_desc_t* test = s_unity_tests_first; test != NULL; test = test->next)
+    {
+        if (strstr(test->desc, filter) != NULL)
+        {
+            unity_run_single_test(test);
+        }
+    }
+}
+
+static void trim_trailing_space(char* str)
+{
+    char* end = str + strlen(str) - 1;
+    while (end >= str && isspace((int) *end))
+    {
+        *end = 0;
+        --end;
+    }
+}
+
+void unity_run_menu()
+{
+    while (true) 
+    {
+        int test_counter = 0;
+        unity_printf("\n\nHere's the test menu, pick your combo:\n");
+        for (const struct test_desc_t* test = s_unity_tests_first; 
+             test != NULL; 
+             test = test->next, ++test_counter)
+        {
+            unity_printf("(%d)\t\"%s\" %s\n", test_counter + 1, test->name, test->desc);
+        }
+        
+        char cmdline[256];
+        UartRxString((uint8_t*) cmdline, sizeof(cmdline) - 1);
+        trim_trailing_space(cmdline);
+
+        if (strlen(cmdline) == 0)
+        {
+            continue;
+        }
+    
+        UNITY_BEGIN();
+        
+        if (cmdline[0] == '*') 
+        {
+            unity_run_all_tests();
+        }
+        else if (cmdline[0] =='[') 
+        {
+            unity_run_tests_with_filter(cmdline);
+        }
+        else if (cmdline[0] =='"')
+        {
+            unity_run_single_test_by_name(cmdline);
+        }
+        else 
+        {
+            int test_index = strtol(cmdline, NULL, 10);
+            if (test_index >= 1 && test_index <= test_counter)
+            {
+                unity_run_single_test_by_index(test_index - 1);
+            }
+        }
+
+        UNITY_END();
+    }
+}
+

+ 18 - 0
tools/unit-test-app/main/app_main.c

@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "unity.h"
+
+
+void unityTask(void *pvParameters) 
+{
+    vTaskDelay(1000 / portTICK_PERIOD_MS);
+    unity_run_menu();
+    while(1);
+}
+
+void app_main() 
+{
+    xTaskCreatePinnedToCore(unityTask, "unityTask", 4096, NULL, 5, NULL, 0);
+}
+

+ 5 - 0
tools/unit-test-app/main/component.mk

@@ -0,0 +1,5 @@
+#
+# Main Makefile. This is basically the same as a component makefile.
+#
+
+include $(IDF_PATH)/make/component_common.mk

+ 125 - 0
tools/unit-test-app/sdkconfig

@@ -0,0 +1,125 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Espressif IoT Development Framework Configuration
+#
+
+#
+# SDK tool configuration
+#
+CONFIG_TOOLPREFIX="xtensa-esp32-elf-"
+CONFIG_PYTHON="python"
+
+#
+# Serial flasher config
+#
+CONFIG_ESPTOOLPY_PORT="/dev/ttyUSB0"
+# CONFIG_ESPTOOLPY_BAUD_115200B is not set
+# CONFIG_ESPTOOLPY_BAUD_230400B is not set
+CONFIG_ESPTOOLPY_BAUD_921600B=y
+# CONFIG_ESPTOOLPY_BAUD_2MB is not set
+# CONFIG_ESPTOOLPY_BAUD_OTHER is not set
+CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
+CONFIG_ESPTOOLPY_BAUD=921600
+CONFIG_ESPTOOLPY_COMPRESSED=y
+# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
+# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE="dio"
+# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
+# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ="40m"
+
+#
+# Partition Table
+#
+CONFIG_PARTITION_TABLE_SINGLE_APP=y
+# CONFIG_PARTITION_TABLE_TWO_OTA is not set
+# CONFIG_PARTITION_TABLE_CUSTOM is not set
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
+CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
+CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
+CONFIG_APP_OFFSET=0x10000
+
+#
+# Component config
+#
+
+#
+# ESP32-specific config
+#
+# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set
+# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set
+CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
+CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
+# CONFIG_ESP32_ENABLE_STACK_WIFI is not set
+# CONFIG_ESP32_ENABLE_STACK_BT is not set
+CONFIG_ESP32_ENABLE_STACK_NONE=y
+CONFIG_MEMMAP_SMP=y
+# CONFIG_MEMMAP_TRACEMEM is not set
+# CONFIG_MEMMAP_SPISRAM is not set
+CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2048
+CONFIG_MAIN_TASK_STACK_SIZE=4096
+CONFIG_NEWLIB_STDOUT_ADDCR=y
+
+#
+# FreeRTOS
+#
+# CONFIG_FREERTOS_UNICORE is not set
+CONFIG_FREERTOS_CORETIMER_0=y
+# CONFIG_FREERTOS_CORETIMER_1 is not set
+# CONFIG_FREERTOS_CORETIMER_2 is not set
+CONFIG_FREERTOS_HZ=1000
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
+CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=3
+# CONFIG_FREERTOS_PANIC_PRINT_HALT is not set
+CONFIG_FREERTOS_PANIC_PRINT_REBOOT=y
+# CONFIG_FREERTOS_PANIC_SILENT_REBOOT is not set
+# CONFIG_FREERTOS_PANIC_GDBSTUB is not set
+CONFIG_FREERTOS_DEBUG_OCDAWARE=y
+CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
+# CONFIG_FREERTOS_ASSERT_DISABLE is not set
+CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG=y
+# CONFIG_ENABLE_MEMORY_DEBUG is not set
+# CONFIG_FREERTOS_DEBUG_INTERNALS is not set
+
+#
+# Log output
+#
+# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
+# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
+# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
+CONFIG_LOG_DEFAULT_LEVEL_INFO=y
+# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
+# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
+CONFIG_LOG_DEFAULT_LEVEL=3
+CONFIG_LOG_COLORS=y
+
+#
+# LWIP
+#
+CONFIG_LWIP_MAX_SOCKETS=4
+CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX=0
+# CONFIG_LWIP_SO_REUSE is not set
+
+#
+# mbedTLS
+#
+CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384
+# CONFIG_MBEDTLS_DEBUG is not set
+
+#
+# SPI Flash driver
+#
+# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
+
+#
+# TESTS
+#
+CONFIG_FP_TEST_ENABLE=y