Sat, 21 Oct 2023 16:22:20 +0200
Added 77.5 KHz signal generation
/** * @file task_dcf.c * @brief DCF77 task. */ #include "dcf77tx.h" static const char *TAG = "task_dcf"; SemaphoreHandle_t xSemaphoreDCF = NULL; ///< Semaphore DCF task. EventGroupHandle_t xEventGroupDCF; ///< Events DCF task. DCF_State *dcf_state = NULL; ///< Public state for other tasks. esp_timer_handle_t timerHandle; ///< Timer handler int impulseCount = 0; ///< 100 mSec transmit slices. int8_t impulseArray[61]; ///< Pulses, 0 = no pulse, 1=100ms, 2=200ms int actualSecond = 0; ///< Current second to transmit. time_t dcf_now; ///< Current time to send. struct tm dcf_tm; ///< Local broken down time. ledc_timer_config_t ledc_timer = { .speed_mode = LEDC_LOW_SPEED_MODE, ///< Use high speed timer .timer_num = LEDC_TIMER_0, ///< Timer 0 .duty_resolution = LEDC_TIMER_10_BIT, ///< 10 bits resolution .freq_hz = 77500, ///< 77.5 KHz .clk_cfg = LEDC_AUTO_CLK ///< Auto select PWM clock }; ledc_channel_config_t dcf77_100tx = { ///< 100% Antenna power .channel = LEDC_CHANNEL_0, .duty = 0, ///< Default 0% .gpio_num = CONFIG_ANTENNA_100_PIN, ///< Antenna pin 100% .speed_mode = LEDC_LOW_SPEED_MODE, .hpoint = 0, .intr_type = LEDC_INTR_DISABLE, .timer_sel = LEDC_TIMER_0 ///< Timer 0 }; ledc_channel_config_t dcf77_15tx = { ///< 15% Antenna power .channel = LEDC_CHANNEL_1, .duty = 0, .gpio_num = CONFIG_ANTENNA_15_PIN, ///< Antenna pin 15% .speed_mode = LEDC_LOW_SPEED_MODE, .hpoint = 0, .intr_type = LEDC_INTR_DISABLE, .timer_sel = LEDC_TIMER_0 ///< Timer 0 }; extern bool System_TimeOk; #define LED1 CONFIG_LED1_PIN #define LED2 CONFIG_LED2_PIN const int TASK_DCF_REQUEST_START = BIT0; const int TASK_DCF_REQUEST_STOP = BIT1; const int TASK_DCF_RUN = BIT2; bool ready_DCF(void) { return dcf_state->DCF_running; } void request_DCF(bool run) { ESP_LOGI(TAG, "request_DCF(%s)", run ? "start":"stop"); if (run) xEventGroupSetBits(xEventGroupDCF, TASK_DCF_REQUEST_START); else xEventGroupSetBits(xEventGroupDCF, TASK_DCF_REQUEST_STOP); } int bin2bcd(int data) { int msb, lsb; if (data < 10) return data; msb = (data / 10) << 4; lsb = data % 10; return msb + lsb; } static void DCFout(void* arg); void DCFout(void* arg) { int i; static int tmp, tmpin, parity = 0; switch (impulseCount++) { case 0: if (actualSecond == 0) { time(&dcf_now); dcf_now += 60; } /* Carrier to 15% */ ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 512); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1); if (impulseArray[actualSecond] == 1) { gpio_set_level(CONFIG_LED1_PIN, 1); } else if (impulseArray[actualSecond] == 2) { gpio_set_level(CONFIG_LED2_PIN, 1); } break; case 1: if (impulseArray[actualSecond] == 1) { /* Carrier back to 100% */ ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 512); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1); gpio_set_level(CONFIG_LED1_PIN, 0); } break; case 2: /* Carrier back to 100% */ ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 512); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1); gpio_set_level(CONFIG_LED1_PIN, 0); gpio_set_level(CONFIG_LED2_PIN, 0); break; case 9: impulseCount = 0; /* * To spread the CPU load, we set all bits during the first seconds * because we don't use these bits. */ switch (actualSecond) { case 0: /* * Bit 0 is always 0. * Bits 1..14 are used to transmit weather information. * Just some fixed values here. * Bit 15, Antenna bit. 0 = normal operation, 1 = fault */ for (i = 0; i < 16; i++) impulseArray[i] = 1; break; case 1: localtime_r(&dcf_now, &dcf_tm); char strftime_buf[64]; strftime(strftime_buf, sizeof(strftime_buf), "%c", &dcf_tm); ESP_LOGI(TAG, "The current date/time to send is: %s", strftime_buf); break; case 2: /* DST bits */ if (dcf_tm.tm_isdst == 0) { impulseArray[17] = 1; /* Set when DST is in effect. */ impulseArray[18] = 2; /* Set when DST is not in effect. */ } else { impulseArray[17] = 2; impulseArray[18] = 1; } /* Start of encoded time. Always set */ impulseArray[20] = 2; break; case 3: /* announce DST on-off bit 16 */ int month = dcf_tm.tm_mon + 1; bool announce = false; if (dcf_tm.tm_mday >= 25 || dcf_tm.tm_wday == 0) { /* Last sunday in the month */ if (month == 3) { if (dcf_tm.tm_isdst == 0 && dcf_tm.tm_hour == 1 && dcf_tm.tm_min != 0) { announce = true; /* Wintertime to summertime */ } } else if (month == 10) { if (dcf_tm.tm_isdst > 0 && dcf_tm.tm_hour == 1 && dcf_tm.tm_min != 0) { announce = true; /* Summertime to wintertime */ } } } ESP_LOGI(TAG, "%d announce TZ change %s", dcf_tm.tm_isdst, announce ? "true":"false"); impulseArray[16] = (announce) ? 2:1; break; case 4: /* * We don't announce the leap second. It is not always sure when this will * happen, possible at end of 2023, but it is not sure. And the next? * SNTP timesync will deal with this and we will see a timejump. */ break; case 5: tmpin = bin2bcd(dcf_tm.tm_min); parity = 0; for (i = 21; i < 28; i++) { tmp = tmpin & 1; impulseArray[i] = tmp + 1; parity += tmp; tmpin >>= 1; } impulseArray[28] = (parity & 1) ? 2:1; ESP_LOGI(TAG, "minute %d%d%d%d%d%d%d P1 %d", impulseArray[21], impulseArray[22], impulseArray[23], impulseArray[24], impulseArray[25], impulseArray[26], impulseArray[27], impulseArray[28]); break; case 6: tmpin = bin2bcd(dcf_tm.tm_hour); parity = 0; for (i = 29; i < 35; i++) { tmp = tmpin & 1; impulseArray[i] = tmp + 1; parity += tmp; tmpin >>= 1; } impulseArray[35] = (parity & 1) ? 2:1; ESP_LOGI(TAG, "hour %d%d%d%d%d%d P2 %d", impulseArray[29], impulseArray[30], impulseArray[31], impulseArray[32], impulseArray[33], impulseArray[34], impulseArray[35]); break; case 7: tmpin = bin2bcd(dcf_tm.tm_mday); parity = 0; for (i = 36; i < 42; i++) { tmp = tmpin & 1; impulseArray[i] = tmp + 1; parity += tmp; tmpin >>= 1; } ESP_LOGI(TAG, "mday %d%d%d%d%d%d", impulseArray[36], impulseArray[37], impulseArray[38], impulseArray[39], impulseArray[40], impulseArray[41]); break; case 8: tmpin = bin2bcd(dcf_tm.tm_wday); if (tmpin == 0) tmpin = 7; for (i = 42; i < 45; i++) { tmp = tmpin & 1; impulseArray[i] = tmp + 1; parity += tmp; tmpin >>= 1; } ESP_LOGI(TAG, "wday %d%d%d", impulseArray[42], impulseArray[43], impulseArray[44]); break; case 9: tmpin = bin2bcd(dcf_tm.tm_mon + 1); for (i = 45; i < 50; i++) { tmp = tmpin & 1; impulseArray[i] = tmp + 1; parity += tmp; tmpin >>= 1; } ESP_LOGI(TAG, "month %d%d%d%d%d", impulseArray[45], impulseArray[46], impulseArray[47], impulseArray[48], impulseArray[49]); break; case 10: tmpin = bin2bcd(dcf_tm.tm_year - 100); for (int i = 50; i < 58; i++) { tmp = tmpin & 1; impulseArray[i] = tmp + 1; parity += tmp; tmpin >>= 1; } impulseArray[58] = (parity & 1) ? 2:1; ESP_LOGI(TAG, "year %d%d%d%d%d%d%d%d P3 %d", impulseArray[50], impulseArray[51], impulseArray[52], impulseArray[53], impulseArray[54], impulseArray[55], impulseArray[56], impulseArray[57], impulseArray[58]); break; } if (actualSecond < 59) /* Can include leap second */ actualSecond++; break; } if (actualSecond >= 59) { time_t now = time(NULL); localtime_r(&now, &dcf_tm); if (dcf_tm.tm_sec == 0) { actualSecond = impulseCount = 0; } } } void task_DCF(void *pvParameters) { ESP_LOGI(TAG, "Starting DCF77"); xEventGroupDCF = xEventGroupCreate(); xSemaphoreDCF = xSemaphoreCreateMutex(); dcf_state = malloc(sizeof(DCF_State)); memset(dcf_state, 0x00, sizeof(DCF_State)); gpio_reset_pin(LED1); gpio_reset_pin(LED2); gpio_set_direction(LED1, GPIO_MODE_OUTPUT); gpio_set_direction(LED2, GPIO_MODE_OUTPUT); esp_timer_create_args_t timerDCF = { .callback = &DCFout, .name = "DCF timer" }; ESP_ERROR_CHECK(esp_timer_create(&timerDCF, &timerHandle)); /* * Prepare the LEDC PWM channels */ ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); ESP_ERROR_CHECK(ledc_channel_config(&dcf77_100tx)); ESP_ERROR_CHECK(ledc_channel_config(&dcf77_15tx)); ESP_LOGI(TAG, "DCF77 antennas at pins %d and %d", CONFIG_ANTENNA_100_PIN, CONFIG_ANTENNA_15_PIN); ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0); ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0); ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1); for (int i = 0; i < 59; i++) impulseArray[i] = 1; impulseArray[59] = impulseArray[60] = 0; xEventGroupClearBits(xEventGroupDCF, TASK_DCF_RUN); EventBits_t uxBits; for (;;) { uxBits = xEventGroupWaitBits(xEventGroupDCF, TASK_DCF_REQUEST_START | TASK_DCF_REQUEST_STOP, pdFALSE, pdFALSE, portMAX_DELAY ); if (uxBits & TASK_DCF_REQUEST_START) { if (dcf_state->DCF_running) { /* Already running */ } else { actualSecond = 0; impulseCount = 0; esp_timer_start_periodic(timerHandle, 100000); dcf_state->DCF_running = true; } xEventGroupClearBits(xEventGroupDCF, TASK_DCF_REQUEST_START); } else if (uxBits & TASK_DCF_REQUEST_STOP) { esp_timer_stop(timerHandle); } } /* for(;;) */ }