/** * Copyright (C) 2018 HAW-Hamburg * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @ingroup tests * @{ * * @file * @brief Test application for the SDS011 Laser Dust Sensor driver * * @author Michel Rottleuthner * * @} */ #include #include #include #include "xtimer.h" #include "sds011.h" #include "sds011_params.h" #include "msg.h" #include "thread.h" #define ACTIVE_REPORTING_TEST_CNT (20U) #define PUT_TO_QUERY_MODE_RETRIES (3U) #define PUT_TO_QUERY_MODE_RETRY_TIMEOUT_MS (100U) #define MANUAL_QUERY_CNT (10U) #define WORKING_PERIOD (0U) /** * @brief Allocate the device descriptor */ static sds011_t dev; static char* _rmode_str(sds011_reporting_mode_t rmode) { switch (rmode) { case SDS011_RMODE_ACTIVE: return "ACTIVE"; case SDS011_RMODE_QUERY: return "QUERY"; default: return "INVALID"; } } static char* _wmode_str(sds011_working_mode_t wmode) { switch (wmode) { case SDS011_WMODE_WORK: return "WORK"; case SDS011_WMODE_SLEEP: return "SLEEP"; default: return "INVALID"; } } static void _print_measurement(sds011_data_t *data) { uint16_t pm10_ug_int = data->pm_10 / 10; uint16_t pm10_ug_dec = data->pm_10 - 10 * pm10_ug_int; uint16_t pm2_5_ug_int = data->pm_2_5 / 10; uint16_t pm2_5_ug_dec = data->pm_2_5 - 10 * pm2_5_ug_int; printf("==> PM2.5: %d.%0d ug/m^3 | PM10: %d.%0d ug/m^3\n", pm2_5_ug_int, pm2_5_ug_dec, pm10_ug_int, pm10_ug_dec); } void measure_cb(sds011_data_t *data, void *ctx) { msg_t msg = { .content.value = (((uint32_t)data->pm_10) << 16 | data->pm_2_5) }; kernel_pid_t target_pid = (int)ctx; msg_send(&msg, target_pid); } int main(void) { unsigned retry_cnt = 0; uint8_t year; uint8_t month; uint8_t day; sds011_reporting_mode_t rmode; sds011_working_mode_t wmode; uint8_t minutes; sds011_data_t data; puts("SDS011 test application"); /* initialize the driver */ if (sds011_init(&dev, &sds011_params[0]) == SDS011_OK) { puts("init [OK]"); } else { puts("initialization [ERROR]"); return -1; } printf("setting reporting mode to '%s'...\n", _rmode_str(SDS011_RMODE_QUERY)); /* set the sensor to query mode to disable active reporting messages -> to work correctly, this step may need to be repeated if the automatic output is incoming while the reply is expected */ while (sds011_set_reporting_mode(&dev, SDS011_RMODE_QUERY) != SDS011_OK) { if (retry_cnt++ >= PUT_TO_QUERY_MODE_RETRIES) { puts("[ERROR]"); return -1; } xtimer_usleep(PUT_TO_QUERY_MODE_RETRY_TIMEOUT_MS * 1000); puts("[RETRY]"); } puts("[OK]"); puts("getting reporting mode from device..."); if (sds011_get_reporting_mode(&dev, &rmode) == SDS011_OK) { printf("[OK] => mode: %s\n", _rmode_str(rmode)); if (rmode != SDS011_RMODE_QUERY) { puts("mismatch! [ERROR]"); return -1; } } else { puts("[ERROR]"); return -1; } puts("getting firmware version..."); if (sds011_get_fw_version(&dev, &year, &month, &day) == SDS011_OK) { printf("[OK] => %d.%d.%d\n", year, month, day); } else { puts("[ERROR]"); return -1; } printf("setting working mode to '%s'...\n", _wmode_str(SDS011_WMODE_WORK)); if (sds011_set_working_mode(&dev, SDS011_WMODE_WORK) == SDS011_OK) { puts("[OK]"); } else { puts("[ERROR]"); return -1; } puts("getting working mode from device..."); if (sds011_get_working_mode(&dev, &wmode) == SDS011_OK) { printf("[OK] => mode: %s\n", _wmode_str(wmode)); if (wmode != SDS011_WMODE_WORK) { puts("mismatch! [ERROR]"); return -1; } } else { puts("[ERROR]"); return -1; } printf("setting working period to %u...\n", WORKING_PERIOD); if (sds011_set_working_period(&dev, WORKING_PERIOD) == SDS011_OK) { puts("[OK]"); } else { puts("[ERROR]"); return 1; } if (sds011_get_working_period(&dev, &minutes) == SDS011_OK) { printf("[OK] => working period: %u\n", minutes); if (minutes != WORKING_PERIOD) { puts("mismatch! [ERROR]"); return -1; } } else { puts("[ERROR]"); return -1; } for (unsigned i = 0; i < MANUAL_QUERY_CNT; i++) { if (sds011_read(&dev, &data) == SDS011_OK) { printf("manual query %2u/%u [OK]: ", i + 1, MANUAL_QUERY_CNT); _print_measurement(&data); } } sds011_register_callback(&dev, measure_cb, (void*)(int)thread_getpid()); printf("switching to active reporting mode for %u measurements...\n", ACTIVE_REPORTING_TEST_CNT); if (sds011_set_reporting_mode(&dev, SDS011_RMODE_ACTIVE) == SDS011_OK) { puts("[OK]"); } else { puts("[ERROR]"); return -1; } /* wait a little bit so the callback gets executed a few times */ msg_t msg; for(unsigned msg_cnt = 0; msg_cnt < ACTIVE_REPORTING_TEST_CNT; msg_cnt++){ msg_receive(&msg); sds011_data_t data; data.pm_10 = msg.content.value >> 16; data.pm_2_5 = msg.content.value & 0xFFFF; printf("msg from callback: "); _print_measurement(&data); } /* unregister callback */ sds011_register_callback(&dev, NULL, NULL); puts("switching to sleep mode..."); if (sds011_set_working_mode(&dev, SDS011_WMODE_SLEEP) == SDS011_OK) { puts("[OK]"); } else { puts("[ERROR]"); return -1; } puts("[SUCCESS]"); return 0; }