C/C++

STM32 HAL PlatformIO LED blink example

In the autogenerated main.c, use the following while() loop:

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
  HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_SET);
  HAL_Delay(1000);
  HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_RESET);
  HAL_Delay(1000);
}
/* USER CODE END 3 */

On STM32H7 Nucleo boards, this will toggle the green LED.

Posted by Uli Köhler in C/C++, PlatformIO, STM32

STM32H743 DAC instant switch off (no fall time)

In our previous post STM32H743 DAC rise/fall time experiments we showed that the STM23H743 has relatively long turn-on / turn-off times of approximately 950 nanoseconds, limiting the generation of fast rectangular signals:

However, there’s a trick how to obtain fall times almost 3 orders of magnitude better for the special case of switching either to full-scale VDD or to GND.

Instead of setting the DAC to the new value, you can just disable the DAC and let the GPIO take care of the rest. This allows for extremely fast fall times of approximately 5ns.

Note that switching the GPIO to digital mode while the DAC is on does not seem to have any effect.

Please note that I didn’t take any care to make the measurement setup immune to the high transients, leading to some oscillation. You should take your own measurements if you have specific requirements.

DAC fall time from 3/4 full scale value (3072)

Note that switching on the DAC quickly is outside the scope of this post, but when toggling the DAC enable bit, you can still obtain 250ns rise times pretty easily.

Code example

void Init() {    
    DAC_ChannelConfTypeDef sConfig = {0};

    // Initialize DAC
    hdac.Instance = DAC1;
    if (HAL_DAC_Init(&hdac) != HAL_OK)
    {
        // Initialization Error
        __BKPT();
    }

    // Configure DAC channel
    sConfig.DAC_Trigger = DAC_TRIGGER_NONE;  // No trigger, free-running mode
    sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;

    if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK)
    {
        // Channel configuration Error
        __BKPT();
    }

    // Enable DAC Channel and start the conversion
    if (HAL_DAC_Start(&hdac, DAC_CHANNEL_1) != HAL_OK)
    {
        // Starting Error
        __BKPT();
    }

    // Set DAC to some value, which won't be changed for this example
    if (HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 3072) != HAL_OK)
    {
        // Setting DAC value Error
         __BKPT();
    }
}
void Pulse_On() {
    // Enable DAC
    hdac.Instance->CR |= DAC_CR_EN1;

    // Set GPIO to analog mode
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void Pulse_Off() {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);

    // Clear EN1 bit of DAC_CR
    hdac.Instance->CR &= ~DAC_CR_EN1;
}

 

 

Posted by Uli Köhler in C/C++, STM32

STM32H743 DAC rise/fall time experiments

This oscilloscope trace was obtained by first setting the STM32H743ZI (Nucleo) DAC to 0x00, then setting it to maximum value (4096) without any intermediate steps.

The output buffer was enabled.

As can be seen on the trace, the rise/fall time is approximately 1us. No information about the clock speed etc is available for this example (Arduino on PlatformIO was used with standard settings). However, it does not appear that the rise/fall time is caused by the update rate. Setting the GPIO speed to maximum does not change the value.

This matches well with the datasheet-provided settling time of 1.7us(typ).

When disabling the output buffer, the result looks like this:

When, on the other hand, using the same pin as GPIO – using the exact same measurement setup (direct connection to BNC with 1M measurement impedance), the rise/fall time is almost zero.

Code example

// Function to initialize the DAC
void MX_DAC_Init(void)
{
    DAC_ChannelConfTypeDef sConfig = {0};

    // Initialize DAC
    hdac.Instance = DAC1;
    if (HAL_DAC_Init(&hdac) != HAL_OK)
    {
        // Initialization Error
        __BKPT();
    }

    // Configure DAC channel
    sConfig.DAC_Trigger = DAC_TRIGGER_NONE;  // No trigger, free-running mode
    sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;

    if (HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1) != HAL_OK)
    {
        // Channel configuration Error
        __BKPT();
    }

    // Enable DAC Channel and start the conversion
    if (HAL_DAC_Start(&hdac, DAC_CHANNEL_1) != HAL_OK)
    {
        // Starting Error
        __BKPT();
    }
}

The DAC value was set using

if (HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 4095) != HAL_OK) {
    // Setting DAC value Error
    __BKPT();
}

 

Posted by Uli Köhler in C/C++, STM32

STM32H743 Arduino PlatformIO example: Read ADC with 16 bit resolution

This example configures ADC1 to read a 16 bit analog value of PA7 using a polled loop. The serial output is available on the STLink header.

#include <Arduino.h>
#include <stm32h7xx_hal.h>

ADC_HandleTypeDef hadc1;

static void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // Enable the GPIOA clock
    __HAL_RCC_GPIOA_CLK_ENABLE();

    /**ADC1 GPIO Configuration    
    PA7     ------> ADC1_IN7 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

static void MX_ADC1_Init(void)
{
    ADC_ChannelConfTypeDef sConfig = {0};

    hadc1.Instance = ADC1;
    hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
    hadc1.Init.Resolution = ADC_RESOLUTION_16B;
    hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
    hadc1.Init.LowPowerAutoWait = DISABLE;
    hadc1.Init.ContinuousConvMode = DISABLE;
    hadc1.Init.NbrOfConversion = 1;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    //hadc1.Init.DMAContinuousRequests = DISABLE;
    hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
    hadc1.Init.OversamplingMode = DISABLE;
    if (HAL_ADC_Init(&hadc1) != HAL_OK)
    {
        // Initialization Error
    }

    sConfig.Channel = ADC_CHANNEL_7;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
    sConfig.SingleDiff = ADC_SINGLE_ENDED;
    sConfig.OffsetNumber = ADC_OFFSET_NONE;
    sConfig.Offset = 0;
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    {
        // Channel Configuration Error
    }
}

void setup() {
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_ADC1_Init();

  Serial.begin(115200);

}

void loop() {
    HAL_ADC_Start(&hadc1); // Start ADC conversion
    HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); // Wait for conversion to complete

    uint32_t adcValue = HAL_ADC_GetValue(&hadc1); // Read the ADC converted value
    Serial.printf("ADC value: %04X\n", adcValue);
}
[env:nucleo_h743zi]
platform = ststm32
board = nucleo_h743zi
framework = arduino
monitor_speed = 115200

Example output (unconnected):

ADC value: 04B6
ADC value: 049C
ADC value: 04AC
ADC value: 04AE
ADC value: 0497
ADC value: 04AF
ADC value: 04A7
ADC value: 04C6
ADC value: 0491
ADC value: 04A1
ADC value: 04AF
ADC value: 0493
ADC value: 0497
ADC value: 04AF
ADC value: 04A3
ADC value: 047D
ADC value: 04C1
ADC value: 04B1
ADC value: 04AF
ADC value: 0498
ADC value: 04A1
ADC value: 04C3
ADC value: 04AE
ADC value: 04AC
ADC value: 0489
ADC value: 0491
ADC value: 0491
ADC value: 047E
ADC value: 04B8
ADC value: 0494
ADC value: 04A5
ADC value: 0491
ADC value: 0494
ADC value: 048A
ADC value: 0499
ADC value: 0494
ADC value: 049E

 

Posted by Uli Köhler in Arduino, C/C++, PlatformIO, STM32

ESP32(-S3) ADC1 ESP-IDF minimal oneshot example with curve calibration

#include <esp_adc/adc_oneshot.h>
#include <esp_adc/adc_cali.h>
#include <esp_adc/adc_cali_scheme.h>


adc_oneshot_unit_handle_t adc1_handle = nullptr;
adc_cali_handle_t adc_cali_channel_handle = nullptr;

void InitADC() {
    //-------------ADC1 Init---------------//
    adc_oneshot_unit_init_cfg_t init_config1 = {
        .unit_id = ADC_UNIT_1,
    };
    ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));

    //-------------ADC1 Config---------------//
    adc_oneshot_chan_cfg_t config = {
        .atten = ADC_ATTEN_DB_11,
        .bitwidth = ADC_BITWIDTH_DEFAULT, // default width is max supported width
    };
    ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC_CHANNEL_6, &config));

    // Initialize 
    adc_cali_curve_fitting_config_t cali_config = {
        .unit_id = ADC_UNIT_1,
        .chan = ADC_CHANNEL_6,
        .atten = ADC_ATTEN_DB_11,
        .bitwidth = ADC_BITWIDTH_DEFAULT,
    };
    ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_channel_handle));


}

void ADCRead() {
    // Read raw value
    int raw = 0;
    ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC_CHANNEL_6, &raw));

    // Apply calibration to value
    int voltage = 0;
    ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_channel_handle, raw, &voltage));

    printf("ADC Channel[%d] Cali Voltage: %d mV\n", ADC_CHANNEL_6, voltage);
}

Usage example:

InitADC();
while(true)
{
    ADCRead();
    // Wait for some delay before reading again
    vTaskDelay(50 / portTICK_PERIOD_MS);
}

This prints, for example:

ADC Channel[6] Cali Voltage: 163 mV

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32

ESP32 HTTP POST with JSON body using ArduinoJson

This example parses a HTTP POST request body using ArduinoJson. I recommend using my HumanESPHTTP library as simple server library based on the ESP-IDF HTTP server.

constexpr size_t JsonParseBufferSize = 2048;
typedef ArduinoJson::StaticJsonDocument JsonParseBuffer;

/**
 * This buffer is used to parse /api/configure events
*/
static JsonParseBuffer document;

static const httpd_uri_t configureHandler = {
    .uri       = "/api/configure",
    .method    = HTTP_POST,
    .handler   = [](httpd_req_t *req) {
        // Receive POST body data into a new buffer
        char* jsonBody = (char*)malloc(req->content_len + 1);
        jsonBody[req->content_len] = '\0'; // NUL terminate [just in case]
        if(jsonBody == nullptr) {
            return SendStatusError(req, "Failed to allocate memory for JSON body");
        }
        int err = httpd_req_recv(req, jsonBody, req->content_len);
        if(err != req->content_len) {
            free(jsonBody);
            return SendStatusError(req, "Failed to read request body");
        }
        // Parse the body as JSON
        deserializeJson(document, jsonBody, req->content_len);
        // TODO: Do something with [document]
        // Cleanup
        free(jsonBody);
        return SendStatusOK(req);
    }
};

which uses the following utility functions:

esp_err_t SendStatusError(httpd_req_t *request, const char* description) {
    httpd_resp_set_type(request, "application/json");
    httpd_resp_send_chunk(request, "{\"status\":\"error\", \"error\": \"", HTTPD_RESP_USE_STRLEN);
    // NOTE: We silently assume that description does not have any special characters
    httpd_resp_send_chunk(request, description, HTTPD_RESP_USE_STRLEN);
    httpd_resp_send_chunk(request, "\"}", HTTPD_RESP_USE_STRLEN);
    httpd_resp_send_chunk(request, nullptr, 0); // Finished
    return ESP_OK;
}

esp_err_t SendStatusOK(httpd_req_t *request) {
    httpd_resp_set_type(request, "application/json");
    httpd_resp_sendstr(request, "{\"status\":\"ok\"}");
    return ESP_OK;
}

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32

How to fix ESP32 rmt: rmt_transmit(466): loop count is not supported

If you encounter

rmt: rmt_transmit(466): loop count is not supported

on the ESP32, this is because you have used a rmt_transmit_config_t with explicitly set loop_count.

rmt_transmit_config_t cfg = {
  .loop_count = 1,
  .flags = {
      .eot_level = 0,
   }
};
ESP_ERROR_CHECK(rmt_transmit(/* ... */, &cfg));

but your IC (e.g. ESP32-D0WD-V3)  does not support hardware loop mode.

Fixing this is easy: Just comment out the .loop_count line:

rmt_transmit_config_t cfg = {
  //.loop_count = 1, // DISABLED as chip does not support it
  .flags = {
      .eot_level = 0,
   }
};
ESP_ERROR_CHECK(rmt_transmit(/* ... */, &cfg));

Note that if you leave .loop_count at its default, it will always act as if .loop_count = 1.

Posted by Uli Köhler in C/C++, ESP8266/ESP32

ESP-IDF minimal Wifi client hello world example using PlatformIO

This basic example showcases how to use PlatformIO with ESP-IDF only (no Arduino) to connect to Wifi in station mode and print Hello world in a loop. It is based on the basic Hello World example from PlatformIO ESP32 with ESP-IDF minimal C++ example:

#include <cstdio>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

#include <esp_wifi.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <esp_netif.h>
#include <esp_event.h>


extern "C" {
    void app_main(void);
}


static void NetworkEventHandler(void* arg, esp_event_base_t event_base,
                          int32_t event_id, void* event_data) {
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        esp_wifi_connect();
        ESP_LOGI("wifi", "Retrying to connect to Wifi...");
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI("wifi", "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
    }
}

void InitNVS() {
    // Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
}

void InitWifi() {

    // Initialize TCP/IP network interface (required for Wi-Fi)
    ESP_ERROR_CHECK(esp_netif_init());

    // Initialize the event loop
    ESP_ERROR_CHECK(esp_event_loop_create_default());    
    esp_netif_create_default_wifi_sta();

    // Initialize Wi-Fi
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    // Set Wi-Fi to station mode
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));

    // Configure the Wi-Fi connection
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = "MyWifi",
            .password = "mypassword"
        }
    };
    // Register event handler
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &NetworkEventHandler,
                                                        NULL,
                                                        NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &NetworkEventHandler,
                                                        NULL,
                                                        NULL));

    // Set Wi-Fi configuration and start Wi-Fi
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
}

void app_main() {
    InitNVS();
    InitWifi();

    while(true) {
        printf("Hello PlatformIO!\n");
        // Wait for one second
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = espidf
monitor_speed = 115200

All sdkconfig settings have been left at their respective defaults.

Posted by Uli Köhler in C/C++, ESP8266/ESP32, PlatformIO

How to fix ESP-IDF error: cannot convert ‘esp_interface_t’ to ‘wifi_interface_t’

Problem:

While trying to  compile your ESP-IDF app using code such as

ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));

you see an error message such as

src/main.cpp:76:41: error: cannot convert 'esp_interface_t' to 'wifi_interface_t'
   76 |     ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
      |                                         ^~~~~~~~~~~~~~~
      |                                         |
      |                                         esp_interface_t

Solution:

Instead of ESP_IF_WIFI_STA, use WIFI_IF_STA (which has the correct type):

ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32

PlatformIO ESP32 with ESP-IDF minimal C++ example

By default, when you initialize a PlatformIO ESP-IDF project, it will generate main.c – not a C++ but a pure C file

This minimal example instead uses main.cpp (you can just rename your main.c – see How to use C++ main.cpp with PlatformIO on ESP32 / esp-idf for a detailed list of steps to do).

#include <cstdio>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

extern "C" {
    void app_main(void);
}

void app_main() {
    while(true) {
        printf("Hello PlatformIO!\n");
        // Wait for one second
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32, PlatformIO

How to use C++ main.cpp with PlatformIO on ESP32 / esp-idf

When you are using PlatformIO to compile your firmware, it is easily possible to use a C++ main.cpp instead of the pure C main.c by just renaming main.c to main.cpp

However, you also need to properly declary app_main(). After the #include section of your main.cpp (or at the top of the file if you don’t have an #include section yet), add this code:

extern "C" {
    void app_main(void);
}

This will tell the compiler that app_main() is a C function, not a C++ function.

Full main.cpp example

#include <cstdio>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

extern "C" {
    void app_main(void);
}

void app_main() {
    while(true) {
        printf("Hello PlatformIO!\n");
        // Wait for one second
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32, PlatformIO

How to generate inverted pulses using the ESP32 RMT module (Arduino & PlatformIO)

In our previous post ESP32 RMT pulse generation minimal example using Arduino & PlatformIO using the RMT peripheral. The pulses have a steady state (off state) of 0V and a pulse voltage of 3.3V.

If we want to generate inverted pulses, we have to invert the level entries in the pulseRMT array:

static const rmt_item32_t pulseRMT[] = {
    {{{
      /*pulse duration=*/100, /*pulse level*/0,
      // After pulse, output 1
      0, 1
    }}},
};

and additionally configure the RMT output when the pulse is finished using

config.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH;
config.tx_config.idle_output_en = true;

This is how the pulse looks like:

Full example:

#include <Arduino.h>
#include <esp_log.h>
#include <driver/rmt.h>

// Output pulse train on D14
constexpr gpio_num_t rmtPin = GPIO_NUM_14;
constexpr rmt_channel_t RMT_TX_CHANNEL = RMT_CHANNEL_0;

static const rmt_item32_t pulseRMT[] = {
    {{{
      /*pulse duration=*/100, /*pulse level*/0,
      // After pulse, output 1
      0, 1
    }}},
};

void setup() {
  Serial.begin(115200);

  rmt_config_t config = RMT_DEFAULT_CONFIG_TX(rmtPin, RMT_TX_CHANNEL);
  config.clk_div = 80; // input clock 80 MHz => output clk 1 MHz
  config.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH;
  config.tx_config.idle_output_en = true;

  ESP_ERROR_CHECK(rmt_config(&config));
  ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));

}

void loop() {
  ESP_ERROR_CHECK(rmt_write_items(RMT_TX_CHANNEL, pulseRMT, sizeof(pulseRMT) / sizeof(rmt_item32_t), true));
  delay(10);
}

 

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

 

Posted by Uli Köhler in Arduino, C/C++, ESP8266/ESP32, PlatformIO

ESP32 HTTP float query parser with range check example using HumanESPHTTP

Example for HumanESPHTTP

static const httpd_uri_t setPowerHandler = {
    .uri       = "/api/set-power",
    .method    = HTTP_GET,
    .handler   = [](httpd_req_t *request) {
        QueryURLParser parser(request);
        if(parser.HasParameter("power")) {
            std::string power = parser.GetParameter("power");
            // Parse power as float
            float powerFloat;
            try {
              powerFloat = std::stof(power);
            } catch (const std::invalid_argument& e) {
              httpd_resp_set_status(request, "400 Bad Request");
              httpd_resp_set_type(request, "text/plain");
              httpd_resp_sendstr(request, "Error: Invalid argument for power parameter (not a float)!");
              return ESP_OK;
            }
            // Check range
            if(powerFloat < 0.0 || powerFloat > 1.0) {
              httpd_resp_set_status(request, "400 Bad Request");
              httpd_resp_set_type(request, "text/plain");
              httpd_resp_sendstr(request, "Error: Invalid argument for power parameter (not in range 0.0 ... 1.0)!");
              return ESP_OK;
            }
            // TODO: Your code goes here
            // Example code: send back power
            httpd_resp_send_chunk(request, "Power is: ", HTTPD_RESP_USE_STRLEN);
            httpd_resp_send_chunk(request, std::to_string(powerFloat).c_str(), HTTPD_RESP_USE_STRLEN);
            httpd_resp_send_chunk(request, nullptr, 0); // Finished
        } else {
            httpd_resp_set_type(request, "text/plain");
              httpd_resp_set_status(request, "400 Bad Request");
            httpd_resp_sendstr(request, "No 'power' query parameter found!");
        }
        return ESP_OK;
    }
};

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32

ESP32 RMT pulse generation minimal example using Arduino & PlatformIO

The following example will generate 100us pulses every 10ms. The pulses are generated using the RMT peripheral.

#include <Arduino.h>
#include <esp_log.h>
#include <driver/rmt.h>

// Output pulse train on D14
constexpr gpio_num_t rmtPin = GPIO_NUM_14;
constexpr rmt_channel_t RMT_TX_CHANNEL = RMT_CHANNEL_0;


static const rmt_item32_t pulseRMT[] = {
    {{{
      /*pulse duration=*/100, /*pulse level*/1,
      // After pulse, output 0
      0, 0
    }}},
};


void setup() {
  Serial.begin(115200);

  rmt_config_t config = RMT_DEFAULT_CONFIG_TX(rmtPin, RMT_TX_CHANNEL);
  config.clk_div = 80; // input clock 80 MHz => output clk 1 MHz

  ESP_ERROR_CHECK(rmt_config(&config));
  ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));

}

void loop() {
  ESP_ERROR_CHECK(rmt_write_items(RMT_TX_CHANNEL, pulseRMT, sizeof(pulseRMT) / sizeof(rmt_item32_t), true));
  delay(10);
}

 

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

 

Posted by Uli Köhler in Arduino, C/C++, ESP8266/ESP32, PlatformIO

How to fix Arduino / PlatformIO undefined reference to `loop()’

Problem:

While trying to compile your Arduino or PlatformIO project, you see an error message such as
/home/uli/.platformio/packages/[email protected]+2021r2-patch5/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/esp32dev/libFrameworkArduino.a(main.cpp.o):(.literal._Z8loopTaskPv+0x8): undefined reference to `loop()'

Solution:

You have not declared a loop() function in your source code. Open main.cpp or your .ino source code file and start with the following (empty) loop() function which does nothing:
void loop() {
    // Nothing to do here since HTTPServer
    // is running in a separate thread
    delay(1000);
}
After you’ve added any void loop() { /* ... */} function to your sourcecode try to build/upload again and the error message should have disappeared.
If you want, you can also add code such as to print a message to the serial port every time the loop is run:
void loop() {
    // Nothing to do here since HTTPServer
    // is running in a separate thread
    Serial.println("Hello world!");
    delay(1000);
}

 

Posted by Uli Köhler in Arduino, C/C++, PlatformIO

Dynamic short pulse generator using Arduino Mega2560 with serial control

This is a simplified version of our hybrid static/dynamic pulse generator. On the Arduino Mega2560 platform, it allows generating pulses from 750ns up to almost arbitrary lengths (limited only by the integer width) with a resolution of approx. 437.5ns

In order to control the pulse width, open a serial interface and type + to increase the pulse width or - to decrease the pulse width.

#include <Arduino.h>
#include <avr/io.h>
#include <ArduinoJson.h>

const int pulseAPin = 11;

#define PORT11 PORTB
#define PIN11 5
#define PIN11_MASK (1 << PIN11)

int pulseLength = 0;

/**
 * Pulse the output pin, for very short pulses.
 */
void PulseDynamic(int n) {
    cli();
    PORT11 |= PIN11_MASK;
    // Dynamic for loop
    for (;n >= 0; n--) {
        _NOP();
    }
    PORT11 &= ~PIN11_MASK;
    sei();
}

void setup()
{
    Serial.begin(115200);
    Serial.setTimeout(25);

    pinMode(pulseAPin, OUTPUT);
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
    PulseDynamic(pulseLength);
    // Process serial
    while(Serial.available() > 0) {
        int c = Serial.read();
        if(c == '+') {
            pulseLength++;
            Serial.println(pulseLength);
        } else if(c == '-') {
            pulseLength--;
            if(pulseLength < 0) {pulseLength = 0;}
            Serial.println(pulseLength);
        }
    }
    delay(50);
}

 

Posted by Uli Köhler in Arduino, C/C++

Hybrid static/dynamic Arduino Mega2560 single channel short pulse generator

This pulse generator firmware uses methods discussed e.g. in Short pulse generation with Arduino Uno Part 4: NOP for loops to generate both dynamic (for loops of NOP instructions) and static (template-based automatically unrolled) in a combined manner so you can select more or less any pulse width using a high resolution.

It doesn’t work 100% since there are still some pulse width jumps. However, it is still useful for many microsecond 5V pulse generation applications and might also be a useful technology demonstrator for hybrid static/dynamic pulsers using optimized integer template loop unrolling approaches.

In order to control the pulse width, open a serial interface and type + to increase the pulse width or - to decrease the pulse width.

This might work on Arduino Unos as well but my Uno had a broken serial interface chip so I used a ATMega2560 board.

// License: CC0 1.0 Universal
// By Uli Köhler (techoverflow.net)
#include <Arduino.h>
#include <avr/io.h>
#include <ArduinoJson.h>

#define PORT13 PORTB
#define PIN13 7
#define PIN13_MASK (1 << PIN13)

#define PORT11 PORTB
#define PIN11 5
#define PIN11_MASK (1 << PIN11)

int pulseLength = 1;

using PulseFunc = void (*)(int);

// Function pointer to void(int)
PulseFunc pulser = nullptr;
int pulserParam = 0; // Pre-computed parameter for the pulser function

void DoNothingPulser(int _) {
}

/**
 * Pulse the output pin, for very short pulses.
 * Will ONLY perform static (optimized) NOPs.
 * Will NOT perform dynamic (slower) NOP cycles
 * 
 * Hence, this function does not have any overhead from for loops.
 */
template<int nNOPs>
void PulseStatic(int _) {
    cli();
    PORT11 |= PIN11_MASK;
    // Static for loop (optimized out - template-driven)
    // Force unrolling of the loop
    // NOTE: Compiler will only unroll for n < 8
    for (int i = 0; i < min(nNOPs, 6); i++) {
        _NOP();
    }
    if(nNOPs > 6) {
        for (int i = 0; i < nNOPs - 6; i++) {
            _NOP();
        }
    }
    PORT11 &= ~PIN11_MASK;
    sei();
}

/**
 * Pulse the output pin, for very short pulses.
 * Will perform static (optimized) NOPs and
 * also dynamic (slower) NOP cycles
 */
template<int nNOPs>
void PulseDynamic(int dynamicNOPs) {
    cli();
    PORT11 |= PIN11_MASK;
    // Dynamic for loop (NOT optimized out - template-driven)
    for (int i = 0; i < dynamicNOPs; i++)
    {
        _NOP();
    }
    // Static for loop (optimized out - template-driven)
    // Force unrolling of the loop
    // NOTE: Compiler will only unroll for n < 8
    for (int i = 0; i < min(nNOPs, 6); i++) {
        _NOP();
    }
    if(nNOPs > 6) {
        for (int i = 0; i < nNOPs - 6; i++) {
            _NOP();
        }
    }
    PORT11 &= ~PIN11_MASK;
    sei();
}

PulseFunc staticPulsers[] = {
    DoNothingPulser,
    &PulseStatic<0>, // 0 NOPs
    &PulseStatic<1>, // 1 NOPs ...
    &PulseStatic<2>,
    &PulseStatic<3>,
    &PulseStatic<4>,
    &PulseStatic<5>,
    &PulseStatic<6>,
    &PulseStatic<7>,
    &PulseStatic<8>,
    &PulseStatic<9>,
    &PulseStatic<10>,
    &PulseStatic<11>
};

PulseFunc dynamicPulsers[] = {
    &PulseDynamic<0>,
    &PulseDynamic<1>,
    &PulseDynamic<2>,
    &PulseDynamic<3>,
    &PulseDynamic<4>,
    &PulseDynamic<5>,
    &PulseDynamic<6>,
    &PulseDynamic<7>,
    &PulseDynamic<8>,
    &PulseDynamic<9>,
    &PulseDynamic<10>,
    &PulseDynamic<11>
};

constexpr int A = 7;
constexpr int B = 6;

void ReconfigurePulse() {
    // Very short pulses are performed using only static
    if(pulseLength < A) {
        pulser = staticPulsers[pulseLength];
    } else {
        pulser = dynamicPulsers[(pulseLength - A) % B];
        pulserParam = (pulseLength - A) / B;
    }
}

void setup()
{
    Serial.begin(115200);
    Serial.setTimeout(25);

    ReconfigurePulse(); // with default pulseLength

    pinMode(11, OUTPUT);
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
    pulser(pulserParam);
    Serial.println(pulseLength);
    //ProcessSerialInput();
    // Wait until 50ms has passed since start
    while(Serial.available() > 0) {
        int c = Serial.read();
        if(c == '+') {
            pulseLength++;
            ReconfigurePulse();
        } else if(c == '-') {
            pulseLength--;
            if(pulseLength < 0) {pulseLength = 0;}
            ReconfigurePulse();
        }
    }
    delay(50);
}

 

 

Posted by Uli Köhler in Arduino, C/C++

How to list all C++ header files included by a source or header file recursively

You can use g++ -M to list all files included by a header file recursively:

gcc -M myheader.hpp

Often you want to ignore system header files from /usr/include etc – in that case, use -MM:

gcc -MM myheader.hpp

For example:

gcc -M /usr/include/boost/circular_buffer/base.hpp

will print:

base.o: /usr/include/boost/circular_buffer/base.hpp \
 /usr/include/stdc-predef.h /usr/include/boost/config.hpp \
 /usr/include/boost/config/user.hpp \
 /usr/include/boost/config/detail/select_compiler_config.hpp \
 /usr/include/boost/config/compiler/gcc.hpp /usr/include/c++/11/cstddef \
 /usr/include/x86_64-linux-gnu/c++/11/bits/c++config.h \
 /usr/include/x86_64-linux-gnu/c++/11/bits/os_defines.h \
 /usr/include/features.h /usr/include/features-time64.h \
 /usr/include/x86_64-linux-gnu/bits/wordsize.h \
 /usr/include/x86_64-linux-gnu/bits/timesize.h \
 /usr/include/x86_64-linux-gnu/sys/cdefs.h \
 /usr/include/x86_64-linux-gnu/bits/long-double.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs.h \
 /usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
 /usr/include/x86_64-linux-gnu/c++/11/bits/cpu_defines.h \
 /usr/include/c++/11/pstl/pstl_config.h \
 /usr/lib/gcc/x86_64-linux-gnu/11/include/stddef.h \
 /usr/include/boost/config/detail/select_stdlib_config.hpp \
 /usr/include/c++/11/version \
 /usr/include/boost/config/stdlib/libstdcpp3.hpp /usr/include/unistd.h \
 /usr/include/x86_64-linux-gnu/bits/posix_opt.h \
 /usr/include/x86_64-linux-gnu/bits/environments.h \
 /usr/include/x86_64-linux-gnu/bits/types.h \
 /usr/include/x86_64-linux-gnu/bits/typesizes.h \
 /usr/include/x86_64-linux-gnu/bits/time64.h \
 /usr/include/x86_64-linux-gnu/bits/confname.h \
 /usr/include/x86_64-linux-gnu/bits/getopt_posix.h \
 /usr/include/x86_64-linux-gnu/bits/getopt_core.h \
 /usr/include/x86_64-linux-gnu/bits/unistd_ext.h \
 /usr/include/linux/close_range.h \
 /usr/include/boost/config/detail/select_platform_config.hpp \
 /usr/include/boost/config/platform/linux.hpp /usr/include/c++/11/cstdlib \
 /usr/include/stdlib.h \
 /usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
 /usr/include/x86_64-linux-gnu/bits/waitflags.h \
 /usr/include/x86_64-linux-gnu/bits/waitstatus.h \
 /usr/include/x86_64-linux-gnu/bits/floatn.h \
 /usr/include/x86_64-linux-gnu/bits/floatn-common.h \
 /usr/include/x86_64-linux-gnu/bits/types/locale_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__locale_t.h \
 /usr/include/x86_64-linux-gnu/sys/types.h \
 /usr/include/x86_64-linux-gnu/bits/types/clock_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/clockid_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/time_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/timer_t.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-intn.h /usr/include/endian.h \
 /usr/include/x86_64-linux-gnu/bits/endian.h \
 /usr/include/x86_64-linux-gnu/bits/endianness.h \
 /usr/include/x86_64-linux-gnu/bits/byteswap.h \
 /usr/include/x86_64-linux-gnu/bits/uintn-identity.h \
 /usr/include/x86_64-linux-gnu/sys/select.h \
 /usr/include/x86_64-linux-gnu/bits/select.h \
 /usr/include/x86_64-linux-gnu/bits/types/sigset_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__sigset_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_timeval.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_timespec.h \
 /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h \
 /usr/include/x86_64-linux-gnu/bits/thread-shared-types.h \
 /usr/include/x86_64-linux-gnu/bits/pthreadtypes-arch.h \
 /usr/include/x86_64-linux-gnu/bits/atomic_wide_counter.h \
 /usr/include/x86_64-linux-gnu/bits/struct_mutex.h \
 /usr/include/x86_64-linux-gnu/bits/struct_rwlock.h /usr/include/alloca.h \
 /usr/include/x86_64-linux-gnu/bits/stdlib-float.h \
 /usr/include/c++/11/bits/std_abs.h \
 /usr/include/boost/config/detail/posix_features.hpp \
 /usr/include/boost/config/detail/suffix.hpp \
 /usr/include/boost/config/helper_macros.hpp \
 /usr/include/boost/config/detail/cxx_composite.hpp \
 /usr/include/boost/concept_check.hpp \
 /usr/include/boost/concept/assert.hpp \
 /usr/include/boost/config/workaround.hpp \
 /usr/include/boost/concept/detail/general.hpp \
 /usr/include/boost/preprocessor/cat.hpp \
 /usr/include/boost/preprocessor/config/config.hpp \
 /usr/include/boost/concept/detail/backward_compatibility.hpp \
 /usr/include/boost/concept/detail/has_constraints.hpp \
 /usr/include/boost/type_traits/integral_constant.hpp \
 /usr/include/boost/detail/workaround.hpp \
 /usr/include/boost/type_traits/conditional.hpp \
 /usr/include/c++/11/iterator \
 /usr/include/c++/11/bits/stl_iterator_base_types.h \
 /usr/include/c++/11/type_traits \
 /usr/include/c++/11/bits/stl_iterator_base_funcs.h \
 /usr/include/c++/11/bits/concept_check.h \
 /usr/include/c++/11/debug/assertions.h \
 /usr/include/c++/11/bits/stl_iterator.h \
 /usr/include/c++/11/bits/cpp_type_traits.h \
 /usr/include/c++/11/ext/type_traits.h /usr/include/c++/11/bits/move.h \
 /usr/include/c++/11/bits/ptr_traits.h /usr/include/c++/11/iosfwd \
 /usr/include/c++/11/bits/stringfwd.h \
 /usr/include/c++/11/bits/memoryfwd.h /usr/include/c++/11/bits/postypes.h \
 /usr/include/c++/11/cwchar /usr/include/wchar.h \
 /usr/lib/gcc/x86_64-linux-gnu/11/include/stdarg.h \
 /usr/include/x86_64-linux-gnu/bits/wchar.h \
 /usr/include/x86_64-linux-gnu/bits/types/wint_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/mbstate_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__FILE.h \
 /usr/include/x86_64-linux-gnu/bits/types/FILE.h \
 /usr/include/c++/11/bits/stream_iterator.h \
 /usr/include/c++/11/debug/debug.h \
 /usr/include/c++/11/bits/streambuf_iterator.h \
 /usr/include/c++/11/streambuf /usr/include/c++/11/bits/localefwd.h \
 /usr/include/x86_64-linux-gnu/c++/11/bits/c++locale.h \
 /usr/include/c++/11/clocale /usr/include/locale.h \
 /usr/include/x86_64-linux-gnu/bits/locale.h /usr/include/c++/11/cctype \
 /usr/include/ctype.h /usr/include/c++/11/bits/ios_base.h \
 /usr/include/c++/11/ext/atomicity.h \
 /usr/include/x86_64-linux-gnu/c++/11/bits/gthr.h \
 /usr/include/x86_64-linux-gnu/c++/11/bits/gthr-default.h \
 /usr/include/pthread.h /usr/include/sched.h \
 /usr/include/x86_64-linux-gnu/bits/sched.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_sched_param.h \
 /usr/include/x86_64-linux-gnu/bits/cpu-set.h /usr/include/time.h \
 /usr/include/x86_64-linux-gnu/bits/time.h \
 /usr/include/x86_64-linux-gnu/bits/timex.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_tm.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_itimerspec.h \
 /usr/include/x86_64-linux-gnu/bits/setjmp.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct___jmp_buf_tag.h \
 /usr/include/x86_64-linux-gnu/bits/pthread_stack_min-dynamic.h \
 /usr/include/x86_64-linux-gnu/c++/11/bits/atomic_word.h \
 /usr/include/x86_64-linux-gnu/sys/single_threaded.h \
 /usr/include/c++/11/bits/locale_classes.h /usr/include/c++/11/string \
 /usr/include/c++/11/bits/char_traits.h \
 /usr/include/c++/11/bits/stl_algobase.h \
 /usr/include/c++/11/bits/functexcept.h \
 /usr/include/c++/11/bits/exception_defines.h \
 /usr/include/c++/11/ext/numeric_traits.h \
 /usr/include/c++/11/bits/stl_pair.h \
 /usr/include/c++/11/bits/predefined_ops.h /usr/include/c++/11/cstdint \
 /usr/lib/gcc/x86_64-linux-gnu/11/include/stdint.h /usr/include/stdint.h \
 /usr/include/x86_64-linux-gnu/bits/stdint-uintn.h \
 /usr/include/c++/11/bits/allocator.h \
 /usr/include/x86_64-linux-gnu/c++/11/bits/c++allocator.h \
 /usr/include/c++/11/ext/new_allocator.h /usr/include/c++/11/new \
 /usr/include/c++/11/bits/exception.h \
 /usr/include/c++/11/bits/ostream_insert.h \
 /usr/include/c++/11/bits/cxxabi_forced.h \
 /usr/include/c++/11/bits/stl_function.h \
 /usr/include/c++/11/backward/binders.h \
 /usr/include/c++/11/bits/range_access.h \
 /usr/include/c++/11/initializer_list \
 /usr/include/c++/11/bits/basic_string.h \
 /usr/include/c++/11/ext/alloc_traits.h \
 /usr/include/c++/11/bits/alloc_traits.h \
 /usr/include/c++/11/bits/stl_construct.h /usr/include/c++/11/string_view \
 /usr/include/c++/11/bits/functional_hash.h \
 /usr/include/c++/11/bits/hash_bytes.h \
 /usr/include/c++/11/bits/string_view.tcc \
 /usr/include/c++/11/ext/string_conversions.h /usr/include/c++/11/cstdio \
 /usr/include/stdio.h /usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h \
 /usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h \
 /usr/include/x86_64-linux-gnu/bits/types/cookie_io_functions_t.h \
 /usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
 /usr/include/c++/11/cerrno /usr/include/errno.h \
 /usr/include/x86_64-linux-gnu/bits/errno.h /usr/include/linux/errno.h \
 /usr/include/x86_64-linux-gnu/asm/errno.h \
 /usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
 /usr/include/x86_64-linux-gnu/bits/types/error_t.h \
 /usr/include/c++/11/bits/charconv.h \
 /usr/include/c++/11/bits/basic_string.tcc \
 /usr/include/c++/11/bits/locale_classes.tcc \
 /usr/include/c++/11/system_error \
 /usr/include/x86_64-linux-gnu/c++/11/bits/error_constants.h \
 /usr/include/c++/11/stdexcept /usr/include/c++/11/exception \
 /usr/include/c++/11/bits/exception_ptr.h \
 /usr/include/c++/11/bits/cxxabi_init_exception.h \
 /usr/include/c++/11/typeinfo /usr/include/c++/11/bits/nested_exception.h \
 /usr/include/c++/11/bits/streambuf.tcc \
 /usr/include/boost/type_traits/conversion_traits.hpp \
 /usr/include/boost/type_traits/is_convertible.hpp \
 /usr/include/boost/type_traits/intrinsics.hpp \
 /usr/include/boost/type_traits/detail/config.hpp \
 /usr/include/boost/version.hpp \
 /usr/include/boost/type_traits/is_complete.hpp \
 /usr/include/boost/type_traits/declval.hpp \
 /usr/include/boost/type_traits/add_rvalue_reference.hpp \
 /usr/include/boost/type_traits/is_void.hpp \
 /usr/include/boost/type_traits/is_reference.hpp \
 /usr/include/boost/type_traits/is_lvalue_reference.hpp \
 /usr/include/boost/type_traits/is_rvalue_reference.hpp \
 /usr/include/boost/type_traits/remove_reference.hpp \
 /usr/include/boost/type_traits/is_function.hpp \
 /usr/include/boost/type_traits/detail/is_function_cxx_11.hpp \
 /usr/include/boost/type_traits/detail/yes_no_type.hpp \
 /usr/include/boost/type_traits/is_array.hpp \
 /usr/include/boost/static_assert.hpp \
 /usr/include/boost/type_traits/is_arithmetic.hpp \
 /usr/include/boost/type_traits/is_integral.hpp \
 /usr/include/boost/type_traits/is_floating_point.hpp \
 /usr/include/boost/type_traits/is_abstract.hpp \
 /usr/include/boost/type_traits/add_lvalue_reference.hpp \
 /usr/include/boost/type_traits/add_reference.hpp \
 /usr/include/c++/11/utility /usr/include/c++/11/bits/stl_relops.h \
 /usr/include/boost/type_traits/is_same.hpp \
 /usr/include/boost/concept/usage.hpp \
 /usr/include/boost/concept/detail/concept_def.hpp \
 /usr/include/boost/preprocessor/seq/for_each_i.hpp \
 /usr/include/boost/preprocessor/arithmetic/dec.hpp \
 /usr/include/boost/preprocessor/config/limits.hpp \
 /usr/include/boost/preprocessor/arithmetic/limits/dec_256.hpp \
 /usr/include/boost/preprocessor/arithmetic/inc.hpp \
 /usr/include/boost/preprocessor/arithmetic/limits/inc_256.hpp \
 /usr/include/boost/preprocessor/control/if.hpp \
 /usr/include/boost/preprocessor/control/iif.hpp \
 /usr/include/boost/preprocessor/logical/bool.hpp \
 /usr/include/boost/preprocessor/logical/limits/bool_256.hpp \
 /usr/include/boost/preprocessor/repetition/for.hpp \
 /usr/include/boost/preprocessor/debug/error.hpp \
 /usr/include/boost/preprocessor/facilities/empty.hpp \
 /usr/include/boost/preprocessor/detail/auto_rec.hpp \
 /usr/include/boost/preprocessor/detail/limits/auto_rec_256.hpp \
 /usr/include/boost/preprocessor/repetition/detail/for.hpp \
 /usr/include/boost/preprocessor/control/expr_iif.hpp \
 /usr/include/boost/preprocessor/tuple/eat.hpp \
 /usr/include/boost/preprocessor/repetition/detail/limits/for_256.hpp \
 /usr/include/boost/preprocessor/repetition/limits/for_256.hpp \
 /usr/include/boost/preprocessor/seq/seq.hpp \
 /usr/include/boost/preprocessor/seq/elem.hpp \
 /usr/include/boost/preprocessor/seq/limits/elem_256.hpp \
 /usr/include/boost/preprocessor/seq/size.hpp \
 /usr/include/boost/preprocessor/seq/limits/size_256.hpp \
 /usr/include/boost/preprocessor/seq/detail/is_empty.hpp \
 /usr/include/boost/preprocessor/logical/compl.hpp \
 /usr/include/boost/preprocessor/tuple/elem.hpp \
 /usr/include/boost/preprocessor/facilities/expand.hpp \
 /usr/include/boost/preprocessor/facilities/overload.hpp \
 /usr/include/boost/preprocessor/variadic/size.hpp \
 /usr/include/boost/preprocessor/facilities/check_empty.hpp \
 /usr/include/boost/preprocessor/variadic/has_opt.hpp \
 /usr/include/boost/preprocessor/variadic/limits/size_64.hpp \
 /usr/include/boost/preprocessor/tuple/rem.hpp \
 /usr/include/boost/preprocessor/tuple/detail/is_single_return.hpp \
 /usr/include/boost/preprocessor/variadic/elem.hpp \
 /usr/include/boost/preprocessor/variadic/limits/elem_64.hpp \
 /usr/include/boost/preprocessor/seq/enum.hpp \
 /usr/include/boost/preprocessor/seq/limits/enum_256.hpp \
 /usr/include/boost/preprocessor/comma_if.hpp \
 /usr/include/boost/preprocessor/punctuation/comma_if.hpp \
 /usr/include/boost/preprocessor/punctuation/comma.hpp \
 /usr/include/boost/concept/detail/concept_undef.hpp \
 /usr/include/boost/limits.hpp /usr/include/c++/11/limits \
 /usr/include/boost/core/allocator_access.hpp \
 /usr/include/boost/core/pointer_traits.hpp \
 /usr/include/boost/core/addressof.hpp \
 /usr/include/boost/core/empty_value.hpp \
 /usr/include/boost/type_traits/is_stateless.hpp \
 /usr/include/boost/type_traits/has_trivial_constructor.hpp \
 /usr/include/boost/type_traits/is_pod.hpp \
 /usr/include/boost/type_traits/is_scalar.hpp \
 /usr/include/boost/type_traits/is_enum.hpp \
 /usr/include/boost/type_traits/is_pointer.hpp \
 /usr/include/boost/type_traits/is_member_pointer.hpp \
 /usr/include/boost/type_traits/is_member_function_pointer.hpp \
 /usr/include/boost/type_traits/detail/is_member_function_pointer_cxx_11.hpp \
 /usr/include/boost/type_traits/is_default_constructible.hpp \
 /usr/include/boost/type_traits/is_volatile.hpp \
 /usr/include/boost/type_traits/has_trivial_copy.hpp \
 /usr/include/boost/type_traits/is_copy_constructible.hpp \
 /usr/include/boost/type_traits/is_constructible.hpp \
 /usr/include/boost/type_traits/is_destructible.hpp \
 /usr/include/boost/type_traits/has_trivial_destructor.hpp \
 /usr/include/boost/type_traits/is_class.hpp \
 /usr/include/boost/type_traits/is_empty.hpp \
 /usr/include/boost/type_traits/remove_cv.hpp \
 /usr/include/boost/type_traits/is_nothrow_move_constructible.hpp \
 /usr/include/boost/type_traits/enable_if.hpp \
 /usr/include/boost/type_traits/is_nothrow_move_assignable.hpp \
 /usr/include/boost/type_traits/has_trivial_move_assign.hpp \
 /usr/include/boost/type_traits/is_assignable.hpp \
 /usr/include/boost/type_traits/has_nothrow_assign.hpp \
 /usr/include/boost/type_traits/is_const.hpp \
 /usr/include/boost/move/adl_move_swap.hpp \
 /usr/include/boost/move/detail/workaround.hpp \
 /usr/include/boost/move/utility_core.hpp \
 /usr/include/boost/move/detail/config_begin.hpp \
 /usr/include/boost/move/core.hpp \
 /usr/include/boost/move/detail/config_end.hpp \
 /usr/include/boost/move/detail/meta_utils.hpp \
 /usr/include/boost/move/detail/meta_utils_core.hpp \
 /usr/include/boost/move/detail/addressof.hpp \
 /usr/include/boost/move/move.hpp /usr/include/boost/move/utility.hpp \
 /usr/include/boost/move/traits.hpp \
 /usr/include/boost/move/detail/type_traits.hpp \
 /usr/include/c++/11/cassert /usr/include/assert.h \
 /usr/include/boost/move/iterator.hpp \
 /usr/include/boost/move/detail/iterator_traits.hpp \
 /usr/include/boost/move/detail/std_ns_begin.hpp \
 /usr/include/boost/move/detail/std_ns_end.hpp \
 /usr/include/boost/move/algorithm.hpp \
 /usr/include/boost/move/algo/move.hpp \
 /usr/include/boost/move/detail/iterator_to_raw_pointer.hpp \
 /usr/include/boost/move/detail/to_raw_pointer.hpp \
 /usr/include/boost/move/detail/pointer_element.hpp \
 /usr/include/c++/11/algorithm /usr/include/c++/11/bits/stl_algo.h \
 /usr/include/c++/11/bits/algorithmfwd.h \
 /usr/include/c++/11/bits/stl_heap.h \
 /usr/include/c++/11/bits/stl_tempbuf.h \
 /usr/include/c++/11/bits/uniform_int_dist.h \
 /usr/include/c++/11/pstl/glue_algorithm_defs.h \
 /usr/include/c++/11/functional /usr/include/c++/11/tuple \
 /usr/include/c++/11/array /usr/include/c++/11/bits/uses_allocator.h \
 /usr/include/c++/11/bits/invoke.h /usr/include/c++/11/bits/refwrap.h \
 /usr/include/c++/11/bits/std_function.h \
 /usr/include/c++/11/unordered_map \
 /usr/include/c++/11/ext/aligned_buffer.h \
 /usr/include/c++/11/bits/hashtable.h \
 /usr/include/c++/11/bits/hashtable_policy.h \
 /usr/include/c++/11/bits/enable_special_members.h \
 /usr/include/c++/11/bits/node_handle.h \
 /usr/include/c++/11/bits/unordered_map.h \
 /usr/include/c++/11/bits/erase_if.h /usr/include/c++/11/vector \
 /usr/include/c++/11/bits/stl_uninitialized.h \
 /usr/include/c++/11/bits/stl_vector.h \
 /usr/include/c++/11/bits/stl_bvector.h \
 /usr/include/c++/11/bits/vector.tcc \
 /usr/include/c++/11/pstl/execution_defs.h /usr/include/c++/11/memory \
 /usr/include/c++/11/bits/stl_raw_storage_iter.h \
 /usr/include/c++/11/bits/align.h /usr/include/c++/11/bit \
 /usr/include/c++/11/bits/unique_ptr.h \
 /usr/include/c++/11/bits/shared_ptr.h \
 /usr/include/c++/11/bits/shared_ptr_base.h \
 /usr/include/c++/11/bits/allocated_ptr.h \
 /usr/include/c++/11/ext/concurrence.h \
 /usr/include/c++/11/bits/shared_ptr_atomic.h \
 /usr/include/c++/11/bits/atomic_base.h \
 /usr/include/c++/11/bits/atomic_lockfree_defines.h \
 /usr/include/c++/11/backward/auto_ptr.h \
 /usr/include/c++/11/pstl/glue_memory_defs.h /usr/include/c++/11/deque \
 /usr/include/c++/11/bits/stl_deque.h /usr/include/c++/11/bits/deque.tcc

 

Posted by Uli Köhler in C/C++

C++ S3 GetObject minimal streaming example using minio-cpp

#include <client.h>
#include <iostream>

using std::cout, std::endl;

int main(int argc, char* argv[]) {
  // Create S3 base URL.
  minio::s3::BaseUrl base_url("minio.mydomain.com");

  // Create credential provider.
  minio::creds::StaticProvider provider(
      "my-access-key", "my-secret-key");

  // Create S3 client.
  minio::s3::Client client(base_url, &provider);
  std::string bucket_name = "my-bucket";

  // Build arguments object
  minio::s3::GetObjectArgs args;
  args.bucket = bucket_name;
  args.object = "my-object.txt";
  args.datafunc = [](minio::http::DataFunctionArgs args) -> bool {
    // This function will be called for every data chunk of the object
    cout << args.datachunk;
    return true;
  };

  // Perform the request (calling datafunc for every chunk)
  minio::s3::GetObjectResponse resp = client.GetObject(args);
  // Handle error (if any)
  if (resp) {
    cout << endl // end line after file content
         << "data of my-object is received successfully" << endl;
  } else {
    cout << "Error during GetObject(): " << resp.Error().String() << endl;
  }

  return EXIT_SUCCESS;
}

 

Posted by Uli Köhler in C/C++, S3

C++ S3 ListObjects minimal example using minio-cpp

#include <client.h>

int main(int argc, char* argv[]) {
  // Create S3 base URL.
  minio::s3::BaseUrl base_url("minio.mydomain.com");

  // Create credential provider.
  minio::creds::StaticProvider provider(
      "my_access_key", "my_secret_key");

  // Create S3 client.
  minio::s3::Client client(base_url, &provider);
  std::string bucket_name = "my-bucket";

  minio::s3::ListObjectsArgs args;
  args.bucket = bucket_name;
  // Optional prefix filter
  args.prefix = "folder/";

  minio::s3::ListObjectsResult result = client.ListObjects(args);
  for (; result; result++) {
      minio::s3::Item item = *result;
      if (!item) {
        throw std::runtime_error("Error during ListObjects(): " + item.Error().String());
      }
      std::cout << item.name << std::endl;
  }

  return EXIT_SUCCESS;
}

 

Posted by Uli Köhler in C/C++, S3