ntp.c 5.29 KB
#include "ntp.h"

Date getDate(unsigned long secsSince1900)
{
	unsigned long daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	unsigned long epoch = secsSince1900 - DIFF_SEC_1900_1970;

	int second = epoch % 60;
	epoch /= 60;
	int minute = epoch % 60;
	epoch /= 60;
	int hour = ((epoch % 24) + TIME_ZONE) % 24;
	epoch /= 24;
	int year = 0;
	unsigned long days = 0;

	while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= epoch)
	{
		year++;
	}
	days -= LEAP_YEAR(year) ? 366 : 365;
	epoch -= days;

	int j=0;
	int cont=0;
	int aux=epoch;
	if(LEAP_YEAR(year))
	{
		daysPerMonth[1]=29;
	}

	while (daysPerMonth[j]<sizeof(daysPerMonth))
	{

		cont+=daysPerMonth[j];
		if(epoch<cont)
		{
			break;
		}
		aux-=daysPerMonth[j];
		j++;
	}

	int day=++aux;
	int month=++j;
	year+=1970;

	Date date;
	date.second=second;
	date.minute=minute;
	date.hour=hour;
	date.day=day;
	date.month=month;
	date.year=year;

	return date;
}

unsigned long getSecsSince1900 (void)
{
	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.
					errLWIP=netconn_recv(sendUDPNetConn, &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))
							{
								DBG_NTP("Successfully got new time\r\n");
								/* extract GMT time from response */
								memcpy(&timestamp, (sntp_response + SNTP_RCV_TIME_OFS), sizeof(timestamp));
								timestamp=(ntohl(timestamp));
								DBG_NTP("Received timestamp %ul\r\n", timestamp);
							}
							else
							{
								DBG_NTP("%c[1;31m[ERROR] Received data did not match frame code%c[1;00m\r\n",0x1B,0x1B);
							}
						}
						else
						{
							DBG_NTP("%c[1;31m[ERROR] Length of data did not match SNTP_MAX_DATA_LEN, received len %u%c[1;00m\r\n", 0x1B,dataLen,0x1B);
						}
						// Deallocate space hold for netbuf structure.
						netbuf_delete(receiveUDPNetBuf);
					}
					else
					{
						DBG_NTP("%c[1;31m[ERROR] Netconn receive failed with %d%c[1;00m\r\n", 0x1B,netconn_err(sendUDPNetConn),0x1B);
					}
				}
				else
				{
					DBG_NTP("%c[1;31m[ERROR] Netconn sendto failed with %d%c[1;00m\r\n", errLWIP,0x1B);
				}
			}
			else
			{
				DBG_NTP("%c[1;31m[ERROR] Netconn connect to server %X, port %u failed with %d%c[1;00m\r\n", 0x1B,sntp_server_address.addr, SNTP_PORT, errLWIP,0x1B);
			}
		}
		else
		{
			DBG_NTP("%c[1;31m[ERROR] Netconn or netbuf or data allocation failed.%c[1;00m\r\n",0x1B,0x1B);
		}
		// Deallocate space hold for netconn and netbuf structure.
		netbuf_delete(sendUDPNetBuf);
		netconn_delete(sendUDPNetConn);
	} //if (sntp_server_address != 0)
	else
	{
		DBG_NTP("%c[1;31m[ERROR] Invalid NTP server address %X%c[1;00m\r\n", 0x1B,SNTP_SERVER_ADDRESS,0x1B);
	}

	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 debe pasar el resultado de la función anterior
*/

char* timestamp_data(char* value,Date time)
{
	DBG_NTP("Writing timestamp...\r\n");
	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));
	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);

	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;
}