main/task_dcf.c

Fri, 20 Oct 2023 20:29:52 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Fri, 20 Oct 2023 20:29:52 +0200
changeset 2
053649608c09
parent 1
86b275481021
child 3
849ca14d4a2f
permissions
-rw-r--r--

Begin coding transmit bits.

/**
 * @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.
								///
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, tmp, parity;

    switch (impulseCount++) {
	case 0:		if (actualSecond == 0) {
			    time(&dcf_now);
			    dcf_now += 60;
			}
			if (impulseArray[actualSecond] != 0) {
			    gpio_set_level(CONFIG_LED1_PIN, 1);
			}
			break;
	case 1:		if (impulseArray[actualSecond] == 1) {
			    gpio_set_level(CONFIG_LED1_PIN, 0);
			}
			break;
	case 2:		gpio_set_level(CONFIG_LED1_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:	/* the first 20 bits of each minute at a logical zero value */
				    	for (i = 0; i < 20; 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;
					    impulseArray[18] = 2;
					} else {
					    impulseArray[17] = 2;
					    impulseArray[18] = 1;
					}
					/* bit 20 must be 1 to indicate active time */
					impulseArray[20] = 2;
					break;
			    case 3:	int minute = bin2bcd(dcf_tm.tm_min);
					parity = 0;
					for (i = 21; i < 28; i++) {
					    tmp = minute & 1;
					    impulseArray[i] = tmp + 1;
					    parity += tmp;
					    minute >>= 1;
					}
					impulseArray[28] = (parity & 1) ? 2:1;
					ESP_LOGI(TAG, "minute %d%d%d%d%d%d%d %d", impulseArray[21], impulseArray[22], impulseArray[23],
							impulseArray[24], impulseArray[25], impulseArray[26], impulseArray[27], impulseArray[28]);
					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_timer_create(&timerDCF, &timerHandle);

    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(;;) */
}

mercurial