He escrito la siguiente función para calcular la marca de tiempo actual (desde las 00 h del 1 de enero de 1900). La salida que obtengo es:
Current Time & Date : 20:5:32 25/7/2014<\r>
2014 7 25 20 5 32<\r>
retval 1 3597523200<\r>
retval 2 3597523200<\r>
retval 3 3613161600<\r>
retval 4 3615235200<\r>
retval 5 3615241664<\r>
retval 6 3615241964<\r>
retval 7 3615241996<\r>
retval 8 3615241996<\r>
Current time timestamp 3615241996
Básicamente estoy imprimiendo el retval (valor de retorno de la función) en cada paso para comprobar y verificar los cálculos.
El cálculo coincide hasta retval 4
(cuando las horas del día actual se convierten en segundos). Creo que podría deberse a un desbordamiento aritmético, pero no estoy seguro.
El problema parece estar sucediendo en esta línea:
retval += (d.hr * 60 * 60); printf("retval 5 %"PRIu32"\r", retval);
retval es uint32_t y d.hr es uint16_t
uint32_t DS1307_GET_CURRENT_TIMESTAMP()
{
uint32_t retval = SECONDS_SINCE_1900_TO_2014;
ds1307 d;
DS1307_GET_DATETIME(&d);
printf("%u %u %u %u %u %u\r", d.yy,d.mm,d.dd,d.hr, d.min, d.sec);
printf("retval 1 %"PRIu32"\r", retval);
//process complete years since 2014 to current year
uint8_t i=0;
for(i=0; i<(d.yy - 2014); i++)
{
if(DS1307_IS_LEAP_YEAR(2014+i)==0) retval += 31622400;
else retval += 31536000;
}
printf("retval 2 %"PRIu32"\r", retval);
//process complete months from beginning of current year to current date/time
for(i=1; i<d.mm; i++)
{
if((i==1) || (i==3) || (i==5) || (i==7) || (i==8) || (i==10) || (i==12))
{
//31 days
retval += (31 * 86400);
}
else if ((i==4) || (i==6) || (i==9) || (i==11))
{
//30 days
retval += (30 * 86400);
}
else
{
//i==2==february. check if leap year
if(DS1307_IS_LEAP_YEAR(d.yy)==0) retval += (29 * 86400);
else retval += (28 * 86400);
}
}
printf("retval 3 %"PRIu32"\r", retval);
//process complete days from beginning of month till current date
retval += ((d.dd-1) * 86400);
printf("retval 4 %"PRIu32"\r", retval);
//process hours, min and seconds - CALCULATION DEVIATES HERE.
retval += (d.hr * 60 * 60); printf("retval 5 %"PRIu32"\r", retval);
retval += (d.min * 60); printf("retval 6 %"PRIu32"\r", retval);
retval += d.sec; printf("retval 7 %"PRIu32"\r", retval);
printf("retval 8 %"PRIu32"\r", retval);
return retval;
}
20 * 60 * 60 = 72000
Debe realizar la multiplicación en 32 bits para evitar un desbordamiento.
retval += (d.hr * 60UL * 60);
(3615235200-3613161600)/(24*60*60) = 24, por lo que el cambio en 'retval 4' es correcto y no un desbordamiento, por lo que su afirmación de que son correctos "hasta que llegue a retval 4" es falsa.
retval 5 sin embargo da (3615241664-3615235200) = 60*60*20 - 2**16, por lo que hay un desbordamiento. Use un uint32_t en el lado derecho de retval += d.hr * uint32_t(60 * 60u)
.
Antes de su edición, le faltaba un espacio entre "retval 3" y "3613161600" .
Ankit
Ignacio Vázquez-Abrams
int
a menos que uno de los operandos lo anule, de ahí elL
sufijo en el literal (paralong
).Ignacio Vázquez-Abrams