#include "Time.h" #include "main.h" #include "i2c.h" #include "cmsis_os.h" #include "log_and_debug.h" #define TIMEOUT_RTC 2000 //struct sntp_msg sntp_msg; RealTimeClock_typeDef RealTimeClock = {0}; void vClockTask(void *param); uint8_t buff[8] = {0}; /*********************************************/ #define _XT_SIGNED #define _TBIAS_DAYS ((70 * (uint32_t)365) + 17) #define _TBIAS_SECS (_TBIAS_DAYS * (int32_t)86400) #define _TBIAS_YEAR 1900 #define MONTAB(year) ((((year) & 03) || ((year) == 0)) ? mos : lmos) const int16_t lmos[] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}; const int16_t mos[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; #define Daysto32(year, mon) (((year - 1) / 4) + MONTAB(year)[mon]) void clock_init(void) { xTaskCreate(vClockTask, "ClockTask", 1024, NULL, osPriorityNormal, NULL); // priority: above normal } int32_t time_to_unix(RealTimeClock_typeDef *t) // возвращает unixTime { int32_t days; int32_t secs; int32_t mon, year; mon = t->Data.Month - 1; year = t->Data.Year - _TBIAS_YEAR; days = Daysto32(year, mon) - 1; days += 365 * year; days += t->Data.Day; days -= _TBIAS_DAYS; secs = 3600 * t->Time.Hour; secs += 60 * t->Time.Min; secs += t->Time.Sec; secs += (days * (int32_t)86400); return (secs); } void unix_to_time(RealTimeClock_typeDef *t, int32_t secsarg) { uint32_t secs; int32_t days; int32_t mon; int32_t year; int32_t i; const int16_t* pm; #ifdef _XT_SIGNED if (secsarg >= 0) { secs = (uint32_t)secsarg; days = _TBIAS_DAYS; } else { secs = (uint32_t)secsarg + _TBIAS_SECS; days = 0; } #else secs = secsarg; days = _TBIAS_DAYS; #endif days += secs / 86400; secs = secs % 86400; t->Time.Hour = secs / 3600; secs %= 3600; t->Time.Min = secs / 60; t->Time.Sec = secs % 60; for (year = days / 365; days < (i = Daysto32(year, 0) + 365*year); ) { --year; } days -= i; t->Data.Year = year + _TBIAS_YEAR; pm = MONTAB(year); for (mon = 12; days < pm[--mon]; ); t->Data.Month = mon + 1; t->Data.Day= days - pm[mon] + 1; } uint8_t ErrBus_RTC(HAL_StatusTypeDef stat) { if(stat != HAL_OK){ if((stat == HAL_BUSY) && (hi2c1.Instance->SR2 & I2C_SR2_BUSY)){ // шина занята MX_I2C1_Init(); // шина занята, переинициализируем интерфейс } else if(hi2c1.Instance->SR1 & 0x1F00){ // ощибка шины по timeout hi2c1.Instance->CR1 &= ~I2C_CR1_PE; osDelay(1); hi2c1.Instance->CR1 |= I2C_CR1_PE; } return 0; } return 1; } uint8_t SetDisable_RTC(void) { buff[0] = 0x01; buff[1] = 0x80; if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 2, TIMEOUT_RTC))) return 0; // если была ошибка по передаче return 1; } uint8_t isEnable_RTC(void) { buff[0] = 0x01; if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 1, TIMEOUT_RTC))) return 0; // если была ошибка по передаче if(!ErrBus_RTC(HAL_I2C_Master_Receive(&hi2c1, M41T82_ADDR, buff, 1, TIMEOUT_RTC))) return 0; // если была ошибка по приему return (buff[0] & 0x80) ? 0: 1; } uint8_t SetEnable_RTC(void) { if(!isEnable_RTC()){ buff[0] = 0x01; buff[1] = 0x00; if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 2, TIMEOUT_RTC))) return 0; // если была ошибка по передаче } buff[0] = 0x08; // вычитываем регистр, что бы узнать включен ли бит FT if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 1, TIMEOUT_RTC))) return 0; // если была ошибка по передаче if(!ErrBus_RTC(HAL_I2C_Master_Receive(&hi2c1, M41T82_ADDR, buff, 1, TIMEOUT_RTC))) return 0; // если была ошибка по приему if(!(buff[0] & (1 << 6))){ buff[1] = buff[0] | (1 << 6); buff[0] = 0x08; /* включаем бит FT для измерения частоты */ if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 2, TIMEOUT_RTC))) return 0; // если была ошибка по передаче } return 1; } void ClearBitHT_RTC(void) { buff[0] = 0x0C; buff[1] = 0x00; ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 2, TIMEOUT_RTC)); // проверяем не было ли ошибок по шине } uint8_t SetCurrent_RTC(RealTimeClock_typeDef *ptrClock) { uint8_t Century = 0; Century = ((ptrClock->Data.Year - 2000) / 100); buff[0] = 0x01; buff[1] = (((ptrClock->Time.Sec / 10) << 4) | (ptrClock->Time.Sec % 10)) & 0x7F; buff[2] = (((ptrClock->Time.Min / 10) << 4) | (ptrClock->Time.Min % 10)) & 0x7F; buff[3] = ((((ptrClock->Time.Hour / 10) << 4) | (ptrClock->Time.Hour % 10)) & 0x3F) | (Century << 6); // + век if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 4, TIMEOUT_RTC))) return 0; // если была ошибка передачи buff[0] = 0x05; buff[1] = (((ptrClock->Data.Day / 10) << 4) | (ptrClock->Data.Day % 10)) & 0x3F; buff[2] = (((ptrClock->Data.Month / 10) << 4) | (ptrClock->Data.Month % 10)) & 0x1F; buff[3] = ((((ptrClock->Data.Year - 2000) - (Century * 100)) / 10) << 4) | (((ptrClock->Data.Year - 2000) - (Century * 100)) % 10); //(((ptrClock->Data.Year - Century * 1000) / 10) << 4) | ((ptrClock->Data.Year - Century * 1000) % 10); return ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 4, TIMEOUT_RTC)); } uint8_t GetCurrent_RTC(RealTimeClock_typeDef *ptrClock) // тут же прочитать флаги { if(ptrClock->Flags.OSC_FAIL){ // если при предыдущем чтении был установлен флаг buff[1] = buff[0] & ~0x04; buff[0] = 0x0F; if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 2, TIMEOUT_RTC))) return 0; // если была ошибка по передаче } buff[0] = 0x01; // читаем с регистра 0 if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 1, TIMEOUT_RTC))) return 0; // если была ошибка по передаче if(!ErrBus_RTC(HAL_I2C_Master_Receive(&hi2c1, M41T82_ADDR, buff, 7, TIMEOUT_RTC))) return 0; // если была ошибка по приему ptrClock->Time.Sec = (((buff[0] & 0x70) >> 4) * 10) + (buff[0] & 0x0F); ptrClock->Time.Min = (((buff[1] & 0x70) >> 4) * 10) + (buff[1] & 0x0F); ptrClock->Time.Hour = (((buff[2] & 0x30) >> 4) * 10) + (buff[2] & 0x0F); ptrClock->Data.Day = (((buff[4] & 0x30) >> 4) * 10) + (buff[4] & 0x0F); ptrClock->Data.Month = (((buff[5] & 0x10) >> 4) * 10) + (buff[5] & 0x0F); ptrClock->Data.Year = ((((buff[2] & 0xC0) >> 6) * 100) + 2000) + ((((buff[6] & 0xF0) >> 4) * 10) + (buff[6] & 0x0F)); buff[0] = 0x0F; if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 1, TIMEOUT_RTC))) return 0; // если была ошибка по передаче if(!ErrBus_RTC(HAL_I2C_Master_Receive(&hi2c1, M41T82_ADDR, buff, 1, TIMEOUT_RTC))) return 0; // если была ошибка по приему ptrClock->Flags.WDT = (buff[0] & 0x80) ? 1 : 0; ptrClock->Flags.ALR = ((buff[0] & 0x60) >> 5); ptrClock->Flags.BAT_LOW = (buff[0] & 0x10) ? 1 : 0; ptrClock->Flags.TMR = (buff[0] & 0x08) ? 1 : 0; ptrClock->Flags.OSC_FAIL = (buff[0] & 0x04) ? 1 : 0; return 1; } void SetCorrection_RTC(RealTimeClock_typeDef *ptrClock, int8_t corr) { buff[0] = 0x12; if(corr > 0) buff[1] = (corr | 0x80); else buff[1] = ~(corr); ptrClock->Correction = corr; if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 2, TIMEOUT_RTC))) return; } void GetCorrection_RTC(RealTimeClock_typeDef *ptrClock) { uint8_t correction; buff[0] = 0x12; if(!ErrBus_RTC(HAL_I2C_Master_Transmit(&hi2c1, M41T82_ADDR, buff, 1, TIMEOUT_RTC))) return; // если была ошибка по передаче if(!ErrBus_RTC(HAL_I2C_Master_Receive(&hi2c1, M41T82_ADDR, &correction, 1, TIMEOUT_RTC))) return; // если была ошибка по приему if(correction & 0x80) correction &= ~0x80; else correction = ~(correction); ptrClock->Correction = correction; } void set_system_time_NTP(uint32_t sec) { RealTimeClock_typeDef t; unix_to_time(&t, sec); SetCurrent_RTC(&t); } void get_system_time_NTP(int32_t *sec, uint32_t *msec) { *sec = time_to_unix(&RealTimeClock); } /* CLOCK TASK ------------------------------------------------------------------------------ */ void vClockTask(void *param) { _Bool prevFlag_BAT_LOW = 0, prevFlag_OSC_FAIL = 0; MX_I2C1_Init(); if(SetEnable_RTC()) __debug(DEBUG_SERVSE,"RTC: is running\r\n"); GetCorrection_RTC(&RealTimeClock); ClearBitHT_RTC(); GetCurrent_RTC(&RealTimeClock); if((RealTimeClock.Data.Month == 0x00) || (RealTimeClock.Data.Day == 0x00) || (RealTimeClock.Data.Year == 0x0000)) { // если масяц день или год не валидный RealTimeClock_typeDef t = {0x00, {1, 1, 2000}, {0, 0, 0, 0}}; SetCurrent_RTC(&t);// устанавливаем 01.01.2000 GetCurrent_RTC(&RealTimeClock); } __debug(DEBUG_SERVSE, "RTC: Data: %02d.%02d.%04d, Time: %02d:%02d:%02d\r\n", RealTimeClock.Data.Day, RealTimeClock.Data.Month, RealTimeClock.Data.Year, RealTimeClock.Time.Hour, RealTimeClock.Time.Min, RealTimeClock.Time.Sec); for(;;){ osDelay(1000); GetCurrent_RTC(&RealTimeClock); if((RealTimeClock.Flags.BAT_LOW) && (RealTimeClock.Flags.BAT_LOW != prevFlag_BAT_LOW)) { __debug(DEBUG_SERVSE,"RTC: Battery low\r\n"); __logWrite("RTC: Battery low\n"); prevFlag_BAT_LOW = 1; } else if((!RealTimeClock.Flags.BAT_LOW) && (RealTimeClock.Flags.BAT_LOW != prevFlag_BAT_LOW)) prevFlag_BAT_LOW = 0; if((RealTimeClock.Flags.OSC_FAIL) && (RealTimeClock.Flags.OSC_FAIL != prevFlag_OSC_FAIL)) { __debug(DEBUG_SERVSE,"RTC: OSC fail\r\n"); prevFlag_OSC_FAIL = 1; } else if((!RealTimeClock.Flags.OSC_FAIL) && (RealTimeClock.Flags.OSC_FAIL != prevFlag_OSC_FAIL)) prevFlag_OSC_FAIL = 0; } }