diff --git a/Project/applications/smartcities/include/ntp.h b/Project/applications/smartcities/include/ntp.h index 4b4ed1a..afd73cc 100644 --- a/Project/applications/smartcities/include/ntp.h +++ b/Project/applications/smartcities/include/ntp.h @@ -8,19 +8,6 @@ #include "lwip/sys.h" #include "lwip/api.h" #include "ch.h" -#include -#include -#include -#include -#include -#include -#include - - -#define NTP_PACKET_LENGTH 48 -#define NTP_SERVER "81.184.154.182" -//const uint16_t remotePort = 123; - typedef struct { int second; @@ -31,24 +18,54 @@ typedef struct { int year; }Date; +unsigned long getSecsSince1900(void); +Date getDate(unsigned long); +void udpNtp_test(void); + #define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400))) -//const unsigned long seventyYears = 2208988800UL; -//const int timeZone = 2; //Time offset from GMT -//unsigned long daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -void udpNTP_Setup(void); -unsigned long getSecsSince1900(void); -Date getDate(void); +#define NTP_PACKET_LENGTH 48 -void udpNtp_test(void); +//cabecera de netconn api +#ifndef SNTP_PORT +#define SNTP_PORT 123 +#endif + +/** SNTP server address as IPv4 address in "u32_t" format */ +#ifndef SNTP_SERVER_ADDRESS +#define SNTP_SERVER_ADDRESS ipaddr_addr("81.184.154.182") /* your ntp server */ +#endif + +/** SNTP receive timeout - in milliseconds */ +#ifndef SNTP_RECV_TIMEOUT +#define SNTP_RECV_TIMEOUT 3000 +#endif + +/** SNTP update delay - in milliseconds */ +#ifndef SNTP_UPDATE_DELAY +#define SNTP_UPDATE_DELAY 60000 +#endif + +/** SNTP macro to change system time and/or the update the RTC clock */ +#ifndef SNTP_SYSTEM_TIME +#define SNTP_SYSTEM_TIME(t) +#endif + +/* SNTP protocol defines */ +#define SNTP_MAX_DATA_LEN 48 +#define SNTP_RCV_TIME_OFS 32 +#define SNTP_LI_NO_WARNING 0x00 +#define SNTP_VERSION (4/* NTP Version 4*/<<3) +#define SNTP_MODE_CLIENT 0x03 +#define SNTP_MODE_SERVER 0x04 +#define SNTP_MODE_BROADCAST 0x05 +#define SNTP_MODE_MASK 0x07 + +/* number of seconds between 1900 and 1970 */ +#define DIFF_SEC_1900_1970 (2208988800) -void udpNtp_init(void); -void udpNtp_send(void); -void udpNtp_dataReceivedCb(void * arg, struct udp_pcb * upcb,struct pbuf * firstPbuf,struct ip_addr * addr, u16_t port); -uint32_t udpNtp_setupConnection(void); -uint32_t udpNtp_setupConnectionL(void); -uint32_t read32(char* buffer, int offset); -char* timestamp_data(char* value,Date time); +/*timezone from GMT*/ +#define TIME_ZONE 2 #endif diff --git a/Project/applications/smartcities/ntp.c b/Project/applications/smartcities/ntp.c index bab8240..9819c15 100644 --- a/Project/applications/smartcities/ntp.c +++ b/Project/applications/smartcities/ntp.c @@ -1,244 +1,24 @@ -#include "ntp.h" - -#define DBG(fmt,...) if(1){printf("[NTP] "fmt"\r\n", ##__VA_ARGS__);}else{({});} -#define DBG_WARNING(fmt,...) if(1){printf("[NTP_WARNING] "fmt"\r\n", ##__VA_ARGS__);}else{({});} - -//define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400))) -//const unsigned long seventyYears = 2208988800UL; -//const int timeZone = 2; //Time offset from GMT -//unsigned long daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -unsigned long secsSince1900=0; -int flag=0; - -struct udp_pcb* udpConnectionHandler= NULL; -uint8_t udpNtpOnline = 0; - - -/*---------------------------------------------------------------------------------------------------------------------------------------- -INITIALIZATION/PROCESSING FUNCTIONS ------------------------------------------------------------------------------------------------------------------------------------------*/ -void udpNtp_init(){ - udpConnectionHandler= NULL; - udpNtpOnline = 0; - secsSince1900=0; - flag=0; -} - -/* -* Check if the connection handler has been initialized, -* and if so send a new message -*/ -void udpNtp_process(){ - while(udpNtpOnline==0){ - DBG("TX abandonned! [Not connected]\r\n"); - chThdSleepMilliseconds(500); - } - udpNtp_send(); -} - -/*---------------------------------------------------------------------------------------------------------------------------------------- -UDP TRANSMISSION HANDLING FUNCTIONS ------------------------------------------------------------------------------------------------------------------------------------------*/ -/* -* Sends a new message to the remote peer -*/ -void udpNtp_send(){ - uint16_t remotePort = 123; - char packetBuffer[NTP_PACKET_LENGTH]; - static uint32_t messageCount = 0; - memset (packetBuffer,0,NTP_PACKET_LENGTH); - packetBuffer[0] =0x1B;//0b11100011; // LI, Version, Mode - packetBuffer[1] = 0; // Stratum, or type of clock - packetBuffer[2] = 6; // Polling Interval - packetBuffer[3] = 0xEC; // Peer Clock Precision - // 8 bytes of zero for Root Delay & Root Dispersion - packetBuffer[12] = 49; - packetBuffer[13] = 0x4E; - packetBuffer[14] = 49; - packetBuffer[15] = 52; - struct pbuf *pbuffer; - ip_addr_t addr; - uint32_t ipaddr; - - err_t err; - - //Convert the IP address from string to lwip format - ipaddr = ipaddr_addr(NTP_SERVER); - ip4_addr_set_u32((&addr), ipaddr); - - /* - * Allocate a pbuf which we are going to fill with the transmitted data. - * We use libwismart_LwIP_lock() here because we are making a LWIP call - */ -libwismart_LwIP_lock(); - pbuffer = pbuf_alloc(PBUF_TRANSPORT, NTP_PACKET_LENGTH, PBUF_POOL); -libwismart_LwIP_unlock(); - if(pbuffer == NULL){ - DBG_WARNING("pbuf_alloc() FAILED!\r\n"); - return; - } - - /* - * Fill the payload of the pbuf with the message to be transmitted - * NOTE: Because pbuffer->payload has type (void*), we have to cast it (else we may have undefined behaviour) - */ - memcpy((uint8_t*)pbuffer->payload, packetBuffer, NTP_PACKET_LENGTH); - - /* - * Send the packet and release the allocated pbuf. - * We use libwismart_LwIP_lock() here because we are making a LWIP call - */ - libwismart_LwIP_lock(); - err = udp_sendto(udpConnectionHandler, pbuffer, &addr, remotePort); - libwismart_LwIP_unlock(); - - /* - * Release the allocated pbuf - * We use libwismart_LwIP_lock() here because we are making a LWIP call - */ - libwismart_LwIP_lock(); - pbuf_free(pbuffer); - libwismart_LwIP_unlock(); - - if(err != ERR_OK){ - DBG_WARNING("udp_sendto() FAILED!"); - return; - } - - DBG("Message #%u sent!",messageCount++); -} - -/*---------------------------------------------------------------------------------------------------------------------------------------- -UDP RECEPTION HANDLING FUNCTIONS ------------------------------------------------------------------------------------------------------------------------------------------*/ -void udpNtp_dataReceivedCb(void * arg, struct udp_pcb * upcb,struct pbuf * firstPbuf,struct ip_addr * addr, u16_t port){ - unsigned char *payload; - unsigned int payloadLen; - struct pbuf *currentPbuf; - - currentPbuf = firstPbuf; - while(currentPbuf != NULL){ - - /* - * It is important to cast the pbufNow->payload because its type is (void*) - */ - payload = (unsigned char *)currentPbuf->payload; - payloadLen = currentPbuf->len; - - DBG("New message [%u bytes] received!\r\n", payloadLen); - - currentPbuf = currentPbuf->next; - }; - - uint32_t temp=read32(payload, 40); - secsSince1900=(unsigned long) temp; - flag=1; - - /* - * Free the pbuf list. - */ - pbuf_free(firstPbuf); - -} - -/*---------------------------------------------------------------------------------------------------------------------------------------- -UDP CONNECTION SETUP FUNCTIONS ------------------------------------------------------------------------------------------------------------------------------------------*/ -/* -* Setups a new udp connection handler -*/ -uint32_t udpNtp_setupConnection(){ - uint32_t error; - -libwismart_LwIP_lock(); - error = udpNtp_setupConnectionL(); -libwismart_LwIP_unlock(); - - return error; -} - -/* -* Setups a new udp connection handler (Locked version of udpNTP_setupConnection) -*/ -uint32_t udpNtp_setupConnectionL(){ - uint16_t localPort = 5004; - err_t err; - - /* - * Create a new udp connection handler - */ - udpConnectionHandler = udp_new(); - if(udpConnectionHandler == NULL){ - DBG_WARNING("udp_new() FAILED!\r\n"); - return 1; - } - - /* - * Bind the connection to a local port. By giving 0 - * as third argument(port), you can say to lwip to bind the connection - * to any available port of our system. - */ - err = udp_bind(udpConnectionHandler, IP_ADDR_ANY, localPort); - if(err != ERR_OK){ - DBG_WARNING("udp_bind() FAILED!\r\n"); - udp_remove(udpConnectionHandler); - return 2; - } - /* - * Set the callback function when udp data are received. - * Since we only transmit, we should set this to NULL(second argument). - * For demonstration reasons only we provide a callback function - * that will be called each time a packet is received at port 'localPort' - */ - udp_recv(udpConnectionHandler, udpNtp_dataReceivedCb, NULL); - - udpNtpOnline = 1; - - return 0; -} - -uint32_t read32(char* buffer, int offset) { - char b0 = buffer[offset]; - char b1 = buffer[offset+1]; - char b2 = buffer[offset+2]; - char b3 = buffer[offset+3]; - - // convert signed bytes to unsigned values - uint32_t i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0); - uint32_t i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1); - uint32_t i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2); - uint32_t i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3); - - uint32_t v = (i0 << 24) + (i1 << 16) + (i2 << 8) + i3; - return v; -} - -unsigned long getSecsSince1900(){ - while(flag==0){ - DBG("in function getSecsSince1900: waiting for NTP procces\n"); - chThdSleepMilliseconds(500); - } - return secsSince1900; -} - -Date getDate(){ - while(flag==0){ - DBG("in function getDate: waiting for NTP procces\n"); - chThdSleepMilliseconds(500); - } +#include +#include +#include +#include +#include +#include +#include +#include +#include "ntp.h" - const unsigned long seventyYears = 2208988800UL; - const int timeZone = 2; //Time offset from GMT +Date getDate(unsigned long secsSince1900){ unsigned long daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - unsigned long epoch = secsSince1900 - seventyYears; + unsigned long epoch = secsSince1900 - DIFF_SEC_1900_1970; int second = epoch % 60; epoch /= 60; int minute = epoch % 60; epoch /= 60; - int hour = ((epoch % 24) + timeZone) % 24; + int hour = ((epoch % 24) + TIME_ZONE) % 24; epoch /= 24; int year = 0; unsigned long days = 0; @@ -281,60 +61,126 @@ Date getDate(){ return date; } -void udpNTP_Setup(){ - DBG("start_init\r\n"); - udpNtp_init(); - - DBG("start_Setup_Connection\r\n"); - udpNtp_setupConnectionL(); - - DBG("start_Procces\r\n"); - udpNtp_process(); -} - -char* timestamp_data(char* value,Date time) +unsigned long getSecsSince1900 (void) { - uint8_t length = strlen(value) + strlen(",00/00/0000T00:00:00") + 1; - char str_day[3],str_month[3],str_year[5],str_hour[3],str_minute[3],str_second[3]; - char* data = chHeapAlloc(NULL,length*sizeof(char)); + unsigned char * sntp_request; + unsigned char * sntp_response; + struct ip_addr sntp_server_address; + time_t timestamp = 0; + + struct netconn * sendUDPNetConn; + struct netbuf * sendUDPNetBuf; + struct netbuf * receiveUDPNetBuf; + + u16_t dataLen; + err_t errLWIP; + + /* initialize SNTP server address */ + sntp_server_address.addr = SNTP_SERVER_ADDRESS; + + /* if we got a valid SNTP server address... */ + if (sntp_server_address.addr != 0) + { + /* create new socket */ + sendUDPNetConn = netconn_new( NETCONN_UDP ); + sendUDPNetBuf = netbuf_new(); + // Create data space for netbuf, if we can. + sntp_request = (unsigned char *) netbuf_alloc(sendUDPNetBuf, SNTP_MAX_DATA_LEN); + + if ((NULL != sendUDPNetConn) && (NULL != sendUDPNetBuf) && (NULL != sntp_request)) + { + errLWIP = netconn_connect(sendUDPNetConn, &sntp_server_address, SNTP_PORT); + if (ERR_OK == errLWIP) + { + /* prepare SNTP request */ + memset(sntp_request, 0, SNTP_MAX_DATA_LEN); + sntp_request[0] = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT; + + errLWIP = netconn_send(sendUDPNetConn, sendUDPNetBuf); + // Send SNTP request to server. + if (ERR_OK == errLWIP) + { + // Set recv timeout. + sendUDPNetConn->recv_timeout = SNTP_RECV_TIMEOUT; + // Receive SNTP server response. + //receiveUDPNetBuf = netconn_recv(sendUDPNetConn); + errLWIP=netconn_recv(sendUDPNetConn, &receiveUDPNetBuf); + + + //if (NULL != receiveUDPNetBuf) + if(errLWIP==ERR_OK) + { + // Get pointer to response data. + netbuf_data(receiveUDPNetBuf, (void **) &sntp_response, (u16_t *) &dataLen); + + + // If the response size is good. + if (dataLen == SNTP_MAX_DATA_LEN) + { + // If this is a SNTP response... + if (((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || ((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST)) + { + /* extract GMT time from response */ + memcpy(×tamp, (sntp_response + SNTP_RCV_TIME_OFS), sizeof(timestamp)); + //timestamp = (ntohl(timestamp) - DIFF_SEC_1900_1970); + timestamp=(ntohl(timestamp)); + + printf("Received timestamp %u\r\n", timestamp); + } + else + { + printf("Received data did not match frame code\r\n"); + } + } + else + { + printf("Length of data did not match SNTP_MAX_DATA_LEN, received len %u\r\n", dataLen); + } + // Deallocate space hold for netbuf structure. + netbuf_delete(receiveUDPNetBuf); + } + else + { + //printf("Netconn receive failed with %d\r\n", netconn_err(sendUDPNetConn)); + printf("Netconn receive failed with %d\r\n", netconn_err(sendUDPNetConn)); + } + } // netconn_send(sendUDPNetConn, sendUDPNetBuf); + else + { + printf("Netconn sendto failed with %d\r\n", errLWIP); + } + } //netconn_connect(sendUDPNetConn, &sntp_server_address, SNTP_PORT); + else + { + printf("Netconn connect to server %X, port %u failed with %d\r\n", sntp_server_address.addr, SNTP_PORT, errLWIP); + } + } // if ((NULL != sendUDPNetConn) && (NULL != sendUDPNetBuf) && (NULL != sntp_request)) + else + { + printf("Netconn or netbuf or data allocation failed.\r\n"); + } - sprintf(str_day,"%d",time.day); - sprintf(str_month,"%d",time.month); - sprintf(str_year,"%d",time.year); - sprintf(str_hour,"%d",time.hour); - sprintf(str_minute,"%d",time.minute); - sprintf(str_second,"%d",time.second); + // Deallocate space hold for netconn and netbuf structure. + netbuf_delete(sendUDPNetBuf); + netconn_delete(sendUDPNetConn); + } //if (sntp_server_address != 0) + else + { + printf("Invalid NTP server address %X\r\n", SNTP_SERVER_ADDRESS); + } - strcpy(data,value); - strcat(data,","); - strcat(data, str_day); - strcat(data,"/"); - strcat(data, str_month); - strcat(data,"/"); - strcat(data, str_year); - strcat(data,"T"); - strcat(data, str_hour); - strcat(data,":"); - strcat(data, str_minute); - strcat(data,":"); - strcat(data, str_second); - data[length-1] = '\0'; - return data; + return (unsigned long) timestamp; } +/*Funcion para testeo del resto de funciones relacionadas con NTP. + -) getSecsSince1900() solo devuelve los segundos desde 1900, esta función abre y cierra los sockets de forma que puede ser llamada de forma continuada + -) a getDate() se le deve pasar el resultado de la función anterior +*/ +void udpNtp_test(){ -/*Funcion para testeo del resto de funciones relacionadas con NTP. En el main() el orden de ejecución debe ser el siguiente. -1ro: udpNTP_Setup -2do: getSecsSince1900() o getDate() -si se quiere actualizar la fecha actual, debemos llamar primeramente a UdpNTP_Setup.*/ -/*void udpNtp_test(){ - - udpNTP_Setup(); - //unsigned long var1=getSecsSince1900(); - Date var2=getDate(); - - //DBG("seconds since 1900: %lu\r\n", var1); + libwismart_EnableBsdSocketAPI(); + Date var2=getDate(getSecsSince1900()); - DBG("Hora:%i:%i:%i\r\n", var2.hour, var2.minute, var2.second); - DBG("Fecha:%i|%i|%i\r\n", var2.day,var2.month,var2.year); -}*/ \ No newline at end of file + printf("Hora:%i:%i:%i\r\n", var2.hour, var2.minute, var2.second); + printf("Fecha:%i|%i|%i\r\n", var2.day,var2.month,var2.year); +} \ No newline at end of file