Commit 0cfa56b6debb5b8c4bbc862cedbcbe7a064455d8
1 parent
041e3945
--no commit message
Showing
2 changed files
with
365 additions
and
0 deletions
Project/applications/smartcities/include/ntp.h
0 → 100644
1 | +#ifndef NTP_H | ||
2 | +#define NTP_H | ||
3 | + | ||
4 | +#include "libwismart.h" | ||
5 | +#include "lwip/opt.h" | ||
6 | +#include "lwip/tcp.h" | ||
7 | +#include "lwip/udp.h" | ||
8 | +#include "lwip/sys.h" | ||
9 | +#include "lwip/api.h" | ||
10 | +#include "ch.h" | ||
11 | + | ||
12 | +#define NTP_PACKET_LENGTH 48 | ||
13 | +//char* remoteIpString ="81.184.154.182"; | ||
14 | +//const uint16_t remotePort = 123; | ||
15 | + | ||
16 | + | ||
17 | +typedef struct { | ||
18 | + int second; | ||
19 | + int minute; | ||
20 | + int hour; | ||
21 | + int day; | ||
22 | + int month; | ||
23 | + int year; | ||
24 | +}Date; | ||
25 | + | ||
26 | +#define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400))) | ||
27 | +//const unsigned long seventyYears = 2208988800UL; | ||
28 | +//const int timeZone = 2; //Time offset from GMT | ||
29 | +//unsigned long daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
30 | + | ||
31 | +void udpNTP_Setup(void); | ||
32 | +unsigned long getSecsSince1900(void); | ||
33 | +Date getDate(void); | ||
34 | + | ||
35 | +void udpNtp_test(void); | ||
36 | + | ||
37 | +void udpNtp_init(void); | ||
38 | +void udpNtp_send(void); | ||
39 | +void udpNtp_dataReceivedCb(void * arg, struct udp_pcb * upcb,struct pbuf * firstPbuf,struct ip_addr * addr, u16_t port); | ||
40 | +uint32_t udpNtp_setupConnection(void); | ||
41 | +uint32_t udpNtp_setupConnectionL(void); | ||
42 | +uint32_t read32(char* buffer, int offset); | ||
43 | + | ||
44 | + | ||
45 | +#endif |
Project/applications/smartcities/ntp.c
0 → 100644
1 | +#include <stdio.h> | ||
2 | +#include <time.h> | ||
3 | +#include <string.h> | ||
4 | +#include <stdlib.h> | ||
5 | +#include <unistd.h> | ||
6 | +#include <errno.h> | ||
7 | +#include <math.h> | ||
8 | +#include <sys/time.h> | ||
9 | + | ||
10 | +#include "ntp.h" | ||
11 | + | ||
12 | +#define DBG(fmt,...) if(1){printf("[NTP] "fmt"\r\n", ##__VA_ARGS__);}else{({});} | ||
13 | +#define DBG_WARNING(fmt,...) if(1){printf("[NTP_WARNING] "fmt"\r\n", ##__VA_ARGS__);}else{({});} | ||
14 | + | ||
15 | +//define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400))) | ||
16 | +//const unsigned long seventyYears = 2208988800UL; | ||
17 | +//const int timeZone = 2; //Time offset from GMT | ||
18 | +//unsigned long daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
19 | +unsigned long secsSince1900=0; | ||
20 | +int flag=0; | ||
21 | + | ||
22 | +struct udp_pcb* udpConnectionHandler= NULL; | ||
23 | +uint8_t udpNtpOnline = 0; | ||
24 | + | ||
25 | + | ||
26 | +/*---------------------------------------------------------------------------------------------------------------------------------------- | ||
27 | +INITIALIZATION/PROCESSING FUNCTIONS | ||
28 | +-----------------------------------------------------------------------------------------------------------------------------------------*/ | ||
29 | +void udpNtp_init(){ | ||
30 | + udpConnectionHandler= NULL; | ||
31 | + udpNtpOnline = 0; | ||
32 | + secsSince1900=0; | ||
33 | + flag=0; | ||
34 | +} | ||
35 | + | ||
36 | +/* | ||
37 | +* Check if the connection handler has been initialized, | ||
38 | +* and if so send a new message | ||
39 | +*/ | ||
40 | +void udpNtp_process(){ | ||
41 | + while(udpNtpOnline==0){ | ||
42 | + DBG("TX abandonned! [Not connected]\r\n"); | ||
43 | + chThdSleepMilliseconds(500); | ||
44 | + } | ||
45 | + udpNtp_send(); | ||
46 | +} | ||
47 | + | ||
48 | +/*---------------------------------------------------------------------------------------------------------------------------------------- | ||
49 | +UDP TRANSMISSION HANDLING FUNCTIONS | ||
50 | +-----------------------------------------------------------------------------------------------------------------------------------------*/ | ||
51 | +/* | ||
52 | +* Sends a new message to the remote peer | ||
53 | +*/ | ||
54 | +void udpNtp_send(){ | ||
55 | + char* remoteIpString ="81.184.154.182";/*"192.168.43.83";"165.193.126.229";*/ | ||
56 | + uint16_t remotePort = 123; | ||
57 | + char packetBuffer[NTP_PACKET_LENGTH]; | ||
58 | + static uint32_t messageCount = 0; | ||
59 | + memset (packetBuffer,0,NTP_PACKET_LENGTH); | ||
60 | + packetBuffer[0] =0x1B;//0b11100011; // LI, Version, Mode | ||
61 | + packetBuffer[1] = 0; // Stratum, or type of clock | ||
62 | + packetBuffer[2] = 6; // Polling Interval | ||
63 | + packetBuffer[3] = 0xEC; // Peer Clock Precision | ||
64 | + // 8 bytes of zero for Root Delay & Root Dispersion | ||
65 | + packetBuffer[12] = 49; | ||
66 | + packetBuffer[13] = 0x4E; | ||
67 | + packetBuffer[14] = 49; | ||
68 | + packetBuffer[15] = 52; | ||
69 | + struct pbuf *pbuffer; | ||
70 | + ip_addr_t addr; | ||
71 | + uint32_t ipaddr; | ||
72 | + | ||
73 | + err_t err; | ||
74 | + | ||
75 | + //Convert the IP address from string to lwip format | ||
76 | + ipaddr = ipaddr_addr(remoteIpString); | ||
77 | + ip4_addr_set_u32((&addr), ipaddr); | ||
78 | + | ||
79 | + /* | ||
80 | + * Allocate a pbuf which we are going to fill with the transmitted data. | ||
81 | + * We use libwismart_LwIP_lock() here because we are making a LWIP call | ||
82 | + */ | ||
83 | +libwismart_LwIP_lock(); | ||
84 | + pbuffer = pbuf_alloc(PBUF_TRANSPORT, NTP_PACKET_LENGTH, PBUF_POOL); | ||
85 | +libwismart_LwIP_unlock(); | ||
86 | + if(pbuffer == NULL){ | ||
87 | + DBG_WARNING("pbuf_alloc() FAILED!\r\n"); | ||
88 | + return; | ||
89 | + } | ||
90 | + | ||
91 | + /* | ||
92 | + * Fill the payload of the pbuf with the message to be transmitted | ||
93 | + * NOTE: Because pbuffer->payload has type (void*), we have to cast it (else we may have undefined behaviour) | ||
94 | + */ | ||
95 | + memcpy((uint8_t*)pbuffer->payload, packetBuffer, NTP_PACKET_LENGTH); | ||
96 | + | ||
97 | + /* | ||
98 | + * Send the packet and release the allocated pbuf. | ||
99 | + * We use libwismart_LwIP_lock() here because we are making a LWIP call | ||
100 | + */ | ||
101 | + libwismart_LwIP_lock(); | ||
102 | + err = udp_sendto(udpConnectionHandler, pbuffer, &addr, remotePort); | ||
103 | + libwismart_LwIP_unlock(); | ||
104 | + | ||
105 | + /* | ||
106 | + * Release the allocated pbuf | ||
107 | + * We use libwismart_LwIP_lock() here because we are making a LWIP call | ||
108 | + */ | ||
109 | + libwismart_LwIP_lock(); | ||
110 | + pbuf_free(pbuffer); | ||
111 | + libwismart_LwIP_unlock(); | ||
112 | + | ||
113 | + if(err != ERR_OK){ | ||
114 | + DBG_WARNING("udp_sendto() FAILED!"); | ||
115 | + return; | ||
116 | + } | ||
117 | + | ||
118 | + DBG("Message #%u sent!",messageCount++); | ||
119 | +} | ||
120 | + | ||
121 | +/*---------------------------------------------------------------------------------------------------------------------------------------- | ||
122 | +UDP RECEPTION HANDLING FUNCTIONS | ||
123 | +-----------------------------------------------------------------------------------------------------------------------------------------*/ | ||
124 | +void udpNtp_dataReceivedCb(void * arg, struct udp_pcb * upcb,struct pbuf * firstPbuf,struct ip_addr * addr, u16_t port){ | ||
125 | + unsigned char *payload; | ||
126 | + unsigned int payloadLen; | ||
127 | + struct pbuf *currentPbuf; | ||
128 | + | ||
129 | + currentPbuf = firstPbuf; | ||
130 | + while(currentPbuf != NULL){ | ||
131 | + | ||
132 | + /* | ||
133 | + * It is important to cast the pbufNow->payload because its type is (void*) | ||
134 | + */ | ||
135 | + payload = (unsigned char *)currentPbuf->payload; | ||
136 | + payloadLen = currentPbuf->len; | ||
137 | + | ||
138 | + DBG("New message [%u bytes] received!\r\n", payloadLen); | ||
139 | + | ||
140 | + currentPbuf = currentPbuf->next; | ||
141 | + }; | ||
142 | + | ||
143 | + uint32_t temp=read32(payload, 40); | ||
144 | + secsSince1900=(unsigned long) temp; | ||
145 | + flag=1; | ||
146 | + | ||
147 | + /* | ||
148 | + * Free the pbuf list. | ||
149 | + */ | ||
150 | + pbuf_free(firstPbuf); | ||
151 | + | ||
152 | +} | ||
153 | + | ||
154 | +/*---------------------------------------------------------------------------------------------------------------------------------------- | ||
155 | +UDP CONNECTION SETUP FUNCTIONS | ||
156 | +-----------------------------------------------------------------------------------------------------------------------------------------*/ | ||
157 | +/* | ||
158 | +* Setups a new udp connection handler | ||
159 | +*/ | ||
160 | +uint32_t udpNtp_setupConnection(){ | ||
161 | + uint32_t error; | ||
162 | + | ||
163 | +libwismart_LwIP_lock(); | ||
164 | + error = udpNtp_setupConnectionL(); | ||
165 | +libwismart_LwIP_unlock(); | ||
166 | + | ||
167 | + return error; | ||
168 | +} | ||
169 | + | ||
170 | +/* | ||
171 | +* Setups a new udp connection handler (Locked version of udpNTP_setupConnection) | ||
172 | +*/ | ||
173 | +uint32_t udpNtp_setupConnectionL(){ | ||
174 | + uint16_t localPort = 5004; | ||
175 | + err_t err; | ||
176 | + | ||
177 | + /* | ||
178 | + * Create a new udp connection handler | ||
179 | + */ | ||
180 | + udpConnectionHandler = udp_new(); | ||
181 | + if(udpConnectionHandler == NULL){ | ||
182 | + DBG_WARNING("udp_new() FAILED!\r\n"); | ||
183 | + return 1; | ||
184 | + } | ||
185 | + | ||
186 | + /* | ||
187 | + * Bind the connection to a local port. By giving 0 | ||
188 | + * as third argument(port), you can say to lwip to bind the connection | ||
189 | + * to any available port of our system. | ||
190 | + */ | ||
191 | + err = udp_bind(udpConnectionHandler, IP_ADDR_ANY, localPort); | ||
192 | + if(err != ERR_OK){ | ||
193 | + DBG_WARNING("udp_bind() FAILED!\r\n"); | ||
194 | + udp_remove(udpConnectionHandler); | ||
195 | + return 2; | ||
196 | + } | ||
197 | + /* | ||
198 | + * Set the callback function when udp data are received. | ||
199 | + * Since we only transmit, we should set this to NULL(second argument). | ||
200 | + * For demonstration reasons only we provide a callback function | ||
201 | + * that will be called each time a packet is received at port 'localPort' | ||
202 | + */ | ||
203 | + udp_recv(udpConnectionHandler, udpNtp_dataReceivedCb, NULL); | ||
204 | + | ||
205 | + udpNtpOnline = 1; | ||
206 | + | ||
207 | + return 0; | ||
208 | +} | ||
209 | + | ||
210 | +uint32_t read32(char* buffer, int offset) { | ||
211 | + char b0 = buffer[offset]; | ||
212 | + char b1 = buffer[offset+1]; | ||
213 | + char b2 = buffer[offset+2]; | ||
214 | + char b3 = buffer[offset+3]; | ||
215 | + | ||
216 | + // convert signed bytes to unsigned values | ||
217 | + uint32_t i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0); | ||
218 | + uint32_t i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1); | ||
219 | + uint32_t i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2); | ||
220 | + uint32_t i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3); | ||
221 | + | ||
222 | + uint32_t v = (i0 << 24) + (i1 << 16) + (i2 << 8) + i3; | ||
223 | + return v; | ||
224 | +} | ||
225 | + | ||
226 | +unsigned long getSecsSince1900(){ | ||
227 | + while(flag==0){ | ||
228 | + DBG("in function getSecsSince1900: waiting for NTP procces\n"); | ||
229 | + chThdSleepMilliseconds(500); | ||
230 | + } | ||
231 | + return secsSince1900; | ||
232 | +} | ||
233 | + | ||
234 | +Date getDate(){ | ||
235 | + while(flag==0){ | ||
236 | + DBG("in function getDate: waiting for NTP procces\n"); | ||
237 | + chThdSleepMilliseconds(500); | ||
238 | + } | ||
239 | + | ||
240 | + | ||
241 | + const unsigned long seventyYears = 2208988800UL; | ||
242 | + const int timeZone = 2; //Time offset from GMT | ||
243 | + unsigned long daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
244 | + | ||
245 | + unsigned long epoch = secsSince1900 - seventyYears; | ||
246 | + | ||
247 | + int second = epoch % 60; | ||
248 | + epoch /= 60; | ||
249 | + int minute = epoch % 60; | ||
250 | + epoch /= 60; | ||
251 | + int hour = ((epoch % 24) + timeZone) % 24; | ||
252 | + epoch /= 24; | ||
253 | + int year = 0; | ||
254 | + unsigned long days = 0; | ||
255 | + | ||
256 | + while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= epoch){ | ||
257 | + year++; | ||
258 | + } | ||
259 | + days -= LEAP_YEAR(year) ? 366 : 365; | ||
260 | + epoch -= days; | ||
261 | + | ||
262 | + int j=0; | ||
263 | + int cont=0; | ||
264 | + int aux=epoch; | ||
265 | + if(LEAP_YEAR(year)){ | ||
266 | + daysPerMonth[1]=29; | ||
267 | + } | ||
268 | + | ||
269 | + while (daysPerMonth[j]<sizeof(daysPerMonth)){ | ||
270 | + | ||
271 | + cont+=daysPerMonth[j]; | ||
272 | + if(epoch<cont){ | ||
273 | + break; | ||
274 | + } | ||
275 | + aux-=daysPerMonth[j]; | ||
276 | + j++; | ||
277 | + } | ||
278 | + | ||
279 | + int day=++aux; | ||
280 | + int month=++j; | ||
281 | + year+=1970; | ||
282 | + | ||
283 | + Date date; | ||
284 | + date.second=second; | ||
285 | + date.minute=minute; | ||
286 | + date.hour=hour; | ||
287 | + date.day=day; | ||
288 | + date.month=month; | ||
289 | + date.year=year; | ||
290 | + | ||
291 | + return date; | ||
292 | +} | ||
293 | + | ||
294 | +void udpNTP_Setup(){ | ||
295 | + DBG("start_init\r\n"); | ||
296 | + udpNtp_init(); | ||
297 | + | ||
298 | + DBG("start_Setup_Connection\r\n"); | ||
299 | + udpNtp_setupConnectionL(); | ||
300 | + | ||
301 | + DBG("start_Procces\r\n"); | ||
302 | + udpNtp_process(); | ||
303 | +} | ||
304 | + | ||
305 | + | ||
306 | +/*Funcion para testeo del resto de funciones relacionadas con NTP. En el main() el orden de ejecución debe ser el siguiente. | ||
307 | +1ro: udpNTP_Setup | ||
308 | +2do: getSecsSince1900() o getDate() | ||
309 | +si se quiere actualizar la fecha actual, debemos llamar primeramente a UdpNTP_Setup.*/ | ||
310 | +/*void udpNtp_test(){ | ||
311 | + | ||
312 | + udpNTP_Setup(); | ||
313 | + //unsigned long var1=getSecsSince1900(); | ||
314 | + Date var2=getDate(); | ||
315 | + | ||
316 | + //DBG("seconds since 1900: %lu\r\n", var1); | ||
317 | + | ||
318 | + DBG("Hora:%i:%i:%i\r\n", var2.hour, var2.minute, var2.second); | ||
319 | + DBG("Fecha:%i|%i|%i\r\n", var2.day,var2.month,var2.year); | ||
320 | +}*/ | ||
0 | \ No newline at end of file | 321 | \ No newline at end of file |