11 |
11 |
12 |
12 |
13 SemaphoreHandle_t xSemaphoreDCF = NULL; ///< Semaphore DCF task. |
13 SemaphoreHandle_t xSemaphoreDCF = NULL; ///< Semaphore DCF task. |
14 EventGroupHandle_t xEventGroupDCF; ///< Events DCF task. |
14 EventGroupHandle_t xEventGroupDCF; ///< Events DCF task. |
15 DCF_State *dcf_state = NULL; ///< Public state for other tasks. |
15 DCF_State *dcf_state = NULL; ///< Public state for other tasks. |
|
16 esp_timer_handle_t timerHandle; ///< Timer handler |
|
17 int impulseCount = 0; ///< 100 mSec transmit slices. |
|
18 int8_t impulseArray[61]; ///< Pulses, 0 = no pulse, 1=100ms, 2=200ms |
|
19 int actualSecond = 0; ///< Current second to transmit. |
|
20 time_t dcf_now; ///< Current time to send. |
|
21 struct tm dcf_tm; ///< Local broken down time. |
|
22 /// |
|
23 extern bool System_TimeOk; |
|
24 |
16 |
25 |
17 #define LED1 CONFIG_LED1_PIN |
26 #define LED1 CONFIG_LED1_PIN |
18 #define LED2 CONFIG_LED2_PIN |
27 #define LED2 CONFIG_LED2_PIN |
19 |
28 |
20 |
29 |
31 |
40 |
32 |
41 |
33 |
42 |
34 void request_DCF(bool run) |
43 void request_DCF(bool run) |
35 { |
44 { |
|
45 ESP_LOGI(TAG, "request_DCF(%s)", run ? "start":"stop"); |
|
46 |
|
47 if (run) |
|
48 xEventGroupSetBits(xEventGroupDCF, TASK_DCF_REQUEST_START); |
|
49 else |
|
50 xEventGroupSetBits(xEventGroupDCF, TASK_DCF_REQUEST_STOP); |
|
51 } |
|
52 |
|
53 |
|
54 int bin2bcd(int data) |
|
55 { |
|
56 int msb, lsb; |
|
57 |
|
58 if (data < 10) |
|
59 return data; |
|
60 msb = (data / 10) << 4; |
|
61 lsb = data % 10; |
|
62 return msb + lsb; |
|
63 } |
|
64 |
|
65 |
|
66 static void DCFout(void* arg); |
|
67 void DCFout(void* arg) |
|
68 { |
|
69 int i, tmp, parity; |
|
70 |
|
71 switch (impulseCount++) { |
|
72 case 0: if (actualSecond == 0) { |
|
73 time(&dcf_now); |
|
74 dcf_now += 60; |
|
75 } |
|
76 if (impulseArray[actualSecond] != 0) { |
|
77 gpio_set_level(CONFIG_LED1_PIN, 1); |
|
78 } |
|
79 break; |
|
80 case 1: if (impulseArray[actualSecond] == 1) { |
|
81 gpio_set_level(CONFIG_LED1_PIN, 0); |
|
82 } |
|
83 break; |
|
84 case 2: gpio_set_level(CONFIG_LED1_PIN, 0); |
|
85 break; |
|
86 case 9: impulseCount = 0; |
|
87 /* |
|
88 * To spread the CPU load, we set all bits during the first seconds |
|
89 * because we don't use these bits. |
|
90 */ |
|
91 switch (actualSecond) { |
|
92 case 0: /* the first 20 bits of each minute at a logical zero value */ |
|
93 for (i = 0; i < 20; i++) |
|
94 impulseArray[i] = 1; |
|
95 break; |
|
96 case 1: localtime_r(&dcf_now, &dcf_tm); |
|
97 char strftime_buf[64]; |
|
98 strftime(strftime_buf, sizeof(strftime_buf), "%c", &dcf_tm); |
|
99 ESP_LOGI(TAG, "The current date/time to send is: %s", strftime_buf); |
|
100 break; |
|
101 case 2: /* DST bits */ |
|
102 if (dcf_tm.tm_isdst == 0) { |
|
103 impulseArray[17] = 1; |
|
104 impulseArray[18] = 2; |
|
105 } else { |
|
106 impulseArray[17] = 2; |
|
107 impulseArray[18] = 1; |
|
108 } |
|
109 /* bit 20 must be 1 to indicate active time */ |
|
110 impulseArray[20] = 2; |
|
111 break; |
|
112 case 3: int minute = bin2bcd(dcf_tm.tm_min); |
|
113 parity = 0; |
|
114 for (i = 21; i < 28; i++) { |
|
115 tmp = minute & 1; |
|
116 impulseArray[i] = tmp + 1; |
|
117 parity += tmp; |
|
118 minute >>= 1; |
|
119 } |
|
120 impulseArray[28] = (parity & 1) ? 2:1; |
|
121 ESP_LOGI(TAG, "minute %d%d%d%d%d%d%d %d", impulseArray[21], impulseArray[22], impulseArray[23], |
|
122 impulseArray[24], impulseArray[25], impulseArray[26], impulseArray[27], impulseArray[28]); |
|
123 break; |
|
124 |
|
125 |
|
126 } |
|
127 if (actualSecond < 59) /* Can include leap second */ |
|
128 actualSecond++; |
|
129 break; |
|
130 } |
|
131 |
|
132 if (actualSecond >= 59) { |
|
133 time_t now = time(NULL); |
|
134 localtime_r(&now, &dcf_tm); |
|
135 if (dcf_tm.tm_sec == 0) { |
|
136 actualSecond = impulseCount = 0; |
|
137 } |
|
138 } |
36 } |
139 } |
37 |
140 |
38 |
141 |
39 |
142 |
40 void task_DCF(void *pvParameters) |
143 void task_DCF(void *pvParameters) |
49 gpio_reset_pin(LED1); |
152 gpio_reset_pin(LED1); |
50 gpio_reset_pin(LED2); |
153 gpio_reset_pin(LED2); |
51 gpio_set_direction(LED1, GPIO_MODE_OUTPUT); |
154 gpio_set_direction(LED1, GPIO_MODE_OUTPUT); |
52 gpio_set_direction(LED2, GPIO_MODE_OUTPUT); |
155 gpio_set_direction(LED2, GPIO_MODE_OUTPUT); |
53 |
156 |
|
157 esp_timer_create_args_t timerDCF = { |
|
158 .callback = &DCFout, |
|
159 .name = "DCF timer" |
|
160 }; |
|
161 esp_timer_create(&timerDCF, &timerHandle); |
|
162 |
|
163 for (int i = 0; i < 59; i++) |
|
164 impulseArray[i] = 1; |
|
165 impulseArray[59] = impulseArray[60] = 0; |
|
166 |
54 xEventGroupClearBits(xEventGroupDCF, TASK_DCF_RUN); |
167 xEventGroupClearBits(xEventGroupDCF, TASK_DCF_RUN); |
55 EventBits_t uxBits; |
168 EventBits_t uxBits; |
56 |
169 |
57 for (;;) { |
170 for (;;) { |
58 uxBits = xEventGroupWaitBits(xEventGroupDCF, TASK_DCF_REQUEST_START | TASK_DCF_REQUEST_STOP, pdFALSE, pdFALSE, portMAX_DELAY ); |
171 uxBits = xEventGroupWaitBits(xEventGroupDCF, TASK_DCF_REQUEST_START | TASK_DCF_REQUEST_STOP, pdFALSE, pdFALSE, portMAX_DELAY ); |
59 |
172 |
60 if (uxBits & TASK_DCF_REQUEST_START) { |
173 if (uxBits & TASK_DCF_REQUEST_START) { |
61 if (dcf_state->DCF_running) { |
174 if (dcf_state->DCF_running) { |
62 /* Already running */ |
175 /* Already running */ |
63 xEventGroupClearBits(xEventGroupDCF, TASK_DCF_REQUEST_START); |
176 } else { |
|
177 actualSecond = 0; |
|
178 impulseCount = 0; |
|
179 esp_timer_start_periodic(timerHandle, 100000); |
|
180 dcf_state->DCF_running = true; |
64 } |
181 } |
|
182 xEventGroupClearBits(xEventGroupDCF, TASK_DCF_REQUEST_START); |
65 |
183 |
66 } else if (uxBits & TASK_DCF_REQUEST_STOP) { |
184 } else if (uxBits & TASK_DCF_REQUEST_STOP) { |
67 |
185 esp_timer_stop(timerHandle); |
68 } |
186 } |
69 } /* for(;;) */ |
187 } /* for(;;) */ |
70 } |
188 } |
71 |
189 |
72 |
190 |