====== Introduction to the Programming Frameworks ====== {{:en:iot-open:czapka_b.png?50| General audience classification icon }}{{:en:iot-open:czapka_e.png?50| General audience classification icon }}\\ In the beginning, it is essential to distinguish an IoT Framework that is a set of tools, firmware for a variety of devices, sometimes also hardware, delivered as is and providing developers with configuration capabilities on the high abstraction level from the Programming Framework that is related to the low-level programming, here in C/C++, referred to as an SDK. SDK tends to be a narrower definition than a programming framework as the former contains both SDK and tools, development toolchain and code organisation rules.\\ This chapter presents and discusses programming frameworks (SDKs and source code organisation) that define how the IoT code is organised on the low level in the Bare Metal programming model for Edge class devices.\\ Almost every MCU (microchip/microcontroller) vendor develops its own SDK, providing programmers with a specific programming framework. It is worth nothing to mention that, in many cases, it follows the general programming construction of the source code for C or C++, such as below: int main() { std::cout << "Hello IoT!"; return 0; } A common approach is to use a GUI to automate the generation of the source code stub that contains the hardware-specific configuration, e.g. timers, GPIOs, and interrupts, to avoid monotonous and complex tasks and speed up time to market.\\ Still, as hardware differs, it is particular for each platform, and usually, software development requires a rigorous approach to inject user-specific code only in predefined locations. Otherwise, it may break source code or even delete it when re-generating configuration using SDK tools and automation. Sample ''main()'' function for the STM32 MCU is presented below. Developers are intended to fill their code only in predefined areas, such as starting from ''USER CODE BEGIN Init'' and finishing before ''USER CODE END Init''; otherwise, the source code will be gone when updating the configuration: int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ MX_GPIO_Init(); MX_LPUART1_UART_Init(); MX_NVIC_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { nUARTBufferLen = sprintf((char*)tUARTBuffer, "Hello World!\n\r"); HAL_UART_Transmit_IT(&hlpuart1, tUARTBuffer, nUARTBufferLen); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } Studying specific platforms is time-consuming, and as each vendor has its approach, knowledge and source codes are usually not portable between microcontrollers.\\ Specific frameworks for hardware vendors are (among others): * Espressif ESP8266: * ESP8266 RTOS SDK, * ESP8266 Non-OS SDK, * Arduino. * AVR/Atmel: * AVR Studio (Atmel Studio), * Arduino. * Espressif ESP32: * ESP-IDF, * Arduino. * Nordic Semiconductors nRF52: * Mbed, * Zephyr RTOS, * nRF5 SDK, * Arduino. * ST Microelectronics STM32 series: * Mbed, * CMSIS, * Zephyr RTOS, * Registers programming model (RAW), * STM32Cube (HAL), * Arduino. Typical C++ code, as presented above, is a single-pass execution. On the other hand, IoT devices used to work infinitely, handling their duties such as reading sensors, communicating over the network, sending and receiving data, routing messages and so on, thus requiring setting up an infinite ''while (1)'' loop for processing. Many tasks need to be done in parallel, so it is expected to include a task scheduling mechanism to run multiple tasks asynchronously. A common is to use the FreeRTOS ((https://www.freertos.org/)) or its modified versions for the specific hardware platform provided by the hardware vendor, e.g. as in the case of the ESP32 ((https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos.html)) to provide support for multicore MCUs. Name FreeRTOS may be misleading because it can be understood as a general purpose operating system (GPOS), suggesting it runs in the background before your application starts as Windows or Linux does. FreeRTOS as an Embedded Operating System (OS for embedded systems and microcontrollers) is included as a C/C++ library in the source code and built into the firmware and algorithms. It provides similar functionalities as the GPOS kernel with task handling, memory management, file system, etc. ===== Arduino Framework ===== Observing the list of software frameworks above, one can easily find that many platforms have common frameworks, but the Arduino framework is present for all of them. Arduino framework is a cross-platform approach providing a slightly higher level of abstraction over dedicated software frameworks, and it is the most popular among hobbyists, students, professionals and even researchers at the moment. Arduino Framework is a reasonable balance between uniform code organisation and elements of cross-hardware HAL, still bringing opportunities to access hardware on a low level and get the advantage of the advanced features of modern IoT microcontrollers such as, e.g. power management. Most hardware vendors support this framework natively, and it has become almost an industry standard. Some advanced hardware controls may require integration or other native frameworks, anyway. Still, the Arduino framework has real-time capacity. It is powerful and flexible enough to handle most IoT-related tasks, and most of all, it has excellent community support with dozens of software libraries, examples and applications worldwide. A dummy C/C++ code for the Arduino framework looks as follows: void setup() { } void loop() { } The ''void setup()'' function is executed only once after the microcontroller reboots. Its purpose is to initialise, instantiate objects, read configuration, check working conditions, and so on: generally, all tasks that are to be executed only once in a work cycle of the IoT device.\\ The ''void loop()'' function is executed in a loop automatically and infinitely once a single pass is finished. Its purpose is to implement repeating tasks such as periodic reading of a sensor and sending the data to the cloud. There is no need to implement a dummy ''while(1)'' inside the ''loop()''; moreover, it is usually not advised or even forbidden. It is because, for every execution of the ''loop()'' statement, many other tasks, such as handling communication, may be executed once. Making a single pass of the ''loop()'' function infinite (e.g. implementing an infinite ''while(1)'' loop could cause starvation of the other underlying processes the framework handles, such as network communication, embedded protocols handling, etc.). The book presents code and examples in the Arduino framework context for edge-class devices and Fog-class devices (scripting). Wherever other framework is used, it will be clearly stated. Note, following introduction to the C and C++ programming and task handling contents are universal and can be applied to the other frameworks, whether directly or indirectly, with some adaptation on the code level.