[
  {
    "path": ".gitignore",
    "content": "/Debug\r\n/.vs\r\n*.bak\r\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\r\n\r\nCopyright (c) 2018-2022 nqtronix (github.com/nqtronix)\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n"
  },
  {
    "path": "README.md",
    "content": "\t\t\n<h1 align=\"center\" style=\"font-weight: bold; margin-top: 20px; margin-bottom: 20px;\">fifofast</h4>\n\n<h3 align=\"center\" style=\"font-weight: bold; margin-top: 20px; margin-bottom: 20px;\">A fast, generic fifo for MCUs.</h4>\n\n<p align=\"center\">\n<a href=\"#changelog\"><img src=\"https://img.shields.io/github/release-pre/nqtronix/fifofast.svg\" alt=\"release: NA\"></a>\n<a href=\"#about\"><img src=\"https://img.shields.io/badge/language-C_(GCC_5.4.0)-blue.svg\" alt=\"language: C GCC (5.4.0)\"></a>\n<a href=\"#about\"><img src=\"https://img.shields.io/badge/platform-MCUs, AVR8-blue.svg\" alt=\"platform: MCUs, AVR8\"></a>\n<a href=\"#about\"><img src=\"https://img.shields.io/badge/status-active-brightgreen.svg\" alt=\"status: active\"></a>\n<a href=\"https://github.com/nqtronix/fifofast/issues\"><img src=\"https://img.shields.io/github/issues/nqtronix/fifofast.svg\" alt=\"issues: NA\"></a>\n<a href=\"#license\"><img src=\"https://img.shields.io/github/license/nqtronix/fifofast.svg\" alt=\"license: NA\"></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"#getting-started\">Getting Started</a> •\n  <a href=\"#documentation\">Documentation</a> •\n  <a href=\"#under-the-hood\">Under the Hood</a> •\n  <a href=\"#support\">Need Help?</a> •\n  <a href=\"#contribute\">Contribute</a> •\n  <a href=\"#about\">About</a> •\n  <a href=\"#credits\">Credits</a>\n</p>\n\n\n## Introduction\nFirst-In-First-Out (FIFO) buffers are one of the most used data structures, especially on micro controllers (MCUs) to handle data input/output in real time. Although there are countless of implementations, there wasn't a single one that is well optimized for entry level MCUs.\n\n**fifofast** was specifically designed to consume as little CPU time and SRAM as possible, while providing more versatility and features than typical implementations. It is ideally suited to buffer serial data, ADC measurement results or arbitrary data shared between differnt time critical functions.\n\n<br>\n\n## Key Features\n - **generic data:** fifofast supports **_any_** data type, even custom typedef'd ones\n - **static memory:** no additional overhead through dynamic memory management\n - **inline support:** speeds up execution, especially from ISRs (Interrupt Service Routines)\n - **minimal RAM:** a typical fifo has only **3 _byte_** management overhead\n - **easy to use:** all typical fifo functions are implemented (and they work like you expect)\n - **supports debugging:** with the build-in debugger of Atmel Studio 7\n - **well documented:** extensive use of comments within the source code\n\n<br>\n\n## Limititations\n- **Fifo size:**<br>\n  The fifo size is limited to 2ⁿ elements to make use of the fast wrapping functionality. Other sizes will be automatically rounded up.\n  \n- **Element size:**<br>\n  Normal fifos can store elements of any size. An exception are point-able fifos, which have a maximum element size of 255 bytes.\n   \n- **Programm memory usage:**<br>\n  Each function-like macro or inline function pastes new code at its location. Compared to a regular function-based fifo the program memory usage (flash) is higher.\n\n<br>\n\n## Minimal Code Example\nThe declaration of a fifo is slightly different to support generic types, but they are accessed just like you'd expect. This is the minimum code example that can be compiled:\n\n```c\n#include \"fifofast.h\"\n\n// declare a fifo with 16 elements of type 'int_8' with the name 'fifo_int8';\n// for access in other .c files, move the declaration into a .h file and include it in each .c file\n_fff_declare(int8_t, fifo_int8, 16);\n\n// initialize the fifo; use this macro only in one .c file (even if accessed from different files)\n_fff_init(fifo_int8);\n\nint main(void)\n{\n    // volatile prevents the compiler from optimizing the variable away\n    volatile int8_t tmp;\n    \n    // write a value to the fifo\n    _fff_write(fifo_int8, -42);\n\n    // read back the value from the fifo\n    tmp = _fff_read(fifo_int8);\n\n    // 'tmp' contains now the value '-42'\n    while(1);\n}\n```\n\nYou find this a variation of this snippet and much more in [`fifofast_test.c`](fifofast_test.c).\n\n<br>\n\n## Getting Started\nThis section is written especially for everyone who is **not familiar** with the used tools. If you run into problems, please [ask for clarification](#get-help).<br>\n\n### Step 1: Software and Tools\n - [**Atmel Studio 7.0**][tool-atmel-studio-7-0] **(Build 1931) [free]**<br>\n   The installer contains all tools you need to open, edit, compile, simulate and flash this code. If you favor another development tool, feel free to use it instead. (But please understand that I can not provide any support).\n - **An AVR8 ISP/JTAG programmer [optional]**<br>\n   To program AVR8 MCUs I use the [AVR Dragon][tool-avr-dragon]. It can be also used as a debugger and is available within Atmel Studio by default.\n\n### Step 2: Download fifofast\n - Clone this repository or hit [Download][git-download] and extract the .zip file.\n\n### Step 3: Browse the project\n - **Open the project in Atmel Studio:**<br>\n   Either double click `fifofast.atsln` or open Atmel Studio and select \"File -> Open -> Project/Solution...\"\n\n - **Open any file of your interest:**<br>\n   Select the file in the top right window \"Solution Explorer\". If the window is not visible, open it by pressing `CTRL + ALT + L` or selecting \"View -> Solution Explorer\" from the menu.\n\n### Step 4: Run the demo\n - **Compile the demo code:**<br>\n   Press `F7` or select \"Build -> Build Solution\" from the menu\n \n - **Run the demo code in the simulator:**<br>\n   Press `CTRL + F5` or select \"Debug -> Start Debugging and Break\" from the menu\n \n - **Place breakpoints:**<br>\n   Left-Click on the lightgrey area left of the code to place or remove a breakpoint. Select lines with the comment \"easy breakpoint\".\n   \n - **View variable values:**<br>\n   When the code is paused, hover over any variable to display its value. Alternately you can \"Right-Click -> Watch\" to display the value in the \"watch window\".\n \n - **Run Code:**<br>\n   Press `F5` to run to the next breakpoint or `F10` to execute one step.\n \n### Step 5: Going further\n - **Changing the target device:**<br>\n   Press `ALT + F7` and select \"Device -> Change device...\" to select your desired MCU.\n \n - **Program a real device:**<br>\n   Connect your programmer, press `ALT + F7` and select \"Tool\". Choose your tool, your programming interface and wire up your MCU. Press `CTRL + ALT + F7` to flash the code to the MCU. Non-official programmers are not supported by Atmel Studio.\n\n<br>\n\n## Documentation\n\n### API\nTo keep the documentation up-to-date with the least hassle, all configuration options, functions and their arguments are explained in a comment right in front of the declaration. See `fifofast.h` for more information. This section will be updated as soon as this project hits version 1.0.0.\n\nBelow you find information about the unusual functions/ macros in this implementation.\n\n#### `_fff_peek()`\nThe macro `_fff_peek()` allows the user to access any element of the fifo _as if_ it was an array. The first element of the fifo can be accessed with `_fff_peek(fifo, 0)`,  the following elements with an incremented index. See the illustration below:\n\n```\narray within fifo:\nfirst element       v\n      ┌───┬───┬───┬───┬───┬───┬───┬───┐\n      │   │   │   │ d │ a │ t │ a │   │\n      └───┴───┴───┴───┴───┴───┴───┴───┘\n_fff_peek(fifo, 0)  ^   ^   ^   ^\n_fff_peek(fifo, 1) ─────┘   │   │\n_fff_peek(fifo, 2) ─────────┘   │\n_fff_peek(fifo, 3) ─────────────┘\n```\n\n`_fff_peek()` is different from the typical `_fff_read()` and `_fff_write()` in multiple ways:\n\n1. The macro can be used as a right side **or** left side argument to read from/ write to a specific location.\n2. The data pointers are **not** changed. Reading or writing data will not remove/ add elements to/ from the fifo.\n3. The current fifo level is **not** checked, allowing the user to access \"empty space\", too.\n\nThus `_fff_peek()` is especially useful for any algorithm that needs to modify present data with minimum overhead. This macro is only marginally slower than a regular array access and significantly faster than copying data to a temporary buffer\n\n#### `_fff_rebase()`\nIf you receive strings through a serial interface you may want to use a fifo to store them temporally. Once completely received, you may want to use any of the build-in string functions on the stored data. This is not always directly possible. Consider the following case:\n\nA fifo has received multiple chars, which might be stored in the internal array as shown below:\n```\narray within fifo:\n┌───┬───┬───┬───┬───┬───┬───┬───┐\n│ n │ g │   │   │ s │ t │ r │ i │\n└───┴───┴───┴───┴───┴───┴───┴───┘\n```\n\nHowever, the string functions expect a continuous data array without the \"wrap\" in the middle. To solve this, 0.8.0 adds the macro `_fff_rebase()`. It re-arranges the array, so that the first element is stored in the first position of the array.\n\n```\narray within fifo, after _fff_rebase():\n┌───┬───┬───┬───┬───┬───┬───┬───┐\n│ s │ t │ r │ i │ n │ g │   │   │\n└───┴───┴───┴───┴───┴───┴───┴───┘\n```\n\nTo get a pointer to the first character, you can use `_fff_peek()`:\n\n```c\nchar* first_char = &_fff_peek(fifo, 0);\n```\n\n**Note:** `_fff_rebase()` iterates across all elements in the array and the execution time increases linearly with depth and element size of the fifo. Use only when necessary.\n\n<br>\n\n### Configuration\nfifofast is designed to work out-of-the-box the majority of all use cases. To increase flexibility, but retain the performance for simple applications, you can set configuration options\\* in `fifofast.h` in the section _User Config_. \n\n<sub>*As of 0.7.0 there is only one configuration option, but this is the place where other options would go.</sub>\n\n<br>\n\n### Pointable Fifos\nSince release 0.6.0 you can create special fifos which can be referenced by a pointer. They are created very similar to normal fifos, but they have a `_p` as a suffix:\n\n```c\n// declare pointable fifo\n_fff_declare_p(uint8_t, fifo_uint8p, 4);\n\n//init pointable fifo\n_fff_init_p(fifo_uint8p);\n```\n\n<br>\n\nTo access such a fifo you have two options:\n\n1. Pass its pointer to one of the implemented functions OR\n2. Use its identifier in a macro\n\nGeneric data in C can only be archived with pointers and type casts. This can be very confusing, so let me demonstrate it with examples:\n\n```c\n// 'fifo_uint8_p' has its own type depending on data type and depth, but its header looks like fff_proto_t,\n// which is the only type excepted by the functions. Therefore you need to convert the pointer first:\nuint8_t tmp_is_empty = fff_is_empty((fff_proto_t*)&fifo_uint8_p);\n\n// alternatively you can create a new temporal pointer like this:\nfff_proto_t* fifo_pointer = (fff_proto_t*)&fifo_uint8_p;\n\n// to write you need to pass a pointer to the data location. NO type check can be performed!\nuint8_t tmp_value = 42;\nfff_write(fifo_pointer, &tmp_value);\n\n// if you read data, you will only receive a void pointer. This needs to be cast into a pointer of the right\n// type and then de-referenced:\nuint8_t tmp_read = *(uint8_t*)fff_peek_read(fifo_pointer, 0);   // returns '42'\n```\n\nType conversions are often considered to be an _evil_ feature of C, as it hides all type mismatches. To reduce the chance of bug, **only use these inline functions where absolutly required!**\n\n<br>\n\n### FIFO Arrays\nFor some applications you may need multiple identical fifos which can be selected with an index.\n\nTo create a fifo array, declare its structure first:\n```c\n// declare an array (suffix _a) of fifos with 16 elements each.\n_fff_declare_a(uint8_t, fifo_array, 16, 5);\n```\nNext initialize it and specify the amount of fifos you need:\n```c\n// initialize an array (suffix _a) of 5 fifos.\n_fff_init_a(fifo_array, 5);\n```\nNow you can access each fifo like this:\n```c\n// write to the fifo at index 'fifo_nr' the value 'data'\n_fff_write(fifo_array[fifo_nr], data);\n```\n<br>\n\n### Aligned Data\nBecause **fifofast** supports any data type, it may also be used to store frames for a serial data transmission. It is often useful to access the data not only in binary (`raw`) format, but also as a struct (`header`):\n```c\ntypedef struct  \n{\n    uint16_t control;\n    uint8_t length;\n    uint8_t id;\n    uint8_t data[];\n} header_t;\n\ntypedef union __attribute__((aligned(2), packed))\n{\n    uint8_t raw[32];\n    header_t header;\n} frame_u;\n```\nIn this case the header variable `control` is 2 bytes large and must be stored aligned\non most architectures. The union however is treated by default as a `uint8_t` array, so no alignment is enforced. To do this manually, GCC supports the [`__attribute__((aligned(n)))`][doc-gcc-alignment]. If a struct or union is declared like this, it will be correctly stored in the fifo.\n\nTo align any non-typedef'd data, you can declare a fifo like this:\n```c\n_fff_declare(uint8_t __attribute__((aligned(4))), fifo_uint8, 4);\n```\n\n<br>\n\n## Under the Hood\nTo use **fifofast** you don't need to know its inner workings. This chapter is for those who seek to understand and learn.\n\n\n### The Typical Implementation\nTo get the best performance most fifos are based on an array for data storage. New elements are always placed at the next free index. When the fifo is read, the element of the earliest written index is returned. Example:\n\n```\nempty array:\n┌───┬───┬───┬───┬───┬───┬───┬───┐\n│   │   │   │   │   │   │   │   │\n└───┴───┴───┴───┴───┴───┴───┴───┘\n\nwrite 4 elements:\n┌───┬───┬───┬───┬───┬───┬───┬───┐\n│ a │ b │ c │ d │   │   │   │   │\n└───┴───┴───┴───┴───┴───┴───┴───┘\n\nread 2 elements:\n┌───┬───┬───┬───┬───┬───┬───┬───┐\n│   │   │ c │ d │   │   │   │   │\n└───┴───┴───┴───┴───┴───┴───┴───┘\n```\n\nAfter the array was filled at least once, new data must be added to the very first location. This is called a [circular buffer (wiki)][wiki-circular-buffer]\n\n```\nafter some time (example):\n┌───┬───┬───┬───┬───┬───┬───┬───┐\n│   │   │   │   │   │ e │ f │ g │\n└───┴───┴───┴───┴───┴───┴───┴───┘\n\nwrite 1 element:\n┌───┬───┬───┬───┬───┬───┬───┬───┐\n│ h │   │   │   │   │ e │ f │ g │\n└───┴───┴───┴───┴───┴───┴───┴───┘\n```\n\nTo detect this overflow the straight forward approach is to use `if(index > array_size){index = 0;}`. This comparison has to be done for _every_ fifo access. Branches take typically more cycles than arithmetic instruction, especially if a [instruction pipeline (wiki)][wiki-pipelining] is used within the MCU.\n\n<br>\n\n### 2ⁿ Ring Buffer\nIf the array has a length of 2ⁿ elements, this `if` can be replaced with a faster logic instruction.\n\n```c\n// increment the write index by 1\nindex = ((index+1) & (array_size-1));\n```\n\nLet's take the example above and observe the bahavior:\n\n```c\n// start values\nuint8_t array_size  = 8;\nuint8_t index       = 5;\n\n// first increment                v equivilant binary          v decimal result\nindex = ((5+1) & (8-1));   // == (0b0110 & 0b0111) == 0b110 == 6\nindex = ((6+1) & (8-1));   // == (0b0111 & 0b0111) == 0b111 == 7\nindex = ((7+1) & (8-1));   // == (0b1000 & 0b0111) == 0b000 == 0\nindex = ((0+1) & (8-1));   // == (0b0001 & 0b0111) == 0b001 == 1\n```\n\nAs you can see, the logic operation works exactly as we want! Of course you don't have to deal with this detail, **fifofast** takes care of that for you. For more info look in the [resource](#resources) section.\n\n<br>\n\n### Generic Data\nSupport for generic data types is not a part of C so **fifofast** has to use a creative work-around with macros. The key are the `_fff_declare(...)` macros:\n\n```c\n#define _fff_declare(_type, _id, _depth)            \\\nstruct _FFF_NAME_STRUCT(_id)                        \\\n{                                                   \\\n    _FFF_GET_TYPE(_depth) read;                     \\\n    _FFF_GET_TYPE(_depth) write;                    \\\n    _FFF_GET_TYPE(_depth) level;                    \\\n    _type data[_FFF_GET_ARRAYDEPTH16(_depth)];      \\\n} _id\n```\n\nEach macro \"call\" declares a new struct with an individual type and identifier. Therefore each of these struct can have members of a different size. However all structs have identical member identifiers, so if the `_id` known, a member can be accessed with `_id.member` like a normal struct. The compiler keeps track of all datatypes used within the structure and generates appropriate code.\n\n<br>\n\n## Support\n\n### Get Help\n\n**Something doesn't work as expected?** No worries! Just open up a new issue in the [GitHub issue tracker][git-issues]. Please provide all information to reproduce your problem. If you don't have a GitHub account (and can't be bothered to create one,) you can [contact](#contact) me directly.\n\n### Contribute\n\n**Spotted an error?** [Open an issue][git-issues] or submit a pull request.\n\nThere is no CONTRIBUTING.md yet, sorry. Contributions will inherit the [license](#license) of this project. If you have any questions, just ask.\n\n<br>\n\n## About\n### Status\n**This project is currently classified as <a href=\"https://github.com/nqtronix/git-template/blob/master/badges.md#project-status\"><img src=\"https://img.shields.io/badge/status-active-brightgreen.svg\" alt=\"status: active\"></a> :**<br>\n_The developers are working on new features, optimisations, documentation or another part of the project. The code will be kept in working condition by updating dependencies, fixing bugs and solving issues with a high priority._\n\nThe first version of this fifo was created about a year ago. Since then I've used the macros successfully for multiple projects and different MCU architectures (AVR8, SAMG and SAML). fifofast is activly used for upcoming projects and will receive additional features whenever I need them.\n\n### Known Issues\n - **Non-Atomic Glitches:**<br>\n   Accessing the same fifo from normal _and_ ISR code can cause glitches with some function combinations. To prevent this, put the normal code in an [atomic block][doc-gcc-atomic] if the fifo is also accessed in an ISR.\n \n### Planned Features\n\n- none (for now)\n\n### Changelog\nThis project uses [**Semantic Versioning 2.0.0**][semver.org]. During initial development (0.x.x versions) any _major_ increase is substituted with a _minor_ increase (0.1.0->0.2.0 instead of 0.1.0->1.0.0).\n\nThe message of each commit contains detailed information about the changes made. The list below is a summary about all significant improvements.\n\n - **0.8.0  (latest)**\n\t - implemented `_fff_rebase()` to handle strings better\n - **0.7.0**\n   - improved usage of struct member 'level'\n     - 'level' contains now real value, even if fifo is full\n     - demo-code compiles with 25% less flash usage\n     - less if-statements required, performance therefore increased\n - **0.6.0**\n   - implemented pointable fifos, including tests\n - **0.5.0**\n   - testing now automated with the brand new [unittrace][git-repo-unittrace].\n   - _finally_ polished up this readme :tada:\n - **0.4.0**\n   - array with several fifos now possible\n   - aligned data example provided\n - **0.3.0**\n   - complete _and successful_ test of all macros (this time for real)\n - **0.2.0**\n   - ~~complete~~ test of all macros\n   - changed fifo struct to improve readability\n   - MIT License added to git\n - **0.1.0**\n   - initial commit\n\n### Contact\n\nIf you haven't done so already, please check out [Get Help](#get-help) for the fastest possible help on your issue. Alternatively you can find my public email address on my [profile][git-profile].\n\n<br>\n\n\n## Credits\n\n### Projects Used\n\n - [**git-template**][git-repo-git-template] - _A simple and clean git repository template._<br>\n\n - [**unittrace**][git-repo-unittrace] - _A simple testing and debugging tool for MCUs inspired by MinUnit_<br>\nSpecifically written for this project, because testing became to annoying.\n\n<br>\n\n### Related Projects\n\n - none (yet)\n \nWant yours to be listed here, too? Create a merge request or [**get in touch**](#get-help).\n\n<br>\n\n### Additional Resources\n - [**2ⁿ circular buffer explanation (German)**][article-2n-buffer] or [English (with google translate)][article-2n-buffer-eng]\n \n - [**GCC: Atomically and Non-Atomically Executed Code Blocks**][doc-gcc-atomic]\n \n - [**GCC: Specifying Attributes of Variables**][doc-gcc-alignment]\n\n<br>\n\n## License\nThis project is proudly licensed under the [MIT license][git-license].\n\nThe MIT license was chosen to give you the freedom to use this project in any way you want, while protecting all contributors from legal claims. Good code works, great code works for everyone. If this code has become a part of one of your projects, a link back to us would be highly appreciated. Thanks!\n\n<!-- Links -->\n\n[semver.org]:https://semver.org/\n\n[git-readme]:README.md\n[git-license]:LICENSE.md\n[git-profile]:https://github.com/nqtronix\n[git-issues]:https://github.com/nqtronix/fifofast/issues\n[git-download]:https://github.com/nqtronix/fifofast/archive/master.zip\n\n[git-repo-unittrace]:https://github.com/nqtronix/unittrace/\n[git-repo-git-template]:https://github.com/nqtronix/git-template/\n\n[doc-gcc-atomic]:https://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html\n[doc-gcc-alignment]:https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Variable-Attributes.html\n[article-2n-buffer]:https://www.mikrocontroller.net/articles/FIFO#2n-Ringpuffer_-_die_schnellste_L.C3.B6sung\n[article-2n-buffer-eng]:https://translate.google.com/translate?sl=de&tl=en&js=y&prev=_t&hl=de&ie=UTF-8&u=https%3A%2F%2Fwww.mikrocontroller.net%2Farticles%2FFIFO%232n-Ringpuffer_-_die_schnellste_L.C3.B6sung&edit-text=&act=url\n\n[wiki-pipelining]:https://en.wikipedia.org/wiki/Instruction_pipelining\n[wiki-circular-buffer]:https://en.wikipedia.org/wiki/Circular_buffer\n\n[tool-atmel-studio-7-0]:https://www.microchip.com/mplab/avr-support/atmel-studio-7\n[tool-avr-dragon]:https://www.microchip.com/Developmenttools/ProductDetails/ATAVRDRAGON\n"
  },
  {
    "path": "fifofast.atsln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Atmel Studio Solution File, Format Version 11.00\r\nVisualStudioVersion = 14.0.23107.0\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{54F91283-7BC4-4236-8FF9-10F437C3AD48}\") = \"fifofast\", \"fifofast.cproj\", \"{DCE6C7E3-EE26-4D79-826B-08594B9AD897}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|AVR = Debug|AVR\r\n\t\tRelease|AVR = Release|AVR\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.ActiveCfg = Debug|AVR\r\n\t\t{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.Build.0 = Debug|AVR\r\n\t\t{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.ActiveCfg = Release|AVR\r\n\t\t{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.Build.0 = Release|AVR\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "fifofast.componentinfo.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Store xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"AtmelPackComponentManagement\">\r\n\t<ProjectComponents>\r\n\t\t<ProjectComponent z:Id=\"i1\" xmlns:z=\"http://schemas.microsoft.com/2003/10/Serialization/\">\r\n\t\t\t<CApiVersion></CApiVersion>\r\n\t\t\t<CBundle></CBundle>\r\n\t\t\t<CClass>Device</CClass>\r\n\t\t\t<CGroup>Startup</CGroup>\r\n\t\t\t<CSub></CSub>\r\n\t\t\t<CVariant></CVariant>\r\n\t\t\t<CVendor>Atmel</CVendor>\r\n\t\t\t<CVersion>1.0.0</CVersion>\r\n\t\t\t<DefaultRepoPath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs</DefaultRepoPath>\r\n\t\t\t<DependentComponents xmlns:d4p1=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\" />\r\n\t\t\t<Description></Description>\r\n\t\t\t<Files xmlns:d4p1=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">\r\n\t\t\t\t<d4p1:anyType i:type=\"FileInfo\">\r\n\t\t\t\t\t<AbsolutePath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs\\atmel\\ATmega_DFP\\1.0.90\\include</AbsolutePath>\r\n\t\t\t\t\t<Attribute></Attribute>\r\n\t\t\t\t\t<Category>include</Category>\r\n\t\t\t\t\t<Condition>C</Condition>\r\n\t\t\t\t\t<FileContentHash i:nil=\"true\" />\r\n\t\t\t\t\t<FileVersion></FileVersion>\r\n\t\t\t\t\t<Name>include</Name>\r\n\t\t\t\t\t<SelectString></SelectString>\r\n\t\t\t\t\t<SourcePath></SourcePath>\r\n\t\t\t\t</d4p1:anyType>\r\n\t\t\t\t<d4p1:anyType i:type=\"FileInfo\">\r\n\t\t\t\t\t<AbsolutePath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs\\atmel\\ATmega_DFP\\1.0.90\\include\\avr\\iom328p.h</AbsolutePath>\r\n\t\t\t\t\t<Attribute></Attribute>\r\n\t\t\t\t\t<Category>header</Category>\r\n\t\t\t\t\t<Condition>C</Condition>\r\n\t\t\t\t\t<FileContentHash>UMk4QUzkkuShabuoYtNl/Q==</FileContentHash>\r\n\t\t\t\t\t<FileVersion></FileVersion>\r\n\t\t\t\t\t<Name>include/avr/iom328p.h</Name>\r\n\t\t\t\t\t<SelectString></SelectString>\r\n\t\t\t\t\t<SourcePath></SourcePath>\r\n\t\t\t\t</d4p1:anyType>\r\n\t\t\t\t<d4p1:anyType i:type=\"FileInfo\">\r\n\t\t\t\t\t<AbsolutePath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs\\atmel\\ATmega_DFP\\1.0.90\\templates\\main.c</AbsolutePath>\r\n\t\t\t\t\t<Attribute>template</Attribute>\r\n\t\t\t\t\t<Category>source</Category>\r\n\t\t\t\t\t<Condition>C Exe</Condition>\r\n\t\t\t\t\t<FileContentHash>GD1k8YYhulqRs6FD1B2Hog==</FileContentHash>\r\n\t\t\t\t\t<FileVersion></FileVersion>\r\n\t\t\t\t\t<Name>templates/main.c</Name>\r\n\t\t\t\t\t<SelectString>Main file (.c)</SelectString>\r\n\t\t\t\t\t<SourcePath></SourcePath>\r\n\t\t\t\t</d4p1:anyType>\r\n\t\t\t\t<d4p1:anyType i:type=\"FileInfo\">\r\n\t\t\t\t\t<AbsolutePath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs\\atmel\\ATmega_DFP\\1.0.90\\templates\\main.cpp</AbsolutePath>\r\n\t\t\t\t\t<Attribute>template</Attribute>\r\n\t\t\t\t\t<Category>source</Category>\r\n\t\t\t\t\t<Condition>C Exe</Condition>\r\n\t\t\t\t\t<FileContentHash>YXFphlh0CtZJU+ebktABgQ==</FileContentHash>\r\n\t\t\t\t\t<FileVersion></FileVersion>\r\n\t\t\t\t\t<Name>templates/main.cpp</Name>\r\n\t\t\t\t\t<SelectString>Main file (.cpp)</SelectString>\r\n\t\t\t\t\t<SourcePath></SourcePath>\r\n\t\t\t\t</d4p1:anyType>\r\n\t\t\t\t<d4p1:anyType i:type=\"FileInfo\">\r\n\t\t\t\t\t<AbsolutePath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs\\atmel\\ATmega_DFP\\1.0.90\\gcc\\dev\\atmega328p</AbsolutePath>\r\n\t\t\t\t\t<Attribute></Attribute>\r\n\t\t\t\t\t<Category>libraryPrefix</Category>\r\n\t\t\t\t\t<Condition>GCC</Condition>\r\n\t\t\t\t\t<FileContentHash i:nil=\"true\" />\r\n\t\t\t\t\t<FileVersion></FileVersion>\r\n\t\t\t\t\t<Name>gcc/dev/atmega328p</Name>\r\n\t\t\t\t\t<SelectString></SelectString>\r\n\t\t\t\t\t<SourcePath></SourcePath>\r\n\t\t\t\t</d4p1:anyType>\r\n\t\t\t</Files>\r\n\t\t\t<PackName>ATmega_DFP</PackName>\r\n\t\t\t<PackPath>C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.0.90/Atmel.ATmega_DFP.pdsc</PackPath>\r\n\t\t\t<PackVersion>1.0.90</PackVersion>\r\n\t\t\t<PresentInProject>true</PresentInProject>\r\n\t\t\t<ReferenceConditionId>ATmega328P</ReferenceConditionId>\r\n\t\t\t<RteComponents xmlns:d4p1=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">\r\n\t\t\t\t<d4p1:string></d4p1:string>\r\n\t\t\t</RteComponents>\r\n\t\t\t<Status>Resolved</Status>\r\n\t\t\t<VersionMode>Fixed</VersionMode>\r\n\t\t\t<IsComponentInAtProject>true</IsComponentInAtProject>\r\n\t\t</ProjectComponent>\r\n\t</ProjectComponents>\r\n</Store>"
  },
  {
    "path": "fifofast.cproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" ToolsVersion=\"14.0\">\r\n  <PropertyGroup>\r\n    <SchemaVersion>2.0</SchemaVersion>\r\n    <ProjectVersion>7.0</ProjectVersion>\r\n    <ToolchainName>com.Atmel.AVRGCC8.C</ToolchainName>\r\n    <ProjectGuid>dce6c7e3-ee26-4d79-826b-08594b9ad897</ProjectGuid>\r\n    <avrdevice>ATmega328P</avrdevice>\r\n    <avrdeviceseries>none</avrdeviceseries>\r\n    <OutputType>Executable</OutputType>\r\n    <Language>C</Language>\r\n    <OutputFileName>$(MSBuildProjectName)</OutputFileName>\r\n    <OutputFileExtension>.elf</OutputFileExtension>\r\n    <OutputDirectory>$(MSBuildProjectDirectory)\\$(Configuration)</OutputDirectory>\r\n    <AssemblyName>fifofast</AssemblyName>\r\n    <Name>fifofast</Name>\r\n    <RootNamespace>fifofast</RootNamespace>\r\n    <ToolchainFlavour>Native</ToolchainFlavour>\r\n    <KeepTimersRunning>true</KeepTimersRunning>\r\n    <OverrideVtor>false</OverrideVtor>\r\n    <CacheFlash>true</CacheFlash>\r\n    <ProgFlashFromRam>true</ProgFlashFromRam>\r\n    <RamSnippetAddress>0x20000000</RamSnippetAddress>\r\n    <UncachedRange />\r\n    <preserveEEPROM>true</preserveEEPROM>\r\n    <OverrideVtorValue>exception_table</OverrideVtorValue>\r\n    <BootSegment>2</BootSegment>\r\n    <eraseonlaunchrule>0</eraseonlaunchrule>\r\n    <AsfFrameworkConfig>\r\n      <framework-data>\r\n  <options />\r\n  <configurations />\r\n  <files />\r\n  <documentation help=\"\" />\r\n  <offline-documentation help=\"\" />\r\n  <dependencies>\r\n    <content-extension eid=\"atmel.asf\" uuidref=\"Atmel.ASF\" version=\"3.42.0\" />\r\n  </dependencies>\r\n</framework-data>\r\n    </AsfFrameworkConfig>\r\n    <avrtool>com.atmel.avrdbg.tool.simulator</avrtool>\r\n    <avrtoolserialnumber />\r\n    <avrdeviceexpectedsignature>0x1E950F</avrdeviceexpectedsignature>\r\n    <com_atmel_avrdbg_tool_simulator>\r\n      <ToolOptions xmlns=\"\">\r\n        <InterfaceProperties>\r\n        </InterfaceProperties>\r\n      </ToolOptions>\r\n      <ToolType xmlns=\"\">com.atmel.avrdbg.tool.simulator</ToolType>\r\n      <ToolNumber xmlns=\"\">\r\n      </ToolNumber>\r\n      <ToolName xmlns=\"\">Simulator</ToolName>\r\n    </com_atmel_avrdbg_tool_simulator>\r\n    <ResetRule>0</ResetRule>\r\n    <EraseKey />\r\n    <AAFDebugger>\r\n      <AAFDebugFiles xmlns=\"\">\r\n        <DebugFile>\r\n          <path>\\Debug\\fifofast.lss</path>\r\n          <AAFSetting>\r\n            <Label>Lss Files</Label>\r\n            <Extention>.lss</Extention>\r\n            <Regex>^\\s*(?&lt;address&gt;[a-f0-9]*):\\s*.*$</Regex>\r\n            <DebugEnabled>true</DebugEnabled>\r\n            <RegexGroups>address</RegexGroups>\r\n            <DebuggerExpression>$pc</DebuggerExpression>\r\n          </AAFSetting>\r\n        </DebugFile>\r\n      </AAFDebugFiles>\r\n    </AAFDebugger>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Release' \">\r\n    <ToolchainSettings>\r\n      <AvrGcc>\r\n        <avrgcc.common.Device>-mmcu=atmega328p -B \"%24(PackRepoDir)\\atmel\\ATmega_DFP\\1.0.90\\gcc\\dev\\atmega328p\"</avrgcc.common.Device>\r\n        <avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>\r\n        <avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>\r\n        <avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>\r\n        <avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>\r\n        <avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>\r\n        <avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>\r\n        <avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>\r\n        <avrgcc.compiler.symbols.DefSymbols>\r\n          <ListValues>\r\n            <Value>NDEBUG</Value>\r\n          </ListValues>\r\n        </avrgcc.compiler.symbols.DefSymbols>\r\n        <avrgcc.compiler.directories.IncludePaths>\r\n          <ListValues>\r\n            <Value>%24(PackRepoDir)\\atmel\\ATmega_DFP\\1.0.90\\include</Value>\r\n          </ListValues>\r\n        </avrgcc.compiler.directories.IncludePaths>\r\n        <avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>\r\n        <avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>\r\n        <avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>\r\n        <avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>\r\n        <avrgcc.linker.libraries.Libraries>\r\n          <ListValues>\r\n            <Value>libm</Value>\r\n          </ListValues>\r\n        </avrgcc.linker.libraries.Libraries>\r\n      </AvrGcc>\r\n    </ToolchainSettings>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Debug' \">\r\n    <ToolchainSettings>\r\n      <AvrGcc>\r\n        <avrgcc.common.Device>-mmcu=atmega328p -B \"%24(PackRepoDir)\\atmel\\ATmega_DFP\\1.0.90\\gcc\\dev\\atmega328p\"</avrgcc.common.Device>\r\n        <avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>\r\n        <avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>\r\n        <avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>\r\n        <avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>\r\n        <avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>\r\n        <avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>\r\n        <avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>\r\n        <avrgcc.compiler.symbols.DefSymbols>\r\n          <ListValues>\r\n            <Value>DEBUG</Value>\r\n          </ListValues>\r\n        </avrgcc.compiler.symbols.DefSymbols>\r\n        <avrgcc.compiler.directories.IncludePaths>\r\n          <ListValues>\r\n            <Value>%24(PackRepoDir)\\atmel\\ATmega_DFP\\1.0.90\\include</Value>\r\n            <Value>../subrepos</Value>\r\n          </ListValues>\r\n        </avrgcc.compiler.directories.IncludePaths>\r\n        <avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>\r\n        <avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>\r\n        <avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>\r\n        <avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>\r\n        <avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>\r\n        <avrgcc.linker.libraries.Libraries>\r\n          <ListValues>\r\n            <Value>libm</Value>\r\n          </ListValues>\r\n        </avrgcc.linker.libraries.Libraries>\r\n        <avrgcc.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcc.assembler.debugging.DebugLevel>\r\n      </AvrGcc>\r\n    </ToolchainSettings>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"fifofast.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"fifofast_demo.c\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"fifofast_demo.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"fifofast_test.c\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"fifofast_test.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"subrepos\\unittrace\\unittrace.c\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"subrepos\\unittrace\\unittrace.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"subrepos\\unittrace\\utility\\macros\\com\\macro_type.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"utility\\macros\\com\\macro_array.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"utility\\macros\\com\\macro_math.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"utility\\macros\\com\\macro_type.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"utility\\macros\\mpl\\macro_cat.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"utility\\macros\\mpl\\macro_narg.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"utility\\macros\\mpl\\macro_vfunc.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Folder Include=\"subrepos\" />\r\n    <Folder Include=\"subrepos\\unittrace\\\" />\r\n    <Folder Include=\"subrepos\\unittrace\\utility\\\" />\r\n    <Folder Include=\"subrepos\\unittrace\\utility\\macros\\\" />\r\n    <Folder Include=\"subrepos\\unittrace\\utility\\macros\\com\\\" />\r\n    <Folder Include=\"utility\\\" />\r\n    <Folder Include=\"utility\\macros\\\" />\r\n    <Folder Include=\"utility\\macros\\com\\\" />\r\n    <Folder Include=\"utility\\macros\\mpl\\\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"LICENSE.md\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n    <None Include=\"README.md\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n    <None Include=\"subrepos\\readme %28license info%29.txt\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n    <None Include=\"subrepos\\unittrace\\LICENSE.md\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n    <None Include=\"subrepos\\unittrace\\README.md\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n    <None Include=\"subrepos\\unittrace\\utility\\macros\\com\\com readme.txt\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n    <None Include=\"utility\\macros\\com\\com readme.txt\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n    <None Include=\"utility\\macros\\mpl\\mpl readme.txt\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n    <None Include=\"utility\\macros\\readme.txt\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n  </ItemGroup>\r\n  <Import Project=\"$(AVRSTUDIO_EXE_PATH)\\\\Vs\\\\Compiler.targets\" />\r\n</Project>"
  },
  {
    "path": "fifofast.h",
    "content": "/*\n * fifofast.h\n *\n * Created: 23.10.2017 06:45:20\n *  Author: Dennis aka nqtronix (github.com/nqtronix)\n *\n * Description:\n * Most libraries for data structures are designed for dynamically allocating memory, which can't be\n * efficiently used on small, low-cost, embedded devices.\n * This library implements the common fifo data structure based on function-like macros, which\n * allows the code to be generic for all data types and buffer sizes. All memory is allocated at\n * compile time. As a side effect the execution time for most functions and RAM memory consumption\n * is reduced, but the program size slightly increased.\n *\n * Some programs may need to access multiple fifos, e.g. to distribute measured ADC values to their\n * corresponding handler functions. For theses applications you can create fifos, which can be safely\n * passed by pointers. Although these fifos can be access by all function-like macros, they can't be\n * as generic and are limited to user selectable depth 'FIFOFAST_MAX_DEPTH_POINTABLE'.\n *\n * If any fifo is accessed from ISRs make sure all access to the involved fifo from normal code is\n * atomic! This is important to prevent glitches in the middle of an operation!\n */ \n\n#ifndef FIFOFAST_H_\n#define FIFOFAST_H_\n\n#include <stdint.h>\t\t// required for data types (uint8_t, uint16_t, ...)\n#include <stddef.h>\t\t// required for \"NULL\"\n#include <string.h>\t\t// required for memcopy\n\n// include required macros\n// by default, the project's macros will be used, they have to be located at:\n// \"utility/macros/...\"\n//\n// If your project has no global macros, you can re-direct GCC to the included files:\n// a) in Atmel Studio edit project properties (ALT+F7 OR \"Project -> <project name> Properties...\")\n// b) Go to \"Toolchain / AVR/GNU C Compiler / Directories\"\n// c) add the relative path to: \"../src/subrepo/fifofast/\" or wherever this code is located. DONE!\n//\n// YOU DO NOT need to change the include(s) below.\n#include \"utility/macros/mpl/macro_cat.h\"\n#include \"utility/macros/com/macro_array.h\"\n#include \"utility/macros/com/macro_math.h\"\n#include \"utility/macros/com/macro_type.h\"\n\n\n//////////////////////////////////////////////////////////////////////////\n// User Config\n//////////////////////////////////////////////////////////////////////////\n\n// defines the maximum depth of pointable fifos. The performance of fifofast drops with increased\n// maximum depth in discrete steps, especially on 8bit MCUs. 32bit MCUs (such as ARM cortex) are\n// mostly unaffected, except they require slightly more RAM. If the value is NOT a 2^n value, it\n// will automatically be rounded up.\n//\n// depth\t\t\t| performance\n// -----------------+-------------\n//    4 <= x <= 128\t| best\n//         x == 256\t| ok\n//  512 <= x\t\t| slow\n#define FIFOFAST_MAX_DEPTH_POINTABLE\t128\n\n\n//////////////////////////////////////////////////////////////////////////\n// General Info\n//////////////////////////////////////////////////////////////////////////\n\n// version numbering is based on \"Semantic Versioning 2.0.0\" (semver.org)\n#define FIFOFAST_VERSION_MAJOR\t\t0\n#define FIFOFAST_VERSION_MINOR\t\t8\n#define FIFOFAST_VERSION_PATCH\t\t0\n#define FIFOFAST_VERSION_SUFFIX\t\t\n#define FIFOFAST_VERSION_META\t\t\n\n// For all development versions (0.x.x) the patch version is increased whenever a function was renamed\n\n\n//////////////////////////////////////////////////////////////////////////\n// Check requirements\n//////////////////////////////////////////////////////////////////////////\n\n#ifndef __GNUC__\n\t#error fifofast.h requires \"compound statments\" and \"typeof\" offered by a GNU C/ GCC compiler!\n#endif\n\n#ifndef __OPTIMIZE__\n\t#pragma message \"fifofast.h is intended to be compiled with optimisation and will run VERY SLOWLY without!\"\n#endif\n\n\n//////////////////////////////////////////////////////////////////////////\n// internal macros (_FFF_*)\n//////////////////////////////////////////////////////////////////////////\n\n// rounds up given argument to next 2^n value. Used to deal with invalid user input.\n#define  ROUND_UP_2N(_arg)\t\t\t\t((uint64_t)1<<(_log2(_arg-1)+1))\n\n// returns the structure name matching to given ID without the keyword 'struct'\n#define _FFF_NAME_STRUCT(_id)\t\t\tCAT(fff_, _id, _s)\n\n// returns matching type for internal index values; fifo constrains are automatically applied\n#define _FFF_GET_TYPE(_depth)\t\t\t_type_min(_limit_lo(_depth,4)-1)\n#define _FFF_SIZEOF_DATA(_id)\t\t\tsizeof(((struct _FFF_NAME_STRUCT(_id)*)0)->data[0])\n#define _FFF_SIZEOF_ARRAY(_id)\t\t\t_sizeof_array(((struct _FFF_NAME_STRUCT(_id)*)0)->data)\n\n// returns the length of the data array; fifo constrains are automatically applied\n#define\t_FFF_GET_ARRAYDEPTH(_depth)\t\t_limit(ROUND_UP_2N(_depth), 4, ((uint32_t)1<<31))\n#define\t_FFF_GET_ARRAYDEPTH_P(_depth)\t_limit(ROUND_UP_2N(_depth), 4, ROUND_UP_2N(FIFOFAST_MAX_DEPTH_POINTABLE))\n\n\n//////////////////////////////////////////////////////////////////////////\n// Data Structures (for inline functions only)\n//////////////////////////////////////////////////////////////////////////\n\n// extra #defines prevent VAssitX from marking the type red (because it doesn't understand 'typeof')\n#define FIFOFAST_INDEX_T _type_min(ROUND_UP_2N(FIFOFAST_MAX_DEPTH_POINTABLE)-1)\n#define FIFOFAST_LEVEL_T _type_min(ROUND_UP_2N(FIFOFAST_MAX_DEPTH_POINTABLE))\ntypedef FIFOFAST_INDEX_T fff_index_t;\ntypedef FIFOFAST_LEVEL_T fff_level_t;\n\ntypedef struct\n{\n\tconst fff_index_t data_size;\t// bytes per element in data array\n\tconst fff_index_t mask;\t\t\t// (max amount of elements in data array) - 1\n\tfff_index_t read;\t\t\t\t// index from which to read next element\n\tfff_index_t write;\t\t\t\t// index to which to write next element\n\tfff_level_t level;\t\t\t\t// current amount of stored data. Is larger than 'mask', if full\n\tuint8_t data[];\t\t\t\t\t// data storage array\n} fff_proto_t;\n\n\n//////////////////////////////////////////////////////////////////////////\n// Function Declarations (User)\n//////////////////////////////////////////////////////////////////////////\n\n// these functions behave as their corresponding macros, so please refer to their description\n// for infos on usage.\nstatic inline fff_index_t\tfff_mem_mask(fff_proto_t *fifo) __attribute__((__always_inline__));\nstatic inline fff_level_t\tfff_mem_level(fff_proto_t *fifo) __attribute__((__always_inline__));\nstatic inline fff_index_t\tfff_mem_free(fff_proto_t *fifo) __attribute__((__always_inline__));\n\nstatic inline fff_index_t\tfff_data_size(fff_proto_t *fifo) __attribute__((__always_inline__));\nstatic inline uint8_t\tfff_is_empty(fff_proto_t *fifo) __attribute__((__always_inline__));\nstatic inline uint8_t\tfff_is_full(fff_proto_t *fifo) __attribute__((__always_inline__));\n\nstatic inline void\t\tfff_reset(fff_proto_t *fifo) __attribute__((__always_inline__));\nstatic inline void\t\tfff_remove(fff_proto_t *fifo, fff_level_t amount) __attribute__((__always_inline__));\nstatic inline void\t\tfff_remove_lite(fff_proto_t *fifo, fff_level_t amount) __attribute__((__always_inline__));\nstatic inline void\t\tfff_write(fff_proto_t *fifo, void *data) __attribute__((__always_inline__));\nstatic inline void\t\tfff_write_lite(fff_proto_t *fifo, void *data) __attribute__((__always_inline__));\n\nstatic inline void*\t\tfff_peek_read(fff_proto_t *fifo, fff_index_t idx) __attribute__((__always_inline__));\nstatic inline void\t\tfff_peek_write(fff_proto_t *fifo, fff_index_t idx, void *data) __attribute__((__always_inline__));\n\n\n//////////////////////////////////////////////////////////////////////////\n// Function Declarations (Internal)\n//////////////////////////////////////////////////////////////////////////\n\nstatic inline fff_index_t fff_wrap(fff_proto_t *fifo, fff_index_t idx) __attribute__((__always_inline__));\nstatic inline void* fff_data_p(fff_proto_t *fifo, fff_index_t idx) __attribute__((__always_inline__));\n\n\n//////////////////////////////////////////////////////////////////////////\n// user macros (_fff_*)\n//////////////////////////////////////////////////////////////////////////\n\n// all function-like macros are suitable for ANY fifo, independent of data type or size. \n\n// declares semi-anonymous fifofast structure\n// semi-anonymous means it appears anonymous for the user as it is derived from the '_id' whenever\n// needed, but is not anonymous on compiler level. This has the additional benefit of VAssisX and\n// debugging (inspecting variables during runtime with an external debugger) working as usual. The\n// fifo shall only be access through macros or functions provided in this file.\n//\n// The variant _fff_declare_p(...) declares a structure which includes the size of each element and\n// the maximum amount of elements and can thus be used by the inline functions. They still can be\n// accessed with all function-like macros provided for some speed gain. \n//\n// The variant_fff_declare_pa(...) declares an array with structures as declared by _fff_declare_p(...).\n// \n//\n// _id:\t\tC conform identifier\n// _type:\tany C type except pointers and structs. To store pointers or structs use typedef first\n// _depth:\tmaximum amount of elements, which can be stored in the fifo. Only values of 2^n are\n//\t\t\tpossible. If another value is passed the next larger value will be automatically\n//\t\t\tselected. The amount of additional RAM required increases in discrete steps:\n//\t\t\t\t    depth (elements) | RAM (bytes)\n//\t\t\t\t---------------------+-------------\n//\t\t\t\t     4 <= x <= 128   | 3\n//\t\t\t\t          x == 256   | 4\n//\t\t\t\t   512 <= x <= 32768 | 6\n//\t\t\t\t          x == 65536 | 8\n//\t\t\t\t131072 <= x          | 12\n\n#define _fff_declare(_type, _id, _depth)\t\t\t\t\t\t\t\t\\\nstruct _FFF_NAME_STRUCT(_id) {\t\t\t\t\t\t\t\t\t\t\t\\\n\t_FFF_GET_TYPE(_depth) read;\t\t\t\t\t\t\t\t\t\t\t\\\n\t_FFF_GET_TYPE(_depth) write;\t\t\t\t\t\t\t\t\t\t\\\n\t_FFF_GET_TYPE(_depth+1) level;\t\t\t\t\t\t\t\t\t\t\\\n\t_type data[_FFF_GET_ARRAYDEPTH(_depth)];\t\t\t\t\t\t\t\\\n} _id\n\n#define _fff_declare_p(_type, _id, _depth)\t\t\t\t\t\t\t\t\\\nstruct _FFF_NAME_STRUCT(_id) {\t\t\t\t\t\t\t\t\t\t\t\\\n\tconst fff_index_t data_size;\t\t\t\t\t\t\t\t\t\t\\\n\tconst fff_index_t mask;\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tfff_index_t read;\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tfff_index_t write;\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tfff_level_t level;\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t_type data[_FFF_GET_ARRAYDEPTH_P(_depth)];\t\t\t\t\t\t\t\\\n} _id\n\n// declares an array with '_size' fifos. '_size' can be any positive integer.\n#define _fff_declare_a(_type, _id, _depth, _size)\t\t_fff_declare(_type, _id, _depth) [_size]\n#define _fff_declare_pa(_type, _id, _depth, _size)\t\t_fff_declare_p(_type, , _depth) [_size]\n\n\n// initializes the fifo with the name '<_id>'\n// This initialization function is technically identical to the term \"definition\" in c, but to\n// prevent confusion with \"#define\" it has been named '_fff_init()'. Since it is a definition it\n// can be only called once. Use '_fff_reset()' to reset any fifo back to it's original state.\n//\n// The variants '_fff_init_p(_id)' and '_fff_init_pa(_id, _arraysize)' are intended for the\n// respective declarations.\n#define _fff_init(_id)\t\t\t\t\t\t\t\t\t\t\t\t\t\\\nstruct _FFF_NAME_STRUCT(_id) _id =\t\t\t\t\t\t\t\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t{}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n}\n\n#define _fff_init_a(_id, _arraysize)\t\t\t\t\t\t\t\t\t\\\nstruct _FFF_NAME_STRUCT(_id) _id [] =\t\t\t\t\t\t\t\t\t\\\n{[0 ... _arraysize-1] = {\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t{}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n}}\n\n#define _fff_init_p(_id)\t\t\t\t\t\t\t\t\t\t\t\t\\\nstruct _FFF_NAME_STRUCT(_id) _id =\t\t\t\t\t\t\t\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t_FFF_SIZEOF_DATA(_id),\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t_FFF_SIZEOF_ARRAY(_id)-1,\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t{}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n}\n\n#define _fff_init_pa(_id, _arraysize)\t\t\t\t\t\t\t\t\t\\\nstruct _FFF_NAME_STRUCT(_id) _id [] =\t\t\t\t\t\t\t\t\t\\\n{[0 ... _arraysize-1] = {\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t_FFF_SIZEOF_DATA(_id),\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t_FFF_SIZEOF_ARRAY(_id)-1,\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t{}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n}}\n\n\n// masks a given index value based on a given fifo\n// This macro is used to simplify other marcos below; the end user will likely never need it\n// _id:\t\tC conform identifier\n// idx:\t\tthe index value to mask. MUST be larger than -_sizeof_array(_id.data)\n#define _fff_wrap(_id, idx)\t\t\t\t((idx) & _fff_mem_mask(_id))\n\n// returns the maximum amount of data elements which can be stored in the fifo\n// The returned value is calculated at compile time and thus a constant. No atomic access is needed.\n// NOTE: For a fifo of size 256 a \"256\" is returned and thus does not fit into uint8_t\n// _id:\t\tC conform identifier\n#define _fff_mem_depth(_id)\t\t\t\t(_sizeof_array(_id.data))\n#define _fff_mem_mask(_id)\t\t\t\t(_sizeof_array(_id.data)-1)\n\n// returns the amount of bytes per data element\n// The returned value is calculated at compile time and thus a constant. No atomic access is needed.\n// _id:\t\tC conform identifier\n#define _fff_data_size(_id)\t\t\t\t(sizeof(_id.data[0]))\n\n// returns !0 if empty\n#define _fff_is_empty(_id)\t\t\t\t(_id.level == 0)\n\n// returns !0 if full\n#define _fff_is_full(_id)\t\t\t\t(_id.level > _fff_mem_mask(_id))\n\n// returns the current fill level of the fifo (the amount of elements that can be read)\n// _id: C conform identifier\n#define _fff_mem_level(_id)\t\t\t\t(_id.level)\n\n// returns the current free space of the fifo (the amount of elements that can be written)\n// _id: C conform identifier\n#define _fff_mem_free(_id)\t\t\t\t(_fff_mem_depth(_id) - _id.level)\n\n// clears/ resets buffer completely\n// _id:\t\tC conform identifier\n#define _fff_reset(_id)\t\t\t\t\tdo{_id.read=0; _id.write=0; _id.level=0;} while (0)\n\n\t\n// removes a certain number of elements or less, if not enough elements are available.\n// This function is especially useful after data has been used by _fff_peek(...)\n// _id:\t\tC conform identifier\n// amount:\tAmount of elements which will be removed, amount >= 0 (positive integer)\n#define _fff_remove(_id, amount)\t\t\t\t\t\t\t\t\\\ndo{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\ttypeof(_id.level) _amount = amount;\t\t\t\t\t\t\t\\\n\tif(amount > _id.level)\t\t\t\t\t\t\t\t\t\t\\\n\t\t_amount = _id.level;\t\t\t\t\t\t\t\t\t\\\n\t_fff_remove_lite(_id, _amount);\t\t\t\t\t\t\t\t\\\n}while(0)\n\t\t\t\t\t\n// removes a certain number of elements. The user must ensure that the given amount of elements can\n// be removed; values larger than _fff_depth(_id) are invalid! If you require argument checking use \n// _fff_remove().\n// This function is especially useful after data has been used by _fff_peek(...)\n// _id:\t\tC conform identifier\n// amount:\tAmount of elements which will be removed; must be 0 <= amount <= _fff_mem_level(_id);\n#define _fff_remove_lite(_id, amount)\t\t\t\t\t\t\t\\\ndo{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t_id.level -= amount;\t\t\t\t\t\t\t\t\t\t\\\n\t_id.read = _fff_wrap(_id, _id.read+amount);\t\t\t\t\t\\\n}while(0)\t\t\t\t\n\n\n// returns the next element from the fifo and removes it from the memory\n// Use if(!_fff_is_empty(_id)) if amount of stored data is unknown\n// _id: C conform identifier\n#define _fff_read_lite(_id)\t\t\t\t\t\t\t\t\t\t\\\n({\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\ttypeof(_id.data[0])\t_return;\t\t\t\t\t\t\t\t\\\n\t_id.level--;\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t_return = _id.data[_id.read];\t\t\t\t\t\t\t\t\\\n\t_id.read = _fff_wrap(_id, (_id.read+1));\t\t\t\t\t\\\n\t_return;\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n})\n\n// returns the next element from the fifo and removes it from the memory\n// if no element is available, 0 is returned\n// _id: C conform identifier\n#define _fff_read(_id)\t\t\t\t\t\t\t\t\t\t\t\\\n({\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\ttypeof(_id.data[0])\t_return = (typeof(_id.data[0])){0};\t\t\\\n\tif(!_fff_is_empty(_id))\t\t\t\t\t\t\t\t\t\t\\\n\t\t_return = _fff_read_lite(_id);\t\t\t\t\t\t\t\\\n\t_return;\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n})\t\n\n\t\t\t\t \n// adds an element to the fifo\n// Use if(!_fff_is_full(_id)) if amount of stored data is unknown\n// _id:\t\tC conform identifier\n// newdata:\tdata to be written\n#define _fff_write_lite(_id, newdata)\t\t\t\t\t\t\t\\\ndo{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t_id.data[_id.write] = (newdata);\t\t\t\t\t\t\t\\\n\t_id.write = _fff_wrap(_id, (_id.write+1));\t\t\t\t\t\\\n\t_id.level++;\t\t\t\t\t\t\t\t\t\t\t\t\\\n}while(0)\n\n// adds an element to the fifo, if space is available\n// if full element will be dismissed\n// _id:\t\tC conform identifier\n// newdata:\tdata to be written\n#define _fff_write(_id, newdata)\t\t\t\t\t\t\t\t\\\ndo{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tif(!_fff_is_full(_id))\t\t\t\t\t\t\t\t\t\t\\\n\t\t_fff_write_lite(_id, newdata);\t\t\t\t\t\t\t\\\n}while(0)\n\n// copies an array of elements to the fifo as long as space is available\n// if full all excess elements will be dismissed\n// _id:\t\tC conform identifier\n// newdata:\tarray of data to be written\n// n:       amount of data do be written\n#define _fff_write_multiple(_id, newdata, n)\t\t\t\t\t\\\ndo{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n    typeof(_id.level) tocopy, btw;\t\t\t\t\t\t\t\t\\\n    btw = _min(_fff_mem_free(_id), (n));\t\t\t\t\t\t\\\n    if (btw == 0) {\t\t\t\t\t\t\t\t\t\t\t\t\\\n        break;\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n    }\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n    tocopy = _min(btw, _fff_mem_depth(_id) - _id.write);\t\t\\\n    memcpy(&_id.data[_id.write], (newdata), tocopy);\t\t\t\\\n    _id.level += tocopy;\t\t\t\t\t\t\t\t\t\t\\\n    _id.write = _fff_wrap(_id, (_id.write+tocopy));\t\t\t\t\\\n    btw -= tocopy;\t\t\t\t\t\t\t\t\t\t\t\t\\\n    if (btw > 0) {\t\t\t\t\t\t\t\t\t\t\t\t\\\n        memcpy(&_id.data[_id.write], (newdata)+tocopy, btw);\t\\\n        _id.write = btw;\t\t\t\t\t\t\t\t\t\t\\\n        _id.level += btw;\t\t\t\t\t\t\t\t\t\t\\\n    }\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n}while(0)\n\n// adds an element to the fifo, but does not write any data to it. instead, a pointer to the data\n// section is returned. The caller may write up to _fff_data_size(_id) bytes to this location.\n// Use if(!_fff_is_full(_id)) if amount of stored data is unknown\n// _id: C conform identifier\n#define _fff_add_lite(_id)\t\t\t\t\t\t\t\t\t\t\\\n({\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\ttypeof(&_id.data[0]) _return = & _id.data[_id.write];\t\t\\\n\t_id.write = _fff_wrap(_id, (_id.write+1));\t\t\t\t\t\\\n\t_id.level++;\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t_return;\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n})\n\n// like _fff_add_lite(_id), but checks if space is available before writing. Returns 'null' if full.\n// _id: C conform identifier\n#define _fff_add(_id)\t\t\t\t\t\t\t\t\t\t\t\\\n({\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\ttypeof(&_id.data[0]) _return = (typeof(&_id.data[0]))NULL;\t\\\n\tif(!_fff_is_full(_id))\t\t\t\t\t\t\t\t\t\t\\\n\t\t_return = _fff_add_lite(_id);\t\t\t\t\t\t\t\\\n\t_return;\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n})\n\n\n// allows accessing the data of a fifo as an array without removing any elements\n// Like any array this function can be used as a right or left site operant. Attempting to access\n// more elements than currently in the buffer will return undefined data on read and will have no\n// effect on write. Accidental read/write operations outside the assigned data space are not\n// possible.\n// This macro is NOT ATOMIC. If fifo \"_id\" is accessed within an ISR at least once, this macro MUST\n// be placed within an atomic block outside of any ISR.\n// _id:\t\tC conform identifier\n// idx:\t\tOffset from the first element in the buffer\n#define _fff_peek(_id, idx)\t\t\t\t_id.data[_fff_wrap(_id, _id.read+(idx))]\n\n\n// re-writes the internal array, so that the element _fff_peek(0) will be at the physical idx 0\n// Although this does not effect any of the fifo functions, it does simplify operations on string\n// stored in the fifo.\n// NOTE that this macro copies element-by-element and might take very long for large fifos with many\n// elements or large data sizes.\n//\n// Macro inspired by Jon Bentley's array rotation algorithm and this stackoverflow answer:\n// https://stackoverflow.com/a/22079960/6215916\n//\n// This version has only one call of _FFF_REVERSE to safe program memory\n#define _fff_rebase(_id)\t\t\t\t\t\t\t\t\t\t\\\ndo{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t/* check if rebase required */\t\t\t\t\t\t\t\t\\\n\tif (_id.read == 0)\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tbreak;\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\ttypeof(_id.read) idx1, idx2;\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t/* reversing 1st half, 2nd half and everything together\t*/\t\\\n\t/* rotates the array\t\t\t\t\t\t\t\t\t*/\t\\\n\tfor (uint8_t rep = 0; rep<3; rep++)\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tswitch (rep)\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tdefault:\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tcase 0:\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\tidx1 = 0;\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\tidx2 = _id.read-1;\t\t\t\t\t\t\t\t\\\n\t\t\t\tbreak;\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tcase 1:\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\tidx1 = _id.read;\t\t\t\t\t\t\t\t\\\n\t\t\t\tidx2 = _fff_mem_mask(_id);\t\t\t\t\t\t\\\n\t\t\t\tbreak;\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tcase 2:\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\tidx1 = 0;\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\tidx2 = _fff_mem_mask(_id);\t\t\t\t\t\t\\\n\t\t\t\tbreak;\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t/* reverse section from idx1 to idx2 */\t\t\t\t\t\\\n\t\tfor (; idx1 < idx2; idx1++, idx2--)\t\t\t\t\t\t\\\n\t\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\ttypeof(_id.data[0]) tmp;\t\t\t\t\t\t\t\\\n\t\t\ttmp\t\t\t\t= _id.data[idx1];\t\t\t\t\t\\\n\t\t\t_id.data[idx1]\t= _id.data[idx2];\t\t\t\t\t\\\n\t\t\t_id.data[idx2]\t= tmp;\t\t\t\t\t\t\t\t\\\n\t\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t/* Update data indices */\t\t\t\t\t\t\t\t\t\\\n\t_id.write\t= _id.write - _id.read;\t\t\t\t\t\t\t\\\n\t_id.read\t= 0;\t\t\t\t\t\t\t\t\t\t\t\\\n}while(0)\n\n//////////////////////////////////////////////////////////////////////////\n// Inline functions\n//////////////////////////////////////////////////////////////////////////\n\n// Inline functions MUST be defined in the .h, not in the .c file to work correctly!\n\n// auxiliary functions\nstatic inline fff_index_t fff_wrap(fff_proto_t *fifo, fff_index_t idx)\n{\n\treturn (idx & fifo->mask);\n}\nstatic inline void* fff_data_p(fff_proto_t *fifo, fff_index_t idx)\n{\n\treturn &(fifo->data[idx * fifo->data_size]);\n}\nstatic inline fff_index_t fff_mem_mask(fff_proto_t *fifo)\n{\n\treturn (fifo->mask);\n}\nstatic inline fff_index_t fff_data_size(fff_proto_t *fifo)\n{\n\treturn fifo->data_size;\n}\n\n//\nstatic inline uint8_t fff_is_empty(fff_proto_t *fifo)\n{\n\treturn (fifo->level == 0);\n}\nstatic inline uint8_t fff_is_full(fff_proto_t *fifo)\n{\n\treturn (fifo->level > fifo->mask);\n}\nstatic inline fff_level_t fff_mem_level(fff_proto_t *fifo)\n{\n\treturn (fifo->level);\n}\nstatic inline fff_index_t fff_mem_free(fff_proto_t *fifo)\n{\n\treturn (fifo->mask - fifo->level + 1);\n}\n\n//\nstatic inline void fff_reset(fff_proto_t *fifo)\n{\n\tfifo->read\t= 0;\n\tfifo->write\t= 0;\n\tfifo->level = 0;\n}\n\n\nstatic inline void fff_remove(fff_proto_t *fifo, fff_level_t amount)\n{\n\tif (amount > fifo->level)\n\t\tamount = fifo->level;\n\tfff_remove_lite(fifo, amount);\n}\nstatic inline void fff_remove_lite(fff_proto_t *fifo, fff_level_t amount)\n{\n\tfifo->level -= amount;\n\tfifo->read = fff_wrap(fifo, fifo->read + amount);\n}\n\nstatic inline void fff_write(fff_proto_t *fifo, void *data)\n{\n\tif (!fff_is_full(fifo))\n\tfff_write_lite(fifo,data);\n}\nstatic inline void fff_write_lite(fff_proto_t *fifo, void *data)\n{\n\tmemcpy(fff_data_p(fifo, fifo->write), data, fifo->data_size);\n\tfifo->write = fff_wrap(fifo, fifo->write+1);\n\tfifo->level++;\n}\n\n// the peek function MUST be split into two to work as a normal c function\n// BOTH function STILL refer to the top (read) end of the fifo\nstatic inline void* fff_peek_read(fff_proto_t *fifo, fff_index_t idx)\n{\n\treturn fff_data_p(fifo, fff_wrap(fifo, fifo->read+idx));\n}\nstatic inline void fff_peek_write(fff_proto_t *fifo, fff_index_t idx, void *data)\n{\n\tmemcpy(fff_data_p(fifo, fff_wrap(fifo, fifo->read+idx)), data, fifo->data_size);\n}\n\n\n#endif /* FIFOFAST_H_ */"
  },
  {
    "path": "fifofast_demo.c",
    "content": "/*\n * fifofast_demo.c\n *\n * Created: 17.09.2018 19:21:17\n *  Author: Dennis aka nqtronix (github.com/nqtronix)\n *\n * Description:\n * This file contains some demo code to try out the provided macros. Simply run it in the simulator\n * and inspect the step-by-step changes with the debugger.\n */ \n\n#include \"fifofast_demo.h\"\n#include \"fifofast_test.h\"\n\n\nint main(void)\n{\n\t//////////////////////////////////////////////////////////////////////////\n\t// Test Environment\n\t//////////////////////////////////////////////////////////////////////////\n\t\n\t// Note: only fifo_uint8 is tested here as uint8 are most easy to work with\n\t// after each change (or set of changes) call all returning functions\n\t//\n\t// The compiler MAY optimize these test strongly, and may not generate all assembler code.\n\t// To debug the tests, please disable optimization.\n\tfifofast_test_macro_initial();\n\tfifofast_test_macro_write(0x10);\n\tfifofast_test_macro_peek(0x20);\n\tfifofast_test_macro_read(0x30);\n\tfifofast_test_macro_add(0x40);\n\tfifofast_test_macro_remove_lite(0x50);\n\tfifofast_test_macro_remove(0x60);\n\tfifofast_test_macro_rebase(0x70);\n\tfifofast_test_macro_write_multiple(0x80);\n\t\n\tfifofast_test_func_initial((fff_proto_t*)&fifo_uint8p);\n\tfifofast_test_func_write((fff_proto_t*)&fifo_uint8p, 0x80);\n\tfifofast_test_func_peek((fff_proto_t*)&fifo_uint8p, 0x90);\n\tfifofast_test_func_remove_lite((fff_proto_t*)&fifo_uint8p, 0xa0);\n\tfifofast_test_func_remove((fff_proto_t*)&fifo_uint8p, 0xb0);\n\t\n\tUT_BREAK();\n\n\n\t//////////////////////////////////////////////////////////////////////////\n\t// Demonstrate usage of fifo array\n\t//////////////////////////////////////////////////////////////////////////\n\n\t// macros have been proved to work, so to see the result just look into the SRAM directly\n\t// These two loops copy the printable chars into the sram, each fifo gets a section of 16\n\t// consecutive characters.\n\tuint8_t data = ' ';\n\tfor (uint8_t fifo_nr = 0; fifo_nr < _sizeof_array(fifo_array); fifo_nr++)\n\t{\n\t\tfor (uint8_t idx = 0; idx < _fff_mem_depth(fifo_array[0]); idx++)\n\t\t{\n\t\t\t_fff_write(fifo_array[fifo_nr], data);\n\t\t\tdata += 1;\n\t\t}\n\t}\n\n\n\t// End simulation\n\tUT_BREAK();\n    while (1);\n}"
  },
  {
    "path": "fifofast_demo.h",
    "content": "/*\r\n * fifofast_demo.h\r\n *\r\n * Created: 08.11.2018 08:46:08\r\n *  Author: Dennis\r\n *\r\n * Description:\r\n * This file declares all fifos used by the demo. If declared in a header, they can be accessed by\r\n * all files, that include this header. In this particular case it is needed for 'fifofast_test.c'.\r\n * If a fifo does NOT need to be access from multiple files (i.e. if used as a buffer for ISRs),\r\n * they can be declared in a c file.\r\n */ \r\n\r\n\r\n#ifndef FIFOFAST_DEMO_H_\r\n#define FIFOFAST_DEMO_H_\r\n\r\n#include \"fifofast.h\"\r\n\r\n\r\n// declare a fifo with 4 elements of type 'uint8_t' with the name 'fifo_uint8'\r\n_fff_declare(uint8_t __attribute__((aligned(4))), fifo_uint8, 4);\r\n\r\n// declare same fifo as above, but it can be passed by pointer to functions\r\n_fff_declare_p(uint8_t, fifo_uint8p, 4);\r\n\r\n// declare a fifo with 8 elements (6 elements is not possible, so it is automatically bumped to 8)\r\n// of type 'int_16' with the name 'fifo_uint16'\r\n_fff_declare(int16_t, fifo_int16, 6);\r\n\r\n// fifofast also supports more complicated data such as frames used for serial data transmission.\r\n// It is often useful to access the data not only in binary format ('raw'), but also as a struct\r\n// ('header'). In this case the header contains a variable >1 byte, which needs to be stored aligned\r\n// on most architectures. However the union is treaded by default as a 'uint8_t' array, so no\r\n// alignment is enforced. To do this manually, GCC supports the attribute 'aligned(n)'. See\r\n// documentation of GCC for more details.\r\ntypedef struct\r\n{\r\n\tuint16_t control;\r\n\tuint8_t length;\r\n\tuint8_t id;\r\n\tuint8_t data[];\r\n} header_t;\r\ntypedef union __attribute__((aligned(4), packed))\r\n{\r\n\tuint8_t raw[32];\r\n\theader_t header;\r\n} frame_u;\r\n\r\n// declare a fifo to store 4 elements of the typedef'd union 'frame_u'\r\n_fff_declare(frame_u, fifo_frame, 4);\r\n\r\n// declare an array (indicated by the suffix _a) of 5 fifos with 16 elements each.\r\n_fff_declare_a(uint8_t, fifo_array, 16, 5);\r\n\r\n\r\n#endif /* FIFOFAST_DEMO_H_ */"
  },
  {
    "path": "fifofast_test.c",
    "content": "/*\n * fifofast_test.c\n *\n * Created: 08.11.2018 08:34:58\n *  Author: Dennis\n */ \n\n#include \"fifofast_test.h\"\n\n///////////////////////////////////////////////////////////////////////////////\n// Initialize fifos for global access\n///////////////////////////////////////////////////////////////////////////////\n\n// initialize all fifos\n_fff_init(fifo_uint8);\n_fff_init_p(fifo_uint8p);\n_fff_init(fifo_int16);\n_fff_init(fifo_frame);\n_fff_init_a(fifo_array, 5);\n\n\n//////////////////////////////////////////////////////////////////////////\n// Test Macros\n//////////////////////////////////////////////////////////////////////////\n\nvoid fifofast_test_macro_initial()\n{\n\tUT_ASSERT(_fff_mem_depth(fifo_uint8)\t== 4);\t\t// constant\n\tUT_ASSERT(_fff_mem_mask(fifo_uint8)\t\t== 3);\t\t// constant = 0b11\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 0);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 4);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t!= 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n}\n\nvoid fifofast_test_macro_write(uint8_t startvalue)\n{\n\t// add 2 values with the fast '_lite' variant (after init we know it is empty)\n\t// use unusual values (NOT 0, 1, 2 ...) to decrease the likelihood of false positives\n\t_fff_write_lite(fifo_uint8, startvalue+0);\n\t_fff_write_lite(fifo_uint8, startvalue+1);\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 2);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 2);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+0);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+1);\n\tUT_BREAK();\n\n\n\t// add 3 values to demonstrate overflow safety\n\t_fff_write(fifo_uint8, startvalue+2);\n\t_fff_write(fifo_uint8, startvalue+3);\n\t_fff_write(fifo_uint8, startvalue+4);\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 4);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t!= 0);\n\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+0);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+1);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 2)\t\t== startvalue+2);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 3)\t\t== startvalue+3);\n\t\n\t_fff_reset(fifo_uint8);\n\t\n\t// Test reset once only\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 0);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 4);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t!= 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n}\n\nvoid fifofast_test_macro_peek(uint8_t startvalue)\n{\n\t_fff_write_lite(fifo_uint8, startvalue+0);\n\t_fff_write_lite(fifo_uint8, startvalue+1);\n\t_fff_write_lite(fifo_uint8, startvalue+2);\n\t\n\t// modify existing value (index 0 and 2) with _fff_peek()\n\t_fff_peek(fifo_uint8, 0) = startvalue+3;\n\t_fff_peek(fifo_uint8, 2) = startvalue+4;\n\t\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 3);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 1);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+3);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+1);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 2)\t\t== startvalue+4);\n\t\n\t// demonstrate \"out of bounds\" safety (no over-read/ over-write possible)\n\tUT_ASSERT(_fff_peek(fifo_uint8, 4)\t\t== startvalue+3);\n\t\n\t_fff_reset(fifo_uint8);\n}\n\nvoid fifofast_test_macro_read(uint8_t startvalue)\n{\n\t_fff_write_lite(fifo_uint8, startvalue+0);\n\t_fff_write_lite(fifo_uint8, startvalue+1);\n\t_fff_write_lite(fifo_uint8, startvalue+2);\n\t\n\t// read 2 values with the fast '_lite' variant (we know we have more than two entries)\n\tUT_ASSERT(_fff_read_lite(fifo_uint8)\t== startvalue+0);\n\tUT_ASSERT(_fff_read_lite(fifo_uint8)\t== startvalue+1);\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 1);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 3);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+2);\n\n\t// read 2 values to demonstrate overflow safety\n\tUT_ASSERT(_fff_read(fifo_uint8)\t\t\t== startvalue+2);\n\tUT_ASSERT(_fff_read(fifo_uint8)\t\t\t== 0x00);\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 0);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 4);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t!= 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n\t\n\t_fff_reset(fifo_uint8);\n}\n\nvoid fifofast_test_macro_add(uint8_t startvalue)\n{\n\t__attribute__ ((unused)) volatile uint8_t* dbg_p0 = 0;\n\t__attribute__ ((unused)) volatile uint8_t* dbg_p1 = 0;\n\t__attribute__ ((unused)) volatile uint8_t* dbg_p2 = 0;\n\t\n\t// add 2 values with the fast '_lite' variant (after init we know it is empty)\n\tdbg_p0 = _fff_add_lite(fifo_uint8);\n\tdbg_p1 = _fff_add_lite(fifo_uint8);\n\n\tUT_ASSERT(dbg_p0 != 0);\n\tUT_ASSERT(dbg_p1 != 0);\n\n\tif(dbg_p0 != 0) *dbg_p0 = startvalue+0;\n\tif(dbg_p1 != 0) *dbg_p1 = startvalue+1;\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 2);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 2);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n\t\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+0);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+1);\n\n\n\t// add 3 values to demonstrate overflow safety\n\tdbg_p0 = _fff_add(fifo_uint8);\n\tdbg_p1 = _fff_add(fifo_uint8);\n\tdbg_p2 = _fff_add(fifo_uint8);\n\n\tUT_ASSERT(dbg_p0 != 0);\n\tUT_ASSERT(dbg_p1 != 0);\n\tUT_ASSERT(dbg_p2 == 0);\t\t// the fifo is full, so a null pointer must be returned\n\n\tif(dbg_p0 != 0) *dbg_p0 = startvalue+2;\n\tif(dbg_p1 != 0) *dbg_p1 = startvalue+3;\n\tif(dbg_p2 != 0) *dbg_p2 = startvalue+4;\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 4);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t!= 0);\n\t\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+0);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+1);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 2)\t\t== startvalue+2);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 3)\t\t== startvalue+3);\n\t\n\t_fff_reset(fifo_uint8);\n}\n\nvoid fifofast_test_macro_remove_lite(uint8_t startvalue)\n{\n\t// fill with any data (macros have been proved to work before)\n\t_fff_write_lite(fifo_uint8, startvalue+0);\n\t_fff_write_lite(fifo_uint8, startvalue+1);\n\t_fff_write_lite(fifo_uint8, startvalue+2);\n\t_fff_write_lite(fifo_uint8, startvalue+3);\n\t// fifo is now full\n\n\t\t\n\t// _remove 2 (Test case: fifo full before macro)\n\t_fff_remove_lite(fifo_uint8, 2);\n\t\t\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 2);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 2);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n\t\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+2);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+3);\n\n\n\t// _remove 1 (Test case: fifo not full before and not empty after macro)\n\t_fff_remove_lite(fifo_uint8, 1);\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 1);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 3);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n\t\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+3);\n\t\n\t\n\t// _remove 1 (Test case: fifo empty after macro)\n\t_fff_remove_lite(fifo_uint8, 1);\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 0);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 4);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t!= 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n\t\n\t_fff_reset(fifo_uint8);\n}\n\nvoid fifofast_test_macro_remove(uint8_t startvalue)\n{\n\t// fill with any data (macros have been proved to work before)\n\t_fff_write_lite(fifo_uint8, startvalue+0);\n\t_fff_write_lite(fifo_uint8, startvalue+1);\n\t_fff_write_lite(fifo_uint8, startvalue+2);\n\t_fff_write_lite(fifo_uint8, startvalue+3);\n\t// fifo is now full\n\t\n\t\n\t// _remove 0 (Test case: amount == 0 elements)\n\t_fff_remove(fifo_uint8, 0);\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 4);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t!= 0);\n\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+0);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+1);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 2)\t\t== startvalue+2);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 3)\t\t== startvalue+3);\n\n\n\t// _remove 4 (Test case: amount == _fff_mem_level() w/ fifo full)\n\t_fff_remove(fifo_uint8, 4);\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 0);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 4);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t!= 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 0);\n}\n\nvoid fifofast_test_macro_rebase(uint8_t startvalue)\n{\n\t//////////////////////////////////////////////////////////////////////////\n\t// Test 1: no rebase needed\n\t\n\t// fill with any data (macros have been proved to work before)\n\t_fff_write_lite(fifo_uint8, startvalue+0);\n\t_fff_write_lite(fifo_uint8, startvalue+1);\n\t_fff_write_lite(fifo_uint8, startvalue+2);\n\t_fff_write_lite(fifo_uint8, startvalue+3);\n\t\n\t_fff_rebase(fifo_uint8);\n\t\n\t// Confirm it is exactly like before:\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 4);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t!= 0);\n\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+0);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+1);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 2)\t\t== startvalue+2);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 3)\t\t== startvalue+3);\n\t\n\t// confirm that the element 0 is at array index 0\n\tUT_ASSERT(&_fff_peek(fifo_uint8, 0)\t\t== &fifo_uint8.data[0]);\n\t\n\t_fff_reset(fifo_uint8);\n\t\n\t\n\t//////////////////////////////////////////////////////////////////////////\n\t// Test 3: move 2 elements\n\t\t\n\t// fill with any data (macros have been proved to work before)\n\t_fff_write_lite(fifo_uint8, startvalue+0);\n\t_fff_write_lite(fifo_uint8, startvalue+1);\n\t_fff_write_lite(fifo_uint8, startvalue+2);\n\t_fff_write_lite(fifo_uint8, startvalue+3);\n\t\t\n\t_fff_read_lite(fifo_uint8);\n\t_fff_write_lite(fifo_uint8, startvalue+4);\n\t\t\n\t_fff_rebase(fifo_uint8);\n\t\t\n\t// Confirm it is exactly like before:\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 4);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t!= 0);\n\t\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+1);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+2);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 2)\t\t== startvalue+3);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 3)\t\t== startvalue+4);\n\t\t\n\t// confirm that the element 0 is at array index 0\n\tUT_ASSERT(&_fff_peek(fifo_uint8, 0)\t\t== &fifo_uint8.data[0]);\n\t\t\n\t_fff_reset(fifo_uint8);\n\t\n\t\n\t//////////////////////////////////////////////////////////////////////////\n\t// Test 3: move 2 elements\n\t\n\t// fill with any data (macros have been proved to work before)\n\t_fff_write_lite(fifo_uint8, startvalue+0);\n\t_fff_write_lite(fifo_uint8, startvalue+1);\n\t_fff_write_lite(fifo_uint8, startvalue+2);\n\t_fff_write_lite(fifo_uint8, startvalue+3);\n\t\n\t_fff_read_lite(fifo_uint8);\n\t_fff_read_lite(fifo_uint8);\n\t_fff_write_lite(fifo_uint8, startvalue+4);\n\t_fff_write_lite(fifo_uint8, startvalue+5);\n\t\n\t_fff_rebase(fifo_uint8);\n\t\n\t// Confirm it is exactly like before:\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 4);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t!= 0);\n\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+2);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+3);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 2)\t\t== startvalue+4);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 3)\t\t== startvalue+5);\n\t\n\t// confirm that the element 0 is at array index 0\n\tUT_ASSERT(&_fff_peek(fifo_uint8, 0)\t\t== &fifo_uint8.data[0]);\n\t\n\t_fff_reset(fifo_uint8);\n\t\n\t\n\t//////////////////////////////////////////////////////////////////////////\n\t// Test 2: move 3 elements\n\t\n\t// fill with any data (macros have been proved to work before)\n\t_fff_write_lite(fifo_uint8, startvalue+0);\n\t_fff_write_lite(fifo_uint8, startvalue+1);\n\t_fff_write_lite(fifo_uint8, startvalue+2);\n\t_fff_write_lite(fifo_uint8, startvalue+3);\n\t\n\t_fff_read_lite(fifo_uint8);\n\t_fff_read_lite(fifo_uint8);\n\t_fff_read_lite(fifo_uint8);\n\t_fff_write_lite(fifo_uint8, startvalue+4);\n\t_fff_write_lite(fifo_uint8, startvalue+5);\n\t_fff_write_lite(fifo_uint8, startvalue+6);\n\t\n\t_fff_rebase(fifo_uint8);\n\t\n\t// Confirm it is exactly like before:\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 4);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t!= 0);\n\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+3);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+4);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 2)\t\t== startvalue+5);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 3)\t\t== startvalue+6);\n\t\n\t// confirm that the element 0 is at array index 0\n\tUT_ASSERT(&_fff_peek(fifo_uint8, 0)\t\t== &fifo_uint8.data[0]);\n\t\n\t_fff_reset(fifo_uint8);\n}\n\nvoid fifofast_test_macro_write_multiple(uint8_t startvalue) {\n\tuint8_t multidata[4] = {startvalue + 3, startvalue + 4, startvalue + 5, startvalue + 6};\n\n\t// initialize fifo with some data\n\t_fff_write_lite(fifo_uint8, startvalue+0);\n\t_fff_write_lite(fifo_uint8, startvalue+1);\n\t_fff_write_lite(fifo_uint8, startvalue+2);\n\t_fff_remove_lite(fifo_uint8, 2);\n\n\t// write test data, case: all data fits\n\t_fff_write_multiple(fifo_uint8, multidata, 3);\n\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+2);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+3);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 2)\t\t== startvalue+4);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 3)\t\t== startvalue+5);\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 4);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 1);\n\t\n\t_fff_reset(fifo_uint8);\n\t\n\t// re-initialize fifo with some data\n\t_fff_write_lite(fifo_uint8, startvalue+7);\n\t_fff_write_multiple(fifo_uint8, multidata, 3);\n\t\n\t// write test data, case: NOT all data fits (overflow is discarded)\n\t_fff_write_multiple(fifo_uint8, multidata, 4);\n\t\n\tUT_ASSERT(_fff_peek(fifo_uint8, 0)\t\t== startvalue+7);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 1)\t\t== startvalue+3);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 2)\t\t== startvalue+4);\n\tUT_ASSERT(_fff_peek(fifo_uint8, 3)\t\t== startvalue+5);\n\n\tUT_ASSERT(_fff_mem_level(fifo_uint8)\t== 4);\n\tUT_ASSERT(_fff_mem_free(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_empty(fifo_uint8)\t\t== 0);\n\tUT_ASSERT(_fff_is_full(fifo_uint8)\t\t== 1);\n}\n\n//////////////////////////////////////////////////////////////////////////\n// Test Functions\n//////////////////////////////////////////////////////////////////////////\n\nvoid fifofast_test_func_initial(fff_proto_t* fifo)\n{\n\t//UT_ASSERT(fff_mem_depth(fifo)\t\t\t== 4);\t\t// constant\n\tUT_ASSERT(fff_mem_mask(fifo)\t\t\t== 3);\t\t// constant = 0b11\n\tUT_ASSERT(fff_mem_level(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_mem_free(fifo)\t\t\t== 4);\n\tUT_ASSERT(fff_is_empty(fifo)\t\t\t!= 0);\n\tUT_ASSERT(fff_is_full(fifo)\t\t\t\t== 0);\n}\n\nvoid fifofast_test_func_write(fff_proto_t* fifo, uint8_t startvalue)\n{\n\t// add 2 values with the fast '_lite' variant (after init we know it is empty)\n\t// use unusual values (NOT 0, 1, 2 ...) to decrease the likelihood of false positives\n\tuint8_t tmp0 = startvalue+0;\n\tuint8_t tmp1 = startvalue+1;\n\tfff_write_lite(fifo, &tmp0);\n\tfff_write_lite(fifo, &tmp1);\n\n\tUT_ASSERT(fff_mem_level(fifo)\t\t\t== 2);\n\tUT_ASSERT(fff_mem_free(fifo)\t\t\t== 2);\n\tUT_ASSERT(fff_is_empty(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_is_full(fifo)\t\t\t\t== 0);\n\t\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 0)\t\t== startvalue+0);\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 1)\t\t== startvalue+1);\n\n\n\t// add 3 values to demonstrate overflow safety\n\tuint8_t tmp2 = startvalue+2;\n\tuint8_t tmp3 = startvalue+3;\n\tuint8_t tmp4 = startvalue+4;\n\tfff_write(fifo, &tmp2);\n\tfff_write(fifo, &tmp3);\n\tfff_write(fifo, &tmp4);\n\n\tUT_ASSERT(fff_mem_level(fifo)\t\t\t== 4);\n\tUT_ASSERT(fff_mem_free(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_is_empty(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_is_full(fifo)\t\t\t\t!= 0);\n\t\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 0)\t\t== startvalue+0);\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 1)\t\t== startvalue+1);\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 2)\t\t== startvalue+2);\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 3)\t\t== startvalue+3);\n\t\n\tfff_reset(fifo);\n\t\n\t// Test reset once only\n\tUT_ASSERT(fff_mem_level(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_mem_free(fifo)\t\t\t== 4);\n\tUT_ASSERT(fff_is_empty(fifo)\t\t\t!= 0);\n\tUT_ASSERT(fff_is_full(fifo)\t\t\t\t== 0);\n}\n\nvoid fifofast_test_func_peek(fff_proto_t* fifo, uint8_t startvalue)\n{\n\tuint8_t tmp0 = startvalue+0;\n\tuint8_t tmp1 = startvalue+1;\n\tuint8_t tmp2 = startvalue+2;\n\tfff_write_lite(fifo, &tmp0);\n\tfff_write_lite(fifo, &tmp1);\n\tfff_write_lite(fifo, &tmp2);\n\t\n\t// modify existing value (index 0 and 2) with _fff_peek()\n\tuint8_t tmp3 = startvalue+3;\n\tuint8_t tmp4 = startvalue+4;\n\tfff_peek_write(fifo, 0, &tmp3);\n\tfff_peek_write(fifo, 2, &tmp4);\n\t\n\tUT_ASSERT(fff_mem_level(fifo)\t\t\t== 3);\n\tUT_ASSERT(fff_mem_free(fifo)\t\t\t== 1);\n\tUT_ASSERT(fff_is_empty(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_is_full(fifo)\t\t\t\t== 0);\n\t\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 0)\t\t== startvalue+3);\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 1)\t\t== startvalue+1);\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 2)\t\t== startvalue+4);\n\t\n\t// demonstrate \"out of bounds\" safety (no over-read/ over-write possible)\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 4)\t\t== startvalue+3);\n\t\n\tfff_reset(fifo);\n}\n\nvoid fifofast_test_func_remove_lite(fff_proto_t* fifo, uint8_t startvalue)\n{\n\t// fill with any data (macros have been proved to work before)\n\tuint8_t tmp0 = startvalue+0;\n\tuint8_t tmp1 = startvalue+1;\n\tuint8_t tmp2 = startvalue+2;\n\tuint8_t tmp3 = startvalue+3;\n\tfff_write_lite(fifo, &tmp0);\n\tfff_write_lite(fifo, &tmp1);\n\tfff_write_lite(fifo, &tmp2);\n\tfff_write_lite(fifo, &tmp3);\n\t// fifo is now full\n\n\t\n\t// _remove 2 (Test case: fifo full before macro)\n\tfff_remove_lite(fifo, 2);\n\t\n\tUT_ASSERT(fff_mem_level(fifo)\t\t\t== 2);\n\tUT_ASSERT(fff_mem_free(fifo)\t\t\t== 2);\n\tUT_ASSERT(fff_is_empty(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_is_full(fifo)\t\t\t\t== 0);\n\t\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 0)\t\t== startvalue+2);\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 1)\t\t== startvalue+3);\n\n\n\t// _remove 1 (Test case: fifo not full before and not empty after macro)\n\tfff_remove_lite(fifo, 1);\n\n\tUT_ASSERT(fff_mem_level(fifo)\t\t\t== 1);\n\tUT_ASSERT(fff_mem_free(fifo)\t\t\t== 3);\n\tUT_ASSERT(fff_is_empty(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_is_full(fifo)\t\t\t\t== 0);\n\t\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 0)\t\t== startvalue+3);\n\t\n\t\n\t// _remove 1 (Test case: fifo empty after macro)\n\tfff_remove_lite(fifo, 1);\n\n\tUT_ASSERT(fff_mem_level(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_mem_free(fifo)\t\t\t== 4);\n\tUT_ASSERT(fff_is_empty(fifo)\t\t\t!= 0);\n\tUT_ASSERT(fff_is_full(fifo)\t\t\t\t== 0);\n\t\n\tfff_reset(fifo);\n}\n\nvoid fifofast_test_func_remove(fff_proto_t* fifo, uint8_t startvalue)\n{\n\t// fill with any data (macros have been proved to work before)\n\tuint8_t tmp0 = startvalue+0;\n\tuint8_t tmp1 = startvalue+1;\n\tuint8_t tmp2 = startvalue+2;\n\tuint8_t tmp3 = startvalue+3;\n\tfff_write_lite(fifo, &tmp0);\n\tfff_write_lite(fifo, &tmp1);\n\tfff_write_lite(fifo, &tmp2);\n\tfff_write_lite(fifo, &tmp3);\n\t// fifo is now full\n\t\n\t\n\t// _remove 0 (Test case: amount == 0 elements)\n\tfff_remove(fifo, 0);\n\n\tUT_ASSERT(fff_mem_level(fifo)\t\t\t== 4);\n\tUT_ASSERT(fff_mem_free(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_is_empty(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_is_full(fifo)\t\t\t\t!= 0);\n\t\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 0)\t\t== startvalue+0);\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 1)\t\t== startvalue+1);\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 2)\t\t== startvalue+2);\n\tUT_ASSERT(*(uint8_t*)fff_peek_read(fifo, 3)\t\t== startvalue+3);\n\n\n\t// _remove 4 (Test case: amount == _fff_mem_level() w/ fifo full)\n\tfff_remove(fifo, 4);\n\n\tUT_ASSERT(fff_mem_level(fifo)\t\t\t== 0);\n\tUT_ASSERT(fff_mem_free(fifo)\t\t\t== 4);\n\tUT_ASSERT(fff_is_empty(fifo)\t\t\t!= 0);\n\tUT_ASSERT(fff_is_full(fifo)\t\t\t\t== 0);\n\n}\n"
  },
  {
    "path": "fifofast_test.h",
    "content": "/*\n * fifofast_test.h\n *\n * Created: 08.11.2018 08:35:16\n *  Author: Dennis\n *\n * Description:\n * This file contains automated tests powered by unittrace.\n */ \n\n\n#ifndef FIFOFAST_TEST_H_\n#define FIFOFAST_TEST_H_\n\n#include \"fifofast_demo.h\"\n#include \"unittrace/unittrace.h\"\n\n//////////////////////////////////////////////////////////////////////////\n// Function Declarations\n//////////////////////////////////////////////////////////////////////////\n\nvoid fifofast_test_macro_initial(void);\nvoid fifofast_test_macro_write(uint8_t startvalue);\nvoid fifofast_test_macro_peek(uint8_t startvalue);\nvoid fifofast_test_macro_read(uint8_t startvalue);\nvoid fifofast_test_macro_add(uint8_t startvalue);\nvoid fifofast_test_macro_remove_lite(uint8_t startvalue);\nvoid fifofast_test_macro_remove(uint8_t startvalue);\nvoid fifofast_test_macro_rebase(uint8_t startvalue);\nvoid fifofast_test_macro_write_multiple(uint8_t startvalue);\n\nvoid fifofast_test_func_initial(fff_proto_t* fifo);\nvoid fifofast_test_func_write(fff_proto_t* fifo, uint8_t startvalue);\nvoid fifofast_test_func_peek(fff_proto_t* fifo, uint8_t startvalue);\nvoid fifofast_test_func_remove_lite(fff_proto_t* fifo, uint8_t startvalue);\nvoid fifofast_test_func_remove(fff_proto_t* fifo, uint8_t startvalue);\n\n#endif /* FIFOFAST_TEST_H_ */"
  },
  {
    "path": "subrepos/readme (license info).txt",
    "content": "This folder contains other projects with their own source code and associated files. The included LICENSE files ONLY apply to the folder (and the project) they are located in."
  },
  {
    "path": "subrepos/unittrace/.gitignore",
    "content": "/Debug\r\n/.vs"
  },
  {
    "path": "subrepos/unittrace/LICENSE.md",
    "content": "MIT License\r\n\r\nCopyright (c) 2018 nqtronix (github.com/nqtronix)\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n"
  },
  {
    "path": "subrepos/unittrace/README.md",
    "content": "<h1 align=\"center\" style=\"font-weight: bold; margin-top: 20px; margin-bottom: 20px;\">unittrace</h4>\r\n\r\n<h4 align=\"center\"> A simple testing and debugging tool for MCUs inspired by <a href=\"http://www.jera.com/techinfo/jtns/jtn002.html\" target=\"_blank\">MinUnit</a>.</h4>\r\n \r\n<p align=\"center\">\r\n\t<a href=\"#changelog\"><img src=\"https://img.shields.io/github/release-pre/nqtronix/unittrace.svg\" alt=\"release: NA\"></a>\r\n    <a href=\"#about\"><img src=\"https://img.shields.io/badge/language-C_(GCC_5.4.0)-blue.svg\" alt=\"language: C GCC (5.4.0)\"></a>\r\n    <a href=\"#about\"><img src=\"https://img.shields.io/badge/platform-MCUs, AVR8-blue.svg\" alt=\"platform: MCUs, AVR8\"></a>\r\n\t<a href=\"#about\"><img src=\"https://img.shields.io/badge/status-maintained-green.svg\" alt=\"status: maintained\"></a>\r\n\t<a href=\"https://github.com/nqtronix/unittrace/issues\"><img src=\"https://img.shields.io/github/issues/nqtronix/unittrace.svg\" alt=\"issues: NA\"></a>\r\n\t<a href=\"#license\"><img src=\"https://img.shields.io/github/license/nqtronix/unittrace.svg\" alt=\"license: NA\"></a>\r\n</p>\r\n\r\n<p align=\"center\">\r\n  <a href=\"#getting-started\">Getting Started</a> •\r\n  <a href=\"#documentation\">Documentation</a> •\r\n  <a href=\"#under-the-hood\">Under the Hood</a> •\r\n  <a href=\"#support\">Need Help?</a> •\r\n  <a href=\"#about\">About</a> •\r\n  <a href=\"#credits-and-references\">Credits</a>\r\n</p>\r\n\r\n\r\n\r\n## Introduction\r\nTesting is an important part of writing code, especially if the code is meant to be re-used for other projects. On small MCUs testing can be quite tricky as the memory is limited and errors can't be easily reported with `printf()` or similar.\r\n\r\n**unittrace** provides basic testing functionality and is designed with the limits of MCUs in mind. It runs directly on the hardware and thus can catch errors other test software can't. Fetch the results through a debugger or with a function.\r\n\r\n<br>\r\n\r\n## Key Features\r\n \r\n - **lightweight:** absolute minimum Flash & RAM usage\r\n - **runtime test:** catches both software and hardware errors\r\n - **static memory**: no malloc overhead\r\n \r\n<br>\r\n\r\n## Limitations\r\n\r\n - on AVR8 MCUs the maximum usable flash memory is 128KB or 64K words, as the address must fit into the 16bit pointer. On 32bit MCUs pointers are always 32bit and therefore there is no upper limit.\r\n \r\n<br>\r\n\r\n## Usage Example\r\n**unittrace** is ridiculously simple to use. You can place the `ut_assert` functions wherever you want:\r\n\r\n```c\r\nint main(void)\r\n{\r\n\t// using inline functions\r\n\tut_assert(5 == 5);\t// passes\r\n\tut_assert(5 == 7);\t// fails and code address gets stored in array\r\n\t\r\n\t// using macros (equivalently behavior to functions)\r\n\tUT_ASSERT(5 == 5);\t// passes\r\n\tUT_ASSERT(5 == 7);\t// fails and code address gets stored in array\r\n    \r\n    // set a breakpoint\r\n\tUT_BREAK();\r\n    while (1);\r\n}\r\n```\r\n[](#interpreting-the-data)\r\n\r\n<br>\r\n\r\n## Getting Started\r\nThis section is written especially for everyone who is **not familiar** with the used tools. If you run into problems, please [ask for clarification](#get-help).<br>\r\n\r\n### Step 1: Software and Tools\r\n - [**Atmel Studio 7.0**][tool-atmel-studio-7-0]** (Build 1931) [free**]<br>\r\n   The installer contains all tools you need to open, edit, compile, simulate and flash this code. If you favor another development tool, feel free to use it instead. (But please understand that I can not provide any support).\r\n - **An AVR8 ISP/JTAG programmer [optional]**<br>\r\n   To program AVR8 MCUs I use the [AVR Dragon][tool-avr-dragon]. It can be also used as a debugger and is available within Atmel Studio by default.\r\n\r\n### Step 2: Download unittrace\r\n - Clone this repository or hit [Download][git-download] and extract the .zip file.\r\n\r\n### Step 3: Browse the project\r\n - **Open the project in Atmel Studio:**<br>\r\n   Either double click `unittrace.atsln` or open Atmel Studio and select \"File -> Open -> Project/Solution...\"\r\n\r\n - **Open any file of your interest:**<br>\r\n   Select the file in the top right window \"Solution Explorer\". If the window is not visible, open it by pressing `CTRL + ALT + L` or selecting \"View -> Solution Explorer\" from the menu.\r\n\r\n### Step 4: Run the demo\r\n - **Compile the demo code:**<br>\r\n   Press `F7` or select \"Build -> Build Solution\" from the menu\r\n \r\n - **Run the demo code in the simulator:**<br>\r\n   Press `CTRL + F5` or select \"Debug -> Start Debugging and Break\" from the menu\r\n \r\n - **Place breakpoints:**<br>\r\n   Left-Click on the light grey area left of the code to place or remove a breakpoint. Select lines with the comment \"easy breakpoint\".\r\n   \r\n - **View variable values:**<br>\r\n   When the code is paused, hover over any variable to display its value. Alternately you can \"Right-Click -> Watch\" to display the value in the \"watch window\".\r\n \r\n - **Run Code:**<br>\r\n   Press `F5` to run to the next breakpoint or `F10` to execute one step.\r\n \r\n### Step 5: Going further\r\n - **Changing the target device:**<br>\r\n   Press `ALT + F7` and select \"Device -> Change device...\" to select your desired MCU.\r\n \r\n - **Program a real device:**<br>\r\n   Connect your programmer, press `ALT + F7` and select \"Tool\". Choose your tool, your programming interface and wire up your MCU. Press `CTRL + ALT + F7` to flash the code to the MCU. Non-official programmers are not supported by Atmel Studio.\r\n\r\n<br>\r\n\r\n## Documentation\r\n\r\n### Interpreting the Data\r\n\r\nThe results of the test can be accessed at any time, even if the test is not fully complete. The global variable `unittrace_count` contains the number of failed asserts, the array `unittrace_array` contains pointers to the location of the failed instruction in the flash memory. Both variables can be read at runtime or in the debugger with right-click -> watch.\r\n\r\nHowever due to limitations of the build-in debugger there is no direct way to jump to the corresponding line of code. Instead you have to:\r\n\r\n1. Start the debug session\r\n2. Right-click on the source code -> open disassembly\r\n3. Scroll and search the correct line\r\n4. Right-click on the line -> Go to source code\r\n\r\nThis section will be updated, if I figure out a better way.\r\n\r\n<br>\r\n\r\n### API\r\n\r\nTo keep the documentation up-to-date with the least hassle, all configuration options, functions and their arguments are explained in a comment right in front of the declaration. See `unittrace.h` for more information. This section will be updated as soon as this project hits version 1.0.0.\r\n\r\n<br>\r\n\r\n## Under the Hood\r\nI possibly should note that I've never used any \"professional\" unit testing library, so this may be unlike the unit testing you are used to. The code was written from scratch and inspired by [MinUnit][tool-minunit].\r\n\r\n> Of course, if you have access to a full-featured testing framework like JUnit, by all means use it. But if you don't, you can still use a simple framework like MinUnit, or whip up your own in a few hours. There's no excuse for not unit testing.\r\n\r\n<br>\r\n\r\n### Development History\r\n\r\nI didn't want to use `printf` or any UART equivalent, but the debugger instead. This is not as easy as it seems. Here are the ideas I've tried:\r\n\r\n<br>\r\n\r\n#### Idea 1\r\nCreate a global `static void*` pointer and one for each assert macro. All shall be initialized with `NULL`. Whenever the assert condition is false, the local pointer gets the value from the global one and the global is updated with a reference to the local one. After multiple failed asserted this generates a linked list.\r\n\r\nProblems:\r\n1. The Atmel Studio 7 Debugger can't jump to the location of a variable, so one can not tell which assert failed.\r\n2. After multiple de-referencing a pointer like this multiple times the 'watch-window' gets progressively slower.\r\n\r\n<br>\r\n\r\n#### Idea 2\r\nCreate an array of structs in SRAM, each containing:\r\n- pointer to a String in FLASH containing the filename and path\r\n- uint16_t with the line number of the failed assert\r\nNew struct shall be added whenever an assert fails. Filename and line number can be accessed with the macros `__FILE__` and `__LINE__`, respectively.\r\n\r\nProblem:<br>\r\nTo show strings in the watch window, the suffix `,s` must be added manually. If the suffix is added to a struct array like this, ALL contents are interpreted as string.\r\n\r\n<br>\r\n\r\n#### Idea 3\r\nInstead of saving filename and line number individually, put them in one string into flash. Now whenever a assert fails, store a pointer to the corresponding string in the array.\r\n\r\nProblem:<br>\r\nThe debugger can't access the data of a FLASH pointer address, if the address is stored in SRAM (or at least I couldn't figure out how). In short: you can't mix SRAM and FLASH pointer as one expression in the debugger.\r\n\r\n<br>\r\n\r\n#### Idea 4\r\nInstead of generating a list of human readable strings, store the physical location of the assert macro in a SRAM array. The location in the program memory is a 16 bit pointer, so the amount of SRAM required is pretty low. Also this solution requires almost no flash memory, except the few instructions to per assert.\r\n\r\nDownside:<br>\r\nAlthough it is easy to get the value of the pointer in the array, you can not jump to the corresponding location in the C source code. See section [Interpreting the Data](#interpreting-the-data) for more details.\r\n\r\nAs of now idea 4 is the only one that works, so it is the implemented solution. Please [tell me](#contribute) if you know a more straightforward solution.\r\n\r\n<br>\r\n\r\n## Support\r\n\r\n### Get Help\r\n\r\n**Something doesn't work as expected?** No worries! Just open up a new issue in the [GitHub issue tracker][git-issues]. Please provide all information to reproduce your problem. If you don't have a GitHub account (and can't be bothered to create one,) you can [contact](#contact) me directly.\r\n\r\n<br>\r\n\r\n### Contribute\r\n\r\n**Spotted an error?** [Open an issue][git-issues] or submit a pull request.\r\n\r\nThere is no CONTRIBUTING.md yet, sorry. Contributions will inherit the [license](#license) of this project. If you have any questions, just ask.\r\n\r\n<br>\r\n\r\n## About\r\n### Status\r\n**This project is currently classified as** <a href=\"https://github.com/nqtronix/git-template/blob/master/badges.md#project-status\"><img src=\"https://img.shields.io/badge/status-maintained-green.svg\" alt=\"status: maintained\"></a><br>\r\n_The developers intend to keep the code in working condition by updating dependencies, fixing bugs and solving issues._\r\n\r\nAs my testing needs increase I will likely add the functionality I need.\r\n\r\n<br>\r\n\r\n### Changelog\r\nThis project uses [**Semantic Versioning 2.0.0**][semver.org]. During initial development (0.x.x versions) any _major_ increase is substituted with a _minor_ increase (0.1.0->0.2.0 instead of 0.1.0->1.0.0).\r\n\r\nThe message of each commit contains detailed information about the changes made. The list below is a summary about all significant improvements.\r\n\r\n - **0.1.0 (latest)** <br>\r\n   - initial release\r\n\r\n<br>\r\n\r\n### Contact\r\n\r\nIf you haven't done so already, please check out [Get Help](#get-help) for the fastest possible help on your issue. Alternatively you can find my public email address on my [profile][git-profile].\r\n\r\n<br>\r\n\r\n## Credits and References\r\n\r\n### Projects Used\r\n- [**MinUnit**][tool-minunit] - _a minimal unit testing framework for C_<br>\r\n  Great inspiration, thanks!\r\n\r\n- [**git-template**][git-repo-git-template] - _A simple and clean git repository template._<br>\r\n\r\n<br>\r\n\r\n### Related Projects\r\n\r\n - none (yet)\r\n \r\nWant yours to be listed here, too? Create a merge request or [**get in touch**](#get-help).\r\n\r\n<br>\r\n\r\n### Additional Resources\r\n\r\n- [**Catch2**][git-repo-catch2] by [@catchorg][at-catchorg]<br>\r\n  A header-only test framework. Found it by chance and it seems like a great choice for PC applications.\r\n\r\n\r\n<br>\r\n\r\n## License\r\nThis project is proudly licensed under the [MIT license][git-license].\r\n\r\nThe MIT license was chosen to give you the freedom to use this project in any way you want, while protecting all contributors from legal claims. Good code works, great code works for everyone. If this code has become a part of one of your projects, a link back to us would be highly appreciated. Thanks!\r\n\r\n<!-- Links -->\r\n\r\n[git-readme]:README.md\r\n[git-license]:LICENSE.md\r\n[git-profile]:https://github.com/nqtronix\r\n[git-issues]:https://github.com/nqtronix/unittrace/issues\r\n[git-download]:https://github.com/nqtronix/unittrace/archive/master.zip\r\n\r\n[git-repo-git-template]:https://github.com/nqtronix/git-template\r\n\r\n[semver.org]:semver.org\r\n\r\n[tool-atmel-studio-7-0]:https://www.microchip.com/mplab/avr-support/atmel-studio-7\r\n[tool-avr-dragon]:https://www.microchip.com/Developmenttools/ProductDetails/ATAVRDRAGON\r\n[tool-minunit]:http://www.jera.com/techinfo/jtns/jtn002.html\r\n\r\n[at-catchorg]:https://github.com/catchorg\r\n[git-repo-catch2]:https://github.com/catchorg/Catch2\r\n"
  },
  {
    "path": "subrepos/unittrace/unittrace.atsln",
    "content": "﻿\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Atmel Studio Solution File, Format Version 11.00\r\nVisualStudioVersion = 14.0.23107.0\r\nMinimumVisualStudioVersion = 10.0.40219.1\r\nProject(\"{54F91283-7BC4-4236-8FF9-10F437C3AD48}\") = \"unittrace\", \"unittrace.cproj\", \"{DCE6C7E3-EE26-4D79-826B-08594B9AD897}\"\r\nEndProject\r\nGlobal\r\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n\t\tDebug|AVR = Debug|AVR\r\n\t\tRelease|AVR = Release|AVR\r\n\tEndGlobalSection\r\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n\t\t{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.ActiveCfg = Debug|AVR\r\n\t\t{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.Build.0 = Debug|AVR\r\n\t\t{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.ActiveCfg = Release|AVR\r\n\t\t{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.Build.0 = Release|AVR\r\n\tEndGlobalSection\r\n\tGlobalSection(SolutionProperties) = preSolution\r\n\t\tHideSolutionNode = FALSE\r\n\tEndGlobalSection\r\nEndGlobal\r\n"
  },
  {
    "path": "subrepos/unittrace/unittrace.c",
    "content": "/*\r\n * unittrace.c\r\n *\r\n * Created: 29.10.2018 20:34:06\r\n *  Author: Dennis aka nqtronix (github.com/nqtronix)\r\n */ \r\n\r\n\r\n#include \"unittrace.h\"\r\n#include <stddef.h>\t\t// required for 'NULL'\r\n\r\n\r\n//////////////////////////////////////////////////////////////////////////\r\n// Variables\r\n//////////////////////////////////////////////////////////////////////////\r\n\r\nvolatile void* unittrace_array[UNITTRACE_LIST_SIZE] = {[0 ... UNITTRACE_LIST_SIZE-1] = NULL};\r\nut_cnt_t unittrace_count = 0;\r\n\r\n\r\n//////////////////////////////////////////////////////////////////////////\r\n// Functions\r\n//////////////////////////////////////////////////////////////////////////\r\n\r\nvoid ut_assert_manual(void* addr, uint8_t cond)\r\n{\r\n\t// only store event, if condition is 'false' \r\n\tif (cond == 0)\r\n\t{\r\n\t\t#ifndef UNITTRACE_USE_EXT_COUNTER\r\n\t\t\t// store event data into array, if it is not full yet\r\n\t\t\tif (unittrace_count < UNITTRACE_LIST_SIZE)\r\n\t\t\t{\r\n\t\t\t\tunittrace_array[unittrace_count] = addr;\r\n\t\t\t\tunittrace_count++;\r\n\t\t\t}\r\n\t\t\r\n\t\t#else\r\n\t\t\t// store event data into array, if it is not full yet\r\n\t\t\tif (unittrace_count < UNITTRACE_LIST_SIZE)\r\n\t\t\t\tunittrace_array[unittrace_count] = addr;\r\n\t\t\t\r\n\t\t\t// increment counter, reset if overflow detected\r\n\t\t\t// this odd code works with any positive integer type\r\n\t\t\tunittrace_count++;\r\n\t\t\tif (unittrace_count == 0)\r\n\t\t\t\tunittrace_count--;\r\n\t\t\r\n\t\t#endif\r\n\t}\r\n}\r\n\r\n\r\nvoid* ut_get_array(void)\r\n{\r\n\treturn unittrace_array;\r\n}\r\n\r\nut_cnt_t ut_get_count(void)\r\n{\r\n\treturn unittrace_count;\r\n}"
  },
  {
    "path": "subrepos/unittrace/unittrace.componentinfo.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Store xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"AtmelPackComponentManagement\">\r\n\t<ProjectComponents>\r\n\t\t<ProjectComponent z:Id=\"i1\" xmlns:z=\"http://schemas.microsoft.com/2003/10/Serialization/\">\r\n\t\t\t<CApiVersion></CApiVersion>\r\n\t\t\t<CBundle></CBundle>\r\n\t\t\t<CClass>Device</CClass>\r\n\t\t\t<CGroup>Startup</CGroup>\r\n\t\t\t<CSub></CSub>\r\n\t\t\t<CVariant></CVariant>\r\n\t\t\t<CVendor>Atmel</CVendor>\r\n\t\t\t<CVersion>1.2.0</CVersion>\r\n\t\t\t<DefaultRepoPath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs</DefaultRepoPath>\r\n\t\t\t<DependentComponents xmlns:d4p1=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\" />\r\n\t\t\t<Description></Description>\r\n\t\t\t<Files xmlns:d4p1=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">\r\n\t\t\t\t<d4p1:anyType i:type=\"FileInfo\">\r\n\t\t\t\t\t<AbsolutePath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs\\atmel\\ATmega_DFP\\1.2.209\\include</AbsolutePath>\r\n\t\t\t\t\t<Attribute></Attribute>\r\n\t\t\t\t\t<Category>include</Category>\r\n\t\t\t\t\t<Condition>C</Condition>\r\n\t\t\t\t\t<FileContentHash i:nil=\"true\" />\r\n\t\t\t\t\t<FileVersion></FileVersion>\r\n\t\t\t\t\t<Name>include</Name>\r\n\t\t\t\t\t<SelectString></SelectString>\r\n\t\t\t\t\t<SourcePath></SourcePath>\r\n\t\t\t\t</d4p1:anyType>\r\n\t\t\t\t<d4p1:anyType i:type=\"FileInfo\">\r\n\t\t\t\t\t<AbsolutePath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs\\atmel\\ATmega_DFP\\1.2.209\\include\\avr\\iom328p.h</AbsolutePath>\r\n\t\t\t\t\t<Attribute></Attribute>\r\n\t\t\t\t\t<Category>header</Category>\r\n\t\t\t\t\t<Condition>C</Condition>\r\n\t\t\t\t\t<FileContentHash>UMk4QUzkkuShabuoYtNl/Q==</FileContentHash>\r\n\t\t\t\t\t<FileVersion></FileVersion>\r\n\t\t\t\t\t<Name>include/avr/iom328p.h</Name>\r\n\t\t\t\t\t<SelectString></SelectString>\r\n\t\t\t\t\t<SourcePath></SourcePath>\r\n\t\t\t\t</d4p1:anyType>\r\n\t\t\t\t<d4p1:anyType i:type=\"FileInfo\">\r\n\t\t\t\t\t<AbsolutePath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs\\atmel\\ATmega_DFP\\1.2.209\\templates\\main.c</AbsolutePath>\r\n\t\t\t\t\t<Attribute>template</Attribute>\r\n\t\t\t\t\t<Category>source</Category>\r\n\t\t\t\t\t<Condition>C Exe</Condition>\r\n\t\t\t\t\t<FileContentHash>GD1k8YYhulqRs6FD1B2Hog==</FileContentHash>\r\n\t\t\t\t\t<FileVersion></FileVersion>\r\n\t\t\t\t\t<Name>templates/main.c</Name>\r\n\t\t\t\t\t<SelectString>Main file (.c)</SelectString>\r\n\t\t\t\t\t<SourcePath></SourcePath>\r\n\t\t\t\t</d4p1:anyType>\r\n\t\t\t\t<d4p1:anyType i:type=\"FileInfo\">\r\n\t\t\t\t\t<AbsolutePath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs\\atmel\\ATmega_DFP\\1.2.209\\templates\\main.cpp</AbsolutePath>\r\n\t\t\t\t\t<Attribute>template</Attribute>\r\n\t\t\t\t\t<Category>source</Category>\r\n\t\t\t\t\t<Condition>C Exe</Condition>\r\n\t\t\t\t\t<FileContentHash>YXFphlh0CtZJU+ebktABgQ==</FileContentHash>\r\n\t\t\t\t\t<FileVersion></FileVersion>\r\n\t\t\t\t\t<Name>templates/main.cpp</Name>\r\n\t\t\t\t\t<SelectString>Main file (.cpp)</SelectString>\r\n\t\t\t\t\t<SourcePath></SourcePath>\r\n\t\t\t\t</d4p1:anyType>\r\n\t\t\t\t<d4p1:anyType i:type=\"FileInfo\">\r\n\t\t\t\t\t<AbsolutePath>C:/Program Files (x86)\\Atmel\\Studio\\7.0\\Packs\\atmel\\ATmega_DFP\\1.2.209\\gcc\\dev\\atmega328p</AbsolutePath>\r\n\t\t\t\t\t<Attribute></Attribute>\r\n\t\t\t\t\t<Category>libraryPrefix</Category>\r\n\t\t\t\t\t<Condition>GCC</Condition>\r\n\t\t\t\t\t<FileContentHash i:nil=\"true\" />\r\n\t\t\t\t\t<FileVersion></FileVersion>\r\n\t\t\t\t\t<Name>gcc/dev/atmega328p</Name>\r\n\t\t\t\t\t<SelectString></SelectString>\r\n\t\t\t\t\t<SourcePath></SourcePath>\r\n\t\t\t\t</d4p1:anyType>\r\n\t\t\t</Files>\r\n\t\t\t<PackName>ATmega_DFP</PackName>\r\n\t\t\t<PackPath>C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.2.209/Atmel.ATmega_DFP.pdsc</PackPath>\r\n\t\t\t<PackVersion>1.2.209</PackVersion>\r\n\t\t\t<PresentInProject>true</PresentInProject>\r\n\t\t\t<ReferenceConditionId>ATmega328P</ReferenceConditionId>\r\n\t\t\t<RteComponents xmlns:d4p1=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">\r\n\t\t\t\t<d4p1:string></d4p1:string>\r\n\t\t\t</RteComponents>\r\n\t\t\t<Status>Resolved</Status>\r\n\t\t\t<VersionMode>Fixed</VersionMode>\r\n\t\t\t<IsComponentInAtProject>true</IsComponentInAtProject>\r\n\t\t</ProjectComponent>\r\n\t</ProjectComponents>\r\n</Store>"
  },
  {
    "path": "subrepos/unittrace/unittrace.cproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" ToolsVersion=\"14.0\">\r\n  <PropertyGroup>\r\n    <SchemaVersion>2.0</SchemaVersion>\r\n    <ProjectVersion>7.0</ProjectVersion>\r\n    <ToolchainName>com.Atmel.AVRGCC8.C</ToolchainName>\r\n    <ProjectGuid>dce6c7e3-ee26-4d79-826b-08594b9ad897</ProjectGuid>\r\n    <avrdevice>ATmega328P</avrdevice>\r\n    <avrdeviceseries>none</avrdeviceseries>\r\n    <OutputType>Executable</OutputType>\r\n    <Language>C</Language>\r\n    <OutputFileName>$(MSBuildProjectName)</OutputFileName>\r\n    <OutputFileExtension>.elf</OutputFileExtension>\r\n    <OutputDirectory>$(MSBuildProjectDirectory)\\$(Configuration)</OutputDirectory>\r\n    <AssemblyName>unittrace</AssemblyName>\r\n    <Name>unittrace</Name>\r\n    <RootNamespace>unittrace</RootNamespace>\r\n    <ToolchainFlavour>Native</ToolchainFlavour>\r\n    <KeepTimersRunning>true</KeepTimersRunning>\r\n    <OverrideVtor>false</OverrideVtor>\r\n    <CacheFlash>true</CacheFlash>\r\n    <ProgFlashFromRam>true</ProgFlashFromRam>\r\n    <RamSnippetAddress>0x20000000</RamSnippetAddress>\r\n    <UncachedRange />\r\n    <preserveEEPROM>true</preserveEEPROM>\r\n    <OverrideVtorValue>exception_table</OverrideVtorValue>\r\n    <BootSegment>2</BootSegment>\r\n    <eraseonlaunchrule>0</eraseonlaunchrule>\r\n    <AsfFrameworkConfig>\r\n      <framework-data xmlns=\"\">\r\n        <options />\r\n        <configurations />\r\n        <files />\r\n        <documentation help=\"\" />\r\n        <offline-documentation help=\"\" />\r\n        <dependencies>\r\n          <content-extension eid=\"atmel.asf\" uuidref=\"Atmel.ASF\" version=\"3.40.0\" />\r\n        </dependencies>\r\n      </framework-data>\r\n    </AsfFrameworkConfig>\r\n    <avrtool>com.atmel.avrdbg.tool.simulator</avrtool>\r\n    <avrtoolserialnumber />\r\n    <avrdeviceexpectedsignature>0x1E950F</avrdeviceexpectedsignature>\r\n    <com_atmel_avrdbg_tool_simulator>\r\n      <ToolOptions>\r\n        <InterfaceProperties>\r\n        </InterfaceProperties>\r\n        <InterfaceName>\r\n        </InterfaceName>\r\n      </ToolOptions>\r\n      <ToolType>com.atmel.avrdbg.tool.simulator</ToolType>\r\n      <ToolNumber>\r\n      </ToolNumber>\r\n      <ToolName>Simulator</ToolName>\r\n    </com_atmel_avrdbg_tool_simulator>\r\n    <avrtoolinterface />\r\n    <ResetRule>0</ResetRule>\r\n    <EraseKey />\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Release' \">\r\n    <ToolchainSettings>\r\n      <AvrGcc>\r\n  <avrgcc.common.Device>-mmcu=atmega328p -B \"%24(PackRepoDir)\\atmel\\ATmega_DFP\\1.2.209\\gcc\\dev\\atmega328p\"</avrgcc.common.Device>\r\n  <avrgcc.common.optimization.RelaxBranches>True</avrgcc.common.optimization.RelaxBranches>\r\n  <avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>\r\n  <avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>\r\n  <avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>\r\n  <avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>\r\n  <avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>\r\n  <avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>\r\n  <avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>\r\n  <avrgcc.compiler.symbols.DefSymbols>\r\n    <ListValues>\r\n      <Value>NDEBUG</Value>\r\n    </ListValues>\r\n  </avrgcc.compiler.symbols.DefSymbols>\r\n  <avrgcc.compiler.directories.IncludePaths>\r\n    <ListValues>\r\n      <Value>%24(PackRepoDir)\\atmel\\ATmega_DFP\\1.2.209\\include</Value>\r\n    </ListValues>\r\n  </avrgcc.compiler.directories.IncludePaths>\r\n  <avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>\r\n  <avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>\r\n  <avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>\r\n  <avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>\r\n  <avrgcc.linker.libraries.Libraries>\r\n    <ListValues>\r\n      <Value>libm</Value>\r\n    </ListValues>\r\n  </avrgcc.linker.libraries.Libraries>\r\n  <avrgcc.assembler.general.IncludePaths>\r\n    <ListValues>\r\n      <Value>%24(PackRepoDir)\\atmel\\ATmega_DFP\\1.2.209\\include</Value>\r\n    </ListValues>\r\n  </avrgcc.assembler.general.IncludePaths>\r\n</AvrGcc>\r\n    </ToolchainSettings>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Debug' \">\r\n    <ToolchainSettings>\r\n      <AvrGcc>\r\n  <avrgcc.common.Device>-mmcu=atmega328p -B \"%24(PackRepoDir)\\atmel\\ATmega_DFP\\1.2.209\\gcc\\dev\\atmega328p\"</avrgcc.common.Device>\r\n  <avrgcc.common.optimization.RelaxBranches>True</avrgcc.common.optimization.RelaxBranches>\r\n  <avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>\r\n  <avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>\r\n  <avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>\r\n  <avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>\r\n  <avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>\r\n  <avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>\r\n  <avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>\r\n  <avrgcc.compiler.symbols.DefSymbols>\r\n    <ListValues>\r\n      <Value>DEBUG</Value>\r\n    </ListValues>\r\n  </avrgcc.compiler.symbols.DefSymbols>\r\n  <avrgcc.compiler.directories.IncludePaths>\r\n    <ListValues>\r\n      <Value>%24(PackRepoDir)\\atmel\\ATmega_DFP\\1.2.209\\include</Value>\r\n    </ListValues>\r\n  </avrgcc.compiler.directories.IncludePaths>\r\n  <avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>\r\n  <avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>\r\n  <avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>\r\n  <avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>\r\n  <avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>\r\n  <avrgcc.linker.libraries.Libraries>\r\n    <ListValues>\r\n      <Value>libm</Value>\r\n    </ListValues>\r\n  </avrgcc.linker.libraries.Libraries>\r\n  <avrgcc.assembler.general.IncludePaths>\r\n    <ListValues>\r\n      <Value>%24(PackRepoDir)\\atmel\\ATmega_DFP\\1.2.209\\include</Value>\r\n    </ListValues>\r\n  </avrgcc.assembler.general.IncludePaths>\r\n  <avrgcc.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcc.assembler.debugging.DebugLevel>\r\n</AvrGcc>\r\n    </ToolchainSettings>\r\n  </PropertyGroup>\r\n  <ItemGroup>\r\n    <Compile Include=\"unittrace.c\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"unittrace.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"unittrace_demo.c\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n    <Compile Include=\"utility\\macros\\com\\macro_type.h\">\r\n      <SubType>compile</SubType>\r\n    </Compile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Folder Include=\"utility\" />\r\n    <Folder Include=\"utility\\macros\" />\r\n    <Folder Include=\"utility\\macros\\com\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"README.md\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n    <None Include=\"utility\\macros\\com\\com readme.txt\">\r\n      <SubType>compile</SubType>\r\n    </None>\r\n  </ItemGroup>\r\n  <Import Project=\"$(AVRSTUDIO_EXE_PATH)\\\\Vs\\\\Compiler.targets\" />\r\n</Project>"
  },
  {
    "path": "subrepos/unittrace/unittrace.h",
    "content": "/*\r\n * unittrace.h\r\n *\r\n * Created: 29.10.2018 20:36:59\r\n *  Author: Dennis aka nqtronix (github.com/nqtronix)\r\n *\r\n * Description:\r\n * Testing is an important part of writing code, especially if the code is meant to be re-used for\r\n * other projects. On small MCUs testing can be quite tricky as the memory is limited and errors\r\n * can't be easily reported with `printf()` or similiar.\r\n *\r\n * unittrace provides basic testing functionality and is designed with the limits of MCUs in mind.\r\n * It runs directly on the hardware and thus can catch errors other test software can't. Fetch the\r\n * results through a debugger or with a function.\r\n *\r\n * See included 'README.md' for additional information.\r\n */\r\n\r\n\r\n#ifndef UNITTRACE_H_\r\n#define UNITTRACE_H_\r\n\r\n\r\n#include <stdint.h>\t\t// required for data types (uint8_t, uint16_t, ...)\r\n#include \"utility/macros/com/macro_type.h\"\r\n\r\n\r\n//////////////////////////////////////////////////////////////////////////\r\n// Check requirements\r\n//////////////////////////////////////////////////////////////////////////\r\n\r\n#ifndef __GNUC__\r\n\t#error unittrace.h requires \"always inline functions\", \"local labels\" and \"typeof\" offered by a GNU C/ GCC compiler!\r\n#endif\r\n// Workarounds are possible. See comments in the source code.\r\n\r\n\r\n//////////////////////////////////////////////////////////////////////////\r\n// General Info\r\n//////////////////////////////////////////////////////////////////////////\r\n\r\n// version numbering is based on \"Semantic Versioning 2.0.0\" (semver.org)\r\n#define UNITTRACE_VERSION_MAJOR\t\t0\r\n#define UNITTRACE_VERSION_MINOR\t\t1\r\n#define UNITTRACE_VERSION_PATCH\t\t0\r\n#define UNITTRACE_VERSION_SUFFIX\t\r\n#define UNITTRACE_VERSION_META\r\n\r\n// For all development versions (0.x.x) the patch version is increased whenever a function was renamed\r\n\r\n\r\n//////////////////////////////////////////////////////////////////////////\r\n// Settings (This section can be modified by the user)\r\n//////////////////////////////////////////////////////////////////////////\r\n\r\n// Define the amount of failed events to log in detail. The same event can be logged multiple times.\r\n// Each event required 4 byte of RAM. There is no upper limit except the device's SRAM. The compiler\r\n// will automatically choose the  smallest possible data type for most efficient operation.\r\n#define UNITTRACE_LIST_SIZE\t\t8\r\n\r\n// Especially on small embedded systems it is best to choose the smallest data type for every\r\n// variable. This macro selects the smallest possible type based on 'UNITTRACE_LIST_SIZE'. Change\r\n// to 'uint8_t', 'uint16_t' or 'uint32_t' to manually overwrite this feature.\r\n//\r\n// extra '#define UNITTRACE_COUNTER_TYPE' prevents VAssistX from marking 'ut_cnt_t' red\r\n#define UNITTRACE_COUNTER_TYPE _type_min(UNITTRACE_LIST_SIZE)\r\ntypedef UNITTRACE_COUNTER_TYPE ut_cnt_t;\r\n\r\n// If 'UNITTRACE_USE_EXT_COUNTER' is defined, failed asserts will be counted till the maximum value,\r\n// even if no space in the array is available. This might be helpful for some test cases, but does\r\n// increase the assert execution time slightly.\r\n#define UNITTRACE_USE_EXT_COUNTER\r\n\r\n\r\n//////////////////////////////////////////////////////////////////////////\r\n// Global Variables\r\n//////////////////////////////////////////////////////////////////////////\r\n\r\n// I couldn't figure out how to pass a void array half-way decently, so both variables are\r\n// now global instead. This is not \"how it's don\", I know, but unittrace is for testing only anyway.\r\n\r\n// WATCH THESE VARIABLES IN THE DEBUGGER\r\n\r\n// contains all traced events\r\nvolatile void* unittrace_array[UNITTRACE_LIST_SIZE];\r\n\r\n// amount of traced events\r\nut_cnt_t unittrace_count;\r\n\r\n\r\n//////////////////////////////////////////////////////////////////////////\r\n// Function Declarations\r\n//////////////////////////////////////////////////////////////////////////\r\n\r\n// 'ut_assert' is used to validate any given condition. If the condition is false (cond == 0), the\r\n// assembler instruction address is stored to an array (unless it is full). This array can be read\r\n// during debugging.\r\n// If your compiler does not support inline functions, use the macro 'UT_ASSERT(cond)'.\r\nstatic inline void ut_assert(uint8_t cond) __attribute__((always_inline));\r\n\r\n// If you manually want to write a value to the array, you can use this macro. Usually the first few\r\n// instructions are generated by the compiler and their addresses will never naturally appear in\r\n// said array. Thus you may abuse low values for your own, custom purpose (<50 should be safe on\r\n// AVR8 MCUs)\r\nvoid ut_assert_manual(void* addr, uint8_t cond);\r\n\r\n\r\n//////////////////////////////////////////////////////////////////////////\r\n// Macros\r\n//////////////////////////////////////////////////////////////////////////\r\n\r\n// alternative implementation of the macro 'ut_assert(cond)'\r\n#define UT_ASSERT(cond)\t\tdo{__label__ lcl; lcl: ut_assert_manual(&&lcl, cond);}while(0)\r\n\r\n// places a single 'nop' instruction. This will not be optimized an is ideal to place a breakpoint.\r\n// Unlike an inline function a macro is taken \"as is\". In this case it make debugging a little\r\n// easier, so support for the equivalent inline function has been removed.\r\n#define UT_BREAK()\t\t\tasm(\"nop\")\r\n\r\n\r\n//////////////////////////////////////////////////////////////////////////\r\n// Inline functions\r\n//////////////////////////////////////////////////////////////////////////\r\n\r\n// Inline functions MUST be defined in the .h, not in the .c file to work correctly!\r\n\r\n// This function MUST be always inline to create an individual label for each call. In GCC inline\r\n// functions declared with '__attribute__((always_inline))' are as fast as the respective macro.\r\n// '__label__' creates a local label to prevent a littered namespace. Alternatively you could use\r\n// the build-in macro '__COUNTER__' and concat '##' to generate unique labels.\r\nstatic inline void ut_assert(uint8_t cond)\r\n{\r\n\t__label__ local_label;\r\n\tlocal_label:\r\n\tut_assert_manual(&&local_label, cond);\r\n}\r\n\r\n#endif /* UNITTRACE_H_ */"
  },
  {
    "path": "subrepos/unittrace/unittrace_demo.c",
    "content": "/*\r\n * unittrace.c\r\n *\r\n * Created: 29.10.2018 20:32:06\r\n * Author : Dennis aka nqtronix (github.com/nqtronix)\r\n */ \r\n\r\n\r\n#include \"unittrace.h\"\r\n\r\nint main(void)\r\n{\r\n\t// using inline functions\r\n\tut_assert(5 == 5);\t// passes\r\n\tUT_BREAK();\r\n\tut_assert(5 == 7);\t// fails and code address gets stored in array\r\n\tUT_BREAK();\r\n\t\r\n\t// using macros (equivalently behavior to functions)\r\n\tUT_ASSERT(5 == 5);\t// passes\r\n\tUT_BREAK();\r\n\tUT_ASSERT(5 == 7);\t// fails and code address gets stored in array\r\n\tUT_BREAK();\r\n\r\n\t// Access generated data\r\n\t// You can access the data either with a debugger by watching the two global variables or use\r\n\t// them in your code. See pseudocode below:\r\n\tfor (uint8_t cnt=0; cnt < unittrace_count; cnt++)\r\n\t{\r\n\t\t/*usedata(unittrace_array[cnt]);*/\r\n\t}\r\n\r\n\t// End test\r\n\tUT_BREAK();\r\n    while (1);\r\n}\r\n"
  },
  {
    "path": "subrepos/unittrace/utility/macros/com/com readme.txt",
    "content": "This folder \"com\" contains macros for common functionalities and can result in significant cleaner\r\ncode. In addition the majority of macros can be highly optimized by the compiler, if the imput\r\narguments are literals. "
  },
  {
    "path": "subrepos/unittrace/utility/macros/com/macro_type.h",
    "content": "/*\r\n * macro_type.h\r\n *\r\n * Created: 14.10.2018 14:34:03\r\n *  Author: Dennis\r\n *\r\n * Description:\r\n * Provides typ-related macros\r\n */\r\n\r\n\r\n#ifndef MACRO_TYPE_H_\r\n#define MACRO_TYPE_H_\r\n\r\n\r\n// returns a value not smaller or larger than the limit\r\n#define _limit(arg, lo, hi)\t\t((arg)<lo? lo : (arg)>hi? hi : (arg))\r\n#define _limit_lo(arg, lo)\t\t((arg)<lo? lo : (arg))\r\n#define _limit_hi(arg, hi)\t\t((arg)>hi? hi : (arg))\r\n\r\n\r\n// returns smallest type for given integer\r\n#define _type_min(_integer)\t\ttypeof(_type_cast_min(_integer))\r\n\r\n// By default all literals are interpreted as a int, whose size varies between systems\r\n// This macro forces minimum memory usage by casting a literal to the smallest data type suitable.\r\n// Unsigned types are proffered.\r\n#define _type_cast_min(_integer)\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\r\n\t(__builtin_choose_expr((_integer)>0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\r\n\t__builtin_choose_expr((_integer)<=UINT8_MAX, (uint8_t) (_integer),\t\t\t\t\t\t\t\t\\\r\n\t__builtin_choose_expr((_integer)<=UINT16_MAX, (uint16_t) (_integer),\t\t\t\t\t\t\t\\\r\n\t__builtin_choose_expr((_integer)<=UINT32_MAX, (uint32_t) (_integer), (uint64_t) (_integer)))),\t\\\r\n\t__builtin_choose_expr((_integer)>=INT8_MIN, (int8_t) (_integer),\t\t\t\t\t\t\t\t\\\r\n\t__builtin_choose_expr((_integer)>=INT16_MIN, (int16_t) (_integer),\t\t\t\t\t\t\t\t\\\r\n\t__builtin_choose_expr((_integer)>=INT32_MIN, (int32_t) (_integer), (int64_t) (_integer))))))\r\n\r\n\r\n\r\n#endif /* MACRO_TYPE_H_ */"
  },
  {
    "path": "utility/macros/com/com readme.txt",
    "content": "This folder \"com\" contains macros for common functionalities and can result in significant cleaner\r\ncode. In addition the majority of macros can be highly optimized by the compiler, if the imput\r\narguments are literals. "
  },
  {
    "path": "utility/macros/com/macro_array.h",
    "content": "/*\r\n * macro_array.h\r\n *\r\n * Created: 14.10.2018 14:38:19\r\n *  Author: Dennis\r\n */ \r\n\r\n\r\n#ifndef MACRO_ARRAY_H_\r\n#define MACRO_ARRAY_H_\r\n\r\n\r\n// like sizeof(), but returns the element count of a const array\r\n#define _sizeof_array(_array)\t(sizeof(_array)/sizeof(_array[0]))\r\n\r\n// returns the length of a string\r\n#define _sizeof_str(_string)\t((sizeof(_string)/sizeof(_string[0]))-sizeof(_string[0]))\r\n\r\n\r\n// Allows access of nth byte in uint16_t, uint32_t, ...\r\n#define _get_nth_element(_type, input, n)\t\t((_type)(input>>(n*sizeof(_type))))\r\n\r\n// returns the index of an array that matches the pointer. the pointer MUST point to an element of\r\n// the array, checks are NOT performed\r\n#define _array_pointer2idx(_array_id, pointer)\t((pointer-_array_id)/sizeof(_array_id[0]))\r\n\r\n\r\n#endif /* MACRO_ARRAY_H_ */"
  },
  {
    "path": "utility/macros/com/macro_math.h",
    "content": "/*\n * macro_math.h\n *\n * Created: 14.10.2018 14:34:32\n *  Author: Dennis\n *\n * Description:\n * Provides math operations, which can be solved at compile time, given the inputs are literals.\n * If used during runtime, these macros might be significant slower than the usual implementations.\n */\n\n\n#ifndef MACRO_MATH_H_\n#define MACRO_MATH_H_\n\n\n\n\n//////////////////////////////////////////////////////////////////////////\n// Comparisons\n//////////////////////////////////////////////////////////////////////////\n\n// returns 0 if argument is not power of two\n#define _is_power_of_two(arg)\t\t\t\t\t\t((arg) && !((arg) & ((arg) - 1)))\n\n// returns 0 if both arguments have the same sign\n#define _is_sign_opposite(arg1, arg2)\t\t\t\t(((arg1) ^ (arg2)) < 0)\n\n\n//////////////////////////////////////////////////////////////////////////\n// Calc\n//////////////////////////////////////////////////////////////////////////\n\n// returns the absolute value\n#define _abs(arg)\t\t\t\t((arg) >= 0? (arg) : -(arg))\n\n// shifts 'input' left or right by 'shiftAmount' , but unlike the C standard operators << and >>\n// negative values are allowed and result in a shift of the opposite direction\n#define _shift_left(arg, shiftAmount)\t\t\\\n\t(shiftAmount > 0 ? arg << shiftAmount : arg >> (-shiftAmount))\n\n#define _shift_right(arg, shiftAmount)\t\t\\\n\t(shiftAmount > 0 ? arg >> shiftAmount : arg << (-shiftAmount))\n\n// returns the minimum of both parameters, if x == y, y is returned\n#define _min(x, y)                           \\\n    (((x) > (y)) ? (y) : (x))\n\n// returns the mathematical function log2(x), rounded down to nearest integer\n// this marco-like function makes use of a GCC build-in function and can be used eg. for if(log2(x)>y)\n// If a literal is passed to this function, the result is calculated at compile time and stored in flash.\n#define _log2(n)\t((unsigned) (8*sizeof(uint64_t) - __builtin_clzll((n)) - 1))\n\n\n\n#endif /* MACRO_MATH_H_ */"
  },
  {
    "path": "utility/macros/com/macro_type.h",
    "content": "/*\r\n * macro_type.h\r\n *\r\n * Created: 14.10.2018 14:34:03\r\n *  Author: Dennis\r\n *\r\n * Description:\r\n * Provides typ-related macros\r\n */\r\n\r\n\r\n#ifndef MACRO_TYPE_H_\r\n#define MACRO_TYPE_H_\r\n\r\n\r\n// returns a value not smaller or larger than the limit\r\n#define _limit(arg, lo, hi)\t\t((arg)<lo? lo : (arg)>hi? hi : (arg))\r\n#define _limit_lo(arg, lo)\t\t((arg)<lo? lo : (arg))\r\n#define _limit_hi(arg, hi)\t\t((arg)>hi? hi : (arg))\r\n\r\n\r\n// returns smallest type for given integer\r\n#define _type_min(_integer)\t\ttypeof(_type_cast_min(_integer))\r\n\r\n// By default all literals are interpreted as a int, whose size varies between systems\r\n// This macro forces minimum memory usage by casting a literal to the smallest data type suitable.\r\n// Unsigned types are proffered.\r\n#define _type_cast_min(_integer)\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\r\n\t(__builtin_choose_expr((_integer)>0,\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\r\n\t__builtin_choose_expr((_integer)<=UINT8_MAX, (uint8_t) (_integer),\t\t\t\t\t\t\t\t\\\r\n\t__builtin_choose_expr((_integer)<=UINT16_MAX, (uint16_t) (_integer),\t\t\t\t\t\t\t\\\r\n\t__builtin_choose_expr((_integer)<=UINT32_MAX, (uint32_t) (_integer), (uint64_t) (_integer)))),\t\\\r\n\t__builtin_choose_expr((_integer)>=INT8_MIN, (int8_t) (_integer),\t\t\t\t\t\t\t\t\\\r\n\t__builtin_choose_expr((_integer)>=INT16_MIN, (int16_t) (_integer),\t\t\t\t\t\t\t\t\\\r\n\t__builtin_choose_expr((_integer)>=INT32_MIN, (int32_t) (_integer), (int64_t) (_integer))))))\r\n\r\n\r\n\r\n#endif /* MACRO_TYPE_H_ */"
  },
  {
    "path": "utility/macros/mpl/macro_cat.h",
    "content": "/*\r\n * macro_cat.h\r\n *\r\n * Created: 14.10.2018 11:09:54\r\n *  Author: Dennis\r\n *\r\n * Description:\r\n * concatenates up to 16 arguments without inhibition\r\n */\r\n\r\n\r\n#ifndef MACRO_CAT_H_\r\n#define MACRO_CAT_H_\r\n\r\n#include \"../mpl/macro_vfunc.h\"\r\n\r\n#define CAT(...)\t\t\t\t\t\t\t\tVFUNC_0ARG(CAT, __VA_ARGS__)\r\n#define CAT0()\r\n#define CAT1(a)\t\t\t\t\t\t\t\t\ta\r\n#define CAT2(a,b)\t\t\t\t\t\t\t\ta ## b\r\n#define CAT3(a,b,c)\t\t\t\t\t\t\t\ta ## b ## c\r\n#define CAT4(a,b,c,d)\t\t\t\t\t\t\ta ## b ## c ## d\r\n#define CAT5(a,b,c,d,e)\t\t\t\t\t\t\ta ## b ## c ## d ## e\r\n#define CAT6(a,b,c,d,e,f)\t\t\t\t\t\ta ## b ## c ## d ## e ## f\r\n#define CAT7(a,b,c,d,e,f,g)\t\t\t\t\t\ta ## b ## c ## d ## e ## f ## g\r\n#define CAT8(a,b,c,d,e,f,g,h)\t\t\t\t\ta ## b ## c ## d ## e ## f ## g ## h\r\n#define CAT9(a,b,c,d,e,f,g,h,i)\t\t\t\t\ta ## b ## c ## d ## e ## f ## g ## h ## i\r\n#define CAT10(a,b,c,d,e,f,g,h,i,j)\t\t\t\ta ## b ## c ## d ## e ## f ## g ## h ## i ## j\r\n#define CAT11(a,b,c,d,e,f,g,h,i,j,k)\t\t\ta ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k\r\n#define CAT12(a,b,c,d,e,f,g,h,i,j,k,l)\t\t\ta ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l\r\n#define CAT13(a,b,c,d,e,f,g,h,i,j,k,l,m)\t\ta ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m\r\n#define CAT14(a,b,c,d,e,f,g,h,i,j,k,l,m,n)\t\ta ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m ## n\r\n#define CAT15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o)\ta ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m ## n ## o\r\n#define CAT16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)\ta ## b ## c ## d ## e ## f ## g ## h ## i ## j ## k ## l ## m ## n ## o ## p\r\n\r\n\r\n\r\n\r\n#endif /* MACRO_CAT_H_ */"
  },
  {
    "path": "utility/macros/mpl/macro_narg.h",
    "content": "/*\r\n * macro_narg.h\r\n *\r\n * Created: 14.10.2018 11:01:15\r\n *  Author: Dennis\r\n *\r\n * Description:\r\n * Returns the number of passed (macro) arguments\r\n */\r\n\r\n\r\n#ifndef MACRO_NARG_H_\r\n#define MACRO_NARG_H_\r\n\r\n// get number of arguments with __NARG__\r\n#define __NARG__(...)  __NARG_I_(\"ignored\", ##__VA_ARGS__, __RSEQ_N())\r\n#define __NARG_I_(...) __ARG_N(__VA_ARGS__)\r\n#define __ARG_N(\t\t\t\t\t\t\t\t\t\t\\\r\n\t_1, _2, _3, _4, _5, _6, _7, _8, _9,_10,\t\t\t\t\\\r\n\t_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,\t\t\t\\\r\n\t_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,\t\t\t\\\r\n\t_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,\t\t\t\\\r\n\t_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,\t\t\t\\\r\n\t_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,\t\t\t\\\r\n\t_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,\t\t\t\\\r\n\t_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,\t\t\t\\\r\n\t_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,\t\t\t\\\r\n\t_91,_92,_93,_94,_95,_96,_97,_98,_99,_100,\t\t\t\\\r\n\t_101,_102,_103,_104,_105,_106,_107,_108,_109,_110,\t\\\r\n\t_111,_112,_113,_114,_115,_116,_117,_118,_119,_120,\t\\\r\n\t_121,_122,_123,_124,_125,_126,_127,_128,N,...) N\r\n#define __RSEQ_N()\t\t\t\t\t\t\t\t\\\r\n\t\t\t127,126,125,124,123,122,121,120,\t\\\r\n\t119,118,117,116,115,114,113,112,111,110,\t\\\r\n\t109,108,107,106,105,104,103,102,101,100,\t\\\r\n\t99,98,97,96,95,94,93,92,91,90,\t\t\t\t\\\r\n\t89,88,87,86,85,84,83,82,81,80,\t\t\t\t\\\r\n\t79,78,77,76,75,74,73,72,71,70,\t\t\t\t\\\r\n\t69,68,67,66,65,64,63,62,61,60,\t\t\t\t\\\r\n\t59,58,57,56,55,54,53,52,51,50,\t\t\t\t\\\r\n\t49,48,47,46,45,44,43,42,41,40,\t\t\t\t\\\r\n\t39,38,37,36,35,34,33,32,31,30,\t\t\t\t\\\r\n\t29,28,27,26,25,24,23,22,21,20,\t\t\t\t\\\r\n\t19,18,17,16,15,14,13,12,11,10,\t\t\t\t\\\r\n\t9,8,7,6,5,4,3,2,1,0\r\n\r\n\r\n\r\n#endif /* MACRO_NARG_H_ */"
  },
  {
    "path": "utility/macros/mpl/macro_vfunc.h",
    "content": "/*\r\n * macro_vfunc.h\r\n *\r\n * Created: 14.10.2018 11:05:26\r\n *  Author: Dennis\r\n *\r\n * Description:\r\n * vfunc expands to a different macro depending on the argument count. See usage example below.\r\n */\r\n\r\n\r\n#ifndef MACRO_VFUNC_H_\r\n#define MACRO_VFUNC_H_\r\n\r\n#include \"macro_narg.h\"\r\n\r\n// general definition for any function name\r\n// VFUNC_NARG passes N arguments to each function in addition to the variable arguments\r\n#define _VFUNC_(name,n)\t\t\t\t\t\t\tname##n\r\n#define _VFUNC(name,n)\t\t\t\t\t\t\t_VFUNC_(name,n)\r\n#define VFUNC_0ARG(func,...)\t\t\t\t\t_VFUNC(func,__NARG__(__VA_ARGS__)) (__VA_ARGS__)\r\n\r\n#define _VFUNC1(name,arg1,n)\t\t\t\t\t_VFUNC_(name,n)\r\n#define VFUNC_1ARG(func,arg1,...)\t\t\t\t_VFUNC1(func,arg1,__NARG__(__VA_ARGS__)) (arg1,__VA_ARGS__)\r\n\r\n#define _VFUNC2(name,arg1,arg2,n)\t\t\t\t_VFUNC_(name,n)\r\n#define VFUNC_2ARG(func,arg1,arg2,...)\t\t\t_VFUNC2(func,arg1,arg2,__NARG__(__VA_ARGS__)) (arg1,arg2,__VA_ARGS__)\r\n\r\n#define _VFUNC3(name,arg1,arg2,arg3,n)\t\t\t_VFUNC_(name,n)\r\n#define VFUNC_3ARG(func,arg1,arg2,arg3,...)\t\t_VFUNC3(func,arg1,arg2,arg3,__NARG__(__VA_ARGS__)) (arg1,arg2,arg3,__VA_ARGS__)\r\n\r\n// USAGE:\r\n// EXAMPLE 1:\r\n// Change all 5 'SUM' in the example below to your desired macro name\r\n//\r\n// #define SUM(...)\t\t\tVFUNC_0ARG(SUM, __VA_ARGS__)\r\n// #define SUM1(x)\t\t\t(x)\r\n// #define SUM2(x, y)\t\t((x) + (y))\r\n// #define SUM3(x, y, z)\t((x) + (y) + (z))\r\n//\r\n// EXAMPLE 2:\r\n// Use it for default arguments:\r\n// \r\n// #define func(...)\t\tVFUNC_0ARG(func, __VA_ARGS__)\r\n// #define func2(a, b)\t\tfunc4(a, b, NULL, NULL)\r\n// #define func3(a, b, c)\tfunc4(a, b, c, NULL)\r\n// \r\n// // real function:\r\n// int func4(int a, int b, void* c, void* d) { /* ... */ }\r\n\r\n\r\n\r\n#endif /* MACRO_VFUNC_H_ */"
  },
  {
    "path": "utility/macros/mpl/mpl readme.txt",
    "content": "This folder \"mpl\" (short for \"macro programming language) contains macros for more advanced\r\nfunctionality. It is not complete by any means and serves more like a sketchbook for ideas and\r\nenables a few special use cases. Changes which break compatibility in the future are likely."
  },
  {
    "path": "utility/macros/readme.txt",
    "content": "\r\n\r\n\r\nMACRO NAMING CONVENTIONS:\r\n\r\nAlthough macros make many complicated things easier they can also easily generate problems by\r\nincorrect use, which are very hard to debug. Therfore naming conventions are important to\r\ndistinguish various functions.\r\n\r\nExample:\t\tDescription:\r\n\r\n__NAME__\t\tCompiler defined macros. Might be used in rare cases to create compiler macro\r\n\t\t\t\tdepended macros such as __TIME_UNIX__\r\nNAME\t\t\tLiterals.\r\nNAME()\t\t\tPreprocessor macro. Performs various operations with the preprocessor, typically\r\n\t\t\t\t# or ##, but can be more complex as well. Their result can be used to create further\r\n\t\t\t\tmacros.\r\n_NAME()\t\t\tHidden preprocessor macro.\r\n_name()\t\t\tFunction-like macro. Unlike preprocessor macros these macros are intended to be used\r\n\t\t\t\tlike any other C function. The _ differentiates it from a normal function and hints\r\n\t\t\t\tto possible subtle problems in use.\r\n_name(id)\t\tAny normally written parameter of a function-like macro can be any C expression of\r\n\t\t\t\tthe correct type (such as uint8_t, uint16_t, ...)\r\n_name(_id)\t\tAny parameter starting with _ is taken literally and thus has to be known at compile\r\n\t\t\t\ttime. See description of macro in question for allowed inputs.\r\ntype_t _tmp\t\tAll local variables of a function like macro are marked with _ to prevent conflicts\r\n\t\t\t\tsubstituted C names for the parameter. DO NOT pass any C identifier starting with _\r\n_return\t\t\tIs used within compound statements as a label for the return value.\r\n\r\n\r\nFrom https://gcc.gnu.org/onlinedocs/gcc/Typeof.html\r\nThe reason for using names that start with underscores for the local variables is to avoid\r\nconflicts with variable names that occur within the expressions that are substituted for a and b.\r\nEventually we hope to design a new form of declaration syntax that allows you to declare variables\r\nwhose scopes start only after their initializers; this will be a more reliable way to prevent such\r\nconflicts."
  }
]