/* * Copyright (c) 2023-2024, Erich Styger * * * Driver for the NXP PCF85063A I2C RTC. * * SPDX-License-Identifier: BSD-3-Clause */ #include "McuPCF85063A.h" #include "McuShell.h" #include "McuUtility.h" #include "McuGenericI2C.h" #include "McuXFormat.h" #define McuPCF85063A_I2C_DEVICE_ADDRESS (0x51) /* 7bit I2C address, not-shifted value */ /* register memory map */ #define McuPCF85063A_ADDRESS_CONTROL_1 0x00 #define McuPCF85063A_ADDRESS_CONTROL_2 0x01 #define McuPCF85063A_ADDRESS_OFFSET 0x02 #define McuPCF85063A_ADDRESS_RAM_BYTE 0x03 #define McuPCF85063A_ADDRESS_TIME_DATE_START_ADDR 0x04 /* start address of time and date registers */ #define McuPCF85063A_ADDRESS_TIME_START_ADDR 0x04 /* start address of time registers */ #define McuPCF85063A_ADDRESS_DATE_START_ADDR 0x07 /* start address of time registers */ #define McuPCF85063A_ADDRESS_ALARM_START_ADDR 0x0B /* start address of alarm registers */ #define McuPCF85063A_ADDRESS_ALARM_SECOND 0x0B /* Second_alarm */ #define McuPCF85063A_ADDRESS_ALARM_MINUTE 0x0C /* Minute_alarm */ #define McuPCF85063A_ADDRESS_ALARM_HOUR 0x0D /* Hour_alarm */ #define McuPCF85063A_ADDRESS_ALARM_DAY 0x0E /* Hour_alarm */ #define McuPCF85063A_ADDRESS_ALARM_WEEKDAY 0x0F /* Weekday_alarm */ #define McuPCF85063A_TTIME_AMPM_AM 0 /* AM */ #define McuPCF85063A_TTIME_AMPM_PM 1 /* PM */ /* hour mode is set in 12_24 bit in Control_1 */ #define McuPCF85063A_TTIME_MODE_12H 0 /* 12 hour clock mode */ #define McuPCF85063A_TTIME_MODE_24H 1 /* 14 hour clock mode */ #define McuPCF85063A_MEMORY_TIME_SIZE (3) /* 0x4-0x6, number of bytes for time information on device */ #define McuPCF85063A_MEMORY_DATE_SIZE (4) /* 0x7-0xA, number of bytes for date information on device */ #define McuPCF85063A_MEMORY_TIME_DATE_SIZE (7) /* 0x4-0xA, number of bytes for data and time information on device */ typedef struct McuPCF85063A_TTIME { /* Time in binary format */ uint8_t hour; /* hours */ uint8_t min; /* minutes */ uint8_t sec; /* seconds */ uint8_t am_pm; /* 0: AM, 1: PM */ uint8_t mode; /* hour mode is set in 12_24 bit in Control_1 */ } McuPCF85063A_TTIME; typedef struct McuPCF85063A_TDATE { /* Date in binary format */ uint8_t year; /* year */ uint8_t month; /* month */ uint8_t day; /* day */ uint8_t dayOfWeek; /* Day of week, where 0 is the first day. In the range of 0..6 */ } McuPCF85063A_TDATE; uint8_t McuPCF85063A_ReadBlock(uint8_t addr, uint8_t *buf, size_t bufSize) { return McuGenericI2C_ReadAddress(McuPCF85063A_I2C_DEVICE_ADDRESS, &addr, sizeof(addr), buf, bufSize); } uint8_t McuPCF85063A_WriteBlock(uint8_t addr, uint8_t *buf, size_t bufSize) { return McuGenericI2C_WriteAddress(McuPCF85063A_I2C_DEVICE_ADDRESS, &addr, sizeof(addr), buf, bufSize); } uint8_t McuPCF85063A_ReadByte(uint8_t addr, uint8_t *data) { return McuGenericI2C_ReadAddress(McuPCF85063A_I2C_DEVICE_ADDRESS, &addr, sizeof(addr), data, sizeof(*data)); } uint8_t McuPCF85063A_WriteByte(uint8_t addr, uint8_t data) { return McuGenericI2C_WriteAddress(McuPCF85063A_I2C_DEVICE_ADDRESS, &addr, sizeof(addr), &data, sizeof(data)); } uint8_t McuPCF85063A_ReadControl1(uint8_t *data) { return McuPCF85063A_ReadByte(McuPCF85063A_ADDRESS_CONTROL_1, data); } uint8_t McuPCF85063A_WriteControl1(uint8_t data) { return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_CONTROL_1, data); } uint8_t McuPCF85063A_WriteSoftwareReset(void) { return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_CONTROL_1, 0x58); } uint8_t McuPCF85063A_ReadControl2(uint8_t *data) { return McuPCF85063A_ReadByte(McuPCF85063A_ADDRESS_CONTROL_2, data); } uint8_t McuPCF85063A_WriteControl2(uint8_t data) { return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_CONTROL_2, data); } uint8_t McuPCF85063A_WriteAlarmInterrupt(bool enable) { uint8_t data; if (McuPCF85063A_ReadControl2(&data)!=ERR_OK) { /* read current value */ return ERR_FAILED; } /* AIE 0: disabled; 1: enabled */ if (enable) { data |= (1<<7); /* set AIE (Alarm Interrupt Enable) bit */ } else { data &= (1<<7); /* clear AIE (Alarm Interrupt Enable) bit */ } return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_CONTROL_2, data); } uint8_t McuPCF85063A_WriteClockOutputFrequency(McuPCF85063A_COF_Frequency_e frequency) { uint8_t data; if (McuPCF85063A_ReadControl2(&data)!=ERR_OK) { /* read current value */ return ERR_FAILED; } /* Clock Output Frequency: * 000: 32768 * 001: 16387 * 010: 8196 * 011: 4096 * 100: 2048 * 101: 1024 * 110: 1 * 111: CLKOUT=LOW */ if (frequency>7) { return ERR_RANGE; } data |= (frequency&7); /* set COF bits [2:0] */ return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_CONTROL_2, data); } uint8_t McuPCF85063A_WriteResetAlarmInterrupt(void) { uint8_t data; if (McuPCF85063A_ReadControl2(&data)!=ERR_OK) { /* read current value */ return ERR_FAILED; } /* AF: reset alarm flag with writing a 0 to it */ data &= ~(1<<6); /* clear AF (Alarm Flag) bit */ return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_CONTROL_2, data); } uint8_t McuPCF85063A_ReadOffset(uint8_t *data) { return McuPCF85063A_ReadByte(McuPCF85063A_ADDRESS_OFFSET, data); } uint8_t McuPCF85063A_WriteOffset(uint8_t data) { return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_OFFSET, data); } bool McuPCF85063A_Is24hMode(void) { uint8_t res, ctrl; res = McuPCF85063A_ReadControl1(&ctrl); if (res!=ERR_OK) { return true; /* default is 24h mode */ } return (ctrl&(1<<1))==0; /* 0: 12-hour mode, 1: 24-hour mode */ } uint8_t McuPCF85063A_ReadAlarmSecond(uint8_t *second, bool *enabled) { uint8_t data, res; res = McuPCF85063A_ReadByte(McuPCF85063A_ADDRESS_ALARM_SECOND, &data); if (res!=ERR_OK) { return ERR_FAILED; } *enabled = (data&(1<<7))==0; /* 1: disabled (default), 0: enabled */ *second = ((data&0x70)>>4)*10 + (data&0x0F); /* BCD encoded */ return ERR_OK; } uint8_t McuPCF85063A_WriteAlarmSecond(uint8_t second, bool enable) { uint8_t data; if (second>59) { return ERR_RANGE; } data = ((second/10)<<4)|(second%10); /* encoded in BCD */ if (!enable) { data |= (1<<7); /* 1: disabled (default), 0: enabled */ } return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_ALARM_SECOND, data); } uint8_t McuPCF85063A_ReadAlarmMinute(uint8_t *minute, bool *enabled) { uint8_t data, res; res = McuPCF85063A_ReadByte(McuPCF85063A_ADDRESS_ALARM_MINUTE, &data); if (res!=ERR_OK) { return ERR_FAILED; } *enabled = (data&(1<<7))==0; /* 1: disabled (default), 0: enabled */ *minute = ((data&0x70)>>4)*10 + (data&0x0F); /* BCD encoded */ return ERR_OK; } uint8_t McuPCF85063A_WriteAlarmMinute(uint8_t minute, bool enable) { uint8_t data; if (minute>59) { return ERR_RANGE; } data = ((minute/10)<<4)|(minute%10); /* BCD encoded */ if (!enable) { data |= (1<<7); /* 1: disabled (default), 0: enabled */ } return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_ALARM_MINUTE, data); } uint8_t McuPCF85063A_ReadAlarmHour(uint8_t *hour, bool *enabled, bool *is24h, bool *isAM) { uint8_t data, res; *is24h = McuPCF85063A_Is24hMode(); res = McuPCF85063A_ReadByte(McuPCF85063A_ADDRESS_ALARM_HOUR, &data); if (res!=ERR_OK) { return ERR_FAILED; } *enabled = (data&(1<<7))==0; /* 1: disabled (default), 0: enabled */ if (*is24h) { *hour = ((data&0x30)>>4)*10 + (data&0x0F); /* BCD encoded */ *isAM = false; } else { *hour = ((data&0x70)>>4)*10 + (data&0x0F); /* BCD encoded */ *isAM = (data&(1<<5))==0; } return ERR_OK; } /* Note: expects 24h hour format! */ uint8_t McuPCF85063A_WriteAlarmHour(uint8_t hour, bool enable, bool is24h, bool isAM) { uint8_t data; if (is24h && hour>23) { return ERR_RANGE; } else if (!is24h && hour>12) { return ERR_RANGE; } data = 0; if (!enable) { data |= (1<<7); /* 1: disabled (default), 0: enabled */ } if (is24h) { data |= ((hour/10)<<4)|(hour%10); /* BCD encoded */ } else { if (hour>12) { /* PM */ hour -= 12; data |= (1<<5); /* set PM bit */ } data |= (hour<<4)|(hour%10); } return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_ALARM_HOUR, data); } uint8_t McuPCF85063A_ReadAlarmDay(uint8_t *day, bool *enabled) { uint8_t res, data; res = McuPCF85063A_ReadByte(McuPCF85063A_ADDRESS_ALARM_DAY, &data); if (res != ERR_OK) { return ERR_FAILED; } *enabled = (data&(1<<7))==0; /* 1: disabled (default), 0: enabled */ *day = ((data&0x70)>>4)*10 + (data&0x0F); /* BCD encoded */ return ERR_OK; } uint8_t McuPCF85063A_WriteAlarmDay(uint8_t day, bool enable) { uint8_t data; data = 0; if (!enable) { data |= (1<<7); /* 1: disabled (default), 0: enabled */ } data |= ((day/10)<<4)|(day%10); /* BCD encoded */ return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_ALARM_DAY, data); } uint8_t McuPCF85063A_ReadAlarmWeekDay(uint8_t *weekDay, bool *enabled) { uint8_t res, data; res = McuPCF85063A_ReadByte(McuPCF85063A_ADDRESS_ALARM_WEEKDAY, &data); if (res != ERR_OK) { return ERR_FAILED; } *enabled = (data&(1<<7))==0; /* 1: disabled (default), 0: enabled */ *weekDay = ((data&0x70)>>4)*10 + (data&0x0F); /* BCD encoded */ return ERR_OK; } uint8_t McuPCF85063A_WriteAlarmWeekDay(uint8_t weekDay, bool enable) { uint8_t data; if (weekDay>6) { return ERR_RANGE; } data = 0; if (!enable) { data |= (1<<7); /* 1: disabled (default), 0: enabled */ } data |= ((weekDay/10)<<4)|(weekDay%10); /* BCD encoded */ return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_ALARM_WEEKDAY, data); } uint8_t McuPCF85063A_ReadTimeDate(McuPCF85063A_TTIME *time, McuPCF85063A_TDATE *date) { uint8_t buf[McuPCF85063A_MEMORY_TIME_DATE_SIZE]; bool is24hMode; if (McuPCF85063A_ReadBlock(McuPCF85063A_ADDRESS_TIME_DATE_START_ADDR, buf, sizeof(buf))!=ERR_OK) { return ERR_FAILED; } is24hMode = McuPCF85063A_Is24hMode(); time->sec = (uint8_t)(((buf[0]&0x70)>>4)*10 + (buf[0]&0x0F)); /* seconds in BCD format */ time->min = (uint8_t)((buf[1]>>4)*10 + (buf[1]&0x0F)); /* minutes in BCD format */ if (is24hMode) { time->hour = (uint8_t)(((buf[2]&0x30)>>4)*10 + (buf[2]&0x0F)); /* hour in BCD format */ time->mode = McuPCF85063A_TTIME_MODE_24H; } else { time->hour = (uint8_t)(((buf[2]&0x10)>>4)*10 + (buf[2]&0x0F)); /* hour in BCD format */ time->am_pm = (uint8_t)((buf[2]&(1<<5))>>5); /* bit 5: AM/PM indicator. 0: AM, 1: PM */ time->mode = McuPCF85063A_TTIME_MODE_12H; } date->day = (uint8_t)((buf[3]>>4)*10 + (buf[3]&0x0F)); /* BCD format */ date->dayOfWeek =(uint8_t)(buf[4]); /* 0: Sunday, 1: Monday, ... 6: Saturday */ date->month = (uint8_t)((buf[5]>>4)*10 + (buf[5]&0x0F)); /* 1: January */ date->year = (uint8_t)((buf[6]>>4)*10 + (buf[6]&0x0F)); return ERR_OK; } uint8_t McuPCF85063A_WriteTimeDate(McuPCF85063A_TTIME *time, McuPCF85063A_TDATE *date) { uint8_t buf[McuPCF85063A_MEMORY_TIME_DATE_SIZE]; if ( ((time->mode==McuPCF85063A_TTIME_MODE_12H)&&((time->hour>12)||(time->hour==0))) || ((time->mode==McuPCF85063A_TTIME_MODE_24H)&&(time->hour>23)) || (time->min>59)||(time->sec>59) || (date->year>99)||(date->month>12)||(date->month==0) || (date->day>31)||(date->day==0) || (date->dayOfWeek>6)) { return ERR_RANGE; } buf[0] = (uint8_t)(((time->sec/10)<<4) | (time->sec%10)); buf[1] = (uint8_t)(((time->min/10)<<4) | (time->min%10)); buf[2] = (uint8_t)(((time->hour/10)<<4) | (time->hour%10)); if (time->mode==McuPCF85063A_TTIME_MODE_12H) { buf[2] |= (time->am_pm)?(1<<5):0; } buf[3] = (uint8_t)(((date->day/10)<<4) | (date->day%10)); buf[4] = (uint8_t)(date->dayOfWeek); buf[5] = (uint8_t)(((date->month/10)<<4) | (date->month%10)); buf[6] = (uint8_t)(((date->year/10)<<4) | (date->year%10)); if (McuPCF85063A_WriteBlock(McuPCF85063A_ADDRESS_TIME_DATE_START_ADDR, buf, sizeof(buf))!=ERR_OK) { return ERR_FAILED; } return ERR_OK; } uint8_t McuPCF85063A_WriteDate(McuPCF85063A_TDATE *date) { uint8_t buf[McuPCF85063A_MEMORY_DATE_SIZE]; if ( (date->year>99) || (date->month>12)||(date->month==0) || (date->day>31)||(date->day==0) || (date->dayOfWeek>6) ) { return ERR_RANGE; } buf[0] = (uint8_t)(((date->day/10)<<4) | (date->day%10)); buf[1] = (uint8_t)(date->dayOfWeek); buf[2] = (uint8_t)(((date->month/10)<<4) | (date->month%10)); buf[3] = (uint8_t)(((date->year/10)<<4) | (date->year%10)); if (McuPCF85063A_WriteBlock(McuPCF85063A_ADDRESS_DATE_START_ADDR, buf, sizeof(buf))!=ERR_OK) { return ERR_FAILED; } return ERR_OK; } uint8_t McuPCF85063A_WriteTime(McuPCF85063A_TTIME *time) { uint8_t buf[McuPCF85063A_MEMORY_TIME_SIZE]; if ( ((time->mode==McuPCF85063A_TTIME_MODE_12H)&&((time->hour>12)||(time->hour==0))) || ((time->mode==McuPCF85063A_TTIME_MODE_24H)&&(time->hour>23)) || (time->min>59) || (time->sec>59) ) { return ERR_RANGE; } buf[0] = (uint8_t)(((time->sec/10)<<4) | (time->sec%10)); buf[1] = (uint8_t)(((time->min/10)<<4) | (time->min%10)); buf[2] = (uint8_t)(((time->hour/10)<<4) | (time->hour%10)); if (time->mode==McuPCF85063A_TTIME_MODE_12H) { buf[2] |= (time->am_pm)?(1<<5):0; } if (McuPCF85063A_WriteBlock(McuPCF85063A_ADDRESS_TIME_START_ADDR, buf, sizeof(buf))!=ERR_OK) { return ERR_FAILED; } return ERR_OK; } uint8_t McuPCF85063A_GetTime(TIMEREC *time) { McuPCF85063A_TTIME ttime; McuPCF85063A_TDATE tdate; if (McuPCF85063A_ReadTimeDate(&ttime, &tdate)!=ERR_OK) { return ERR_FAILED; } time->Hour = ttime.hour; time->Min = ttime.min; time->Sec = ttime.sec; time->Sec100 = 0; return ERR_OK; } uint8_t McuPCF85063A_SetTimeInfo(uint8_t Hour, uint8_t Min, uint8_t Sec, uint8_t Sec100) { McuPCF85063A_TTIME ttime; ttime.hour = Hour; ttime.min = Min; ttime.sec = Sec; (void)Sec100; /* ignored, as cannot be stored on device */ ttime.mode = McuPCF85063A_TTIME_MODE_24H; ttime.am_pm = McuPCF85063A_TTIME_AMPM_AM; return McuPCF85063A_WriteTime(&ttime); } uint8_t McuPCF85063A_SetTime(TIMEREC *time) { return McuPCF85063A_SetTimeInfo(time->Hour, time->Min, time->Sec, time->Sec100); } uint8_t McuPCF85063A_GetDate(DATEREC *date) { McuPCF85063A_TTIME ttime; McuPCF85063A_TDATE tdate; if (McuPCF85063A_ReadTimeDate(&ttime, &tdate)!=ERR_OK) { return ERR_FAILED; } date->Year = (uint16_t)(tdate.year+2000); /* assume we are after the year 2000 */ date->Month = tdate.month; date->Day = tdate.day; return ERR_OK; } uint8_t McuPCF85063A_SetDateInfo(uint16_t Year, uint8_t Month, uint8_t Day) { McuPCF85063A_TDATE tdate; if (Year>=2000) { tdate.year = (uint8_t)(Year-2000); } else if (Year>=1900) { tdate.year = (uint8_t)(Year-1900); } else { tdate.year = Year%100; } tdate.month = Month; tdate.day = Day; tdate.dayOfWeek = McuUtility_WeekDay(Year, Month, Day); return McuPCF85063A_WriteDate(&tdate); } uint8_t McuPCF85063A_SetDate(DATEREC *date) { return McuPCF85063A_SetDateInfo(date->Year, date->Month, date->Day); } uint8_t McuPCF85063A_GetTimeDate(TIMEREC *time, DATEREC *date) { McuPCF85063A_TTIME ttime; McuPCF85063A_TDATE tdate; if (McuPCF85063A_ReadTimeDate(&ttime, &tdate)!=ERR_OK) { return ERR_FAILED; } time->Hour = ttime.hour; time->Min = ttime.min; time->Sec = ttime.sec; time->Sec100 = 0; date->Year = (uint16_t)(tdate.year+2000); date->Month = tdate.month; date->Day = tdate.day; return ERR_OK; } uint8_t McuPCF85063A_ReadRamByte(uint8_t *data) { return McuPCF85063A_ReadByte(McuPCF85063A_ADDRESS_RAM_BYTE, data); } uint8_t McuPCF85063A_WriteRamByte(uint8_t data) { return McuPCF85063A_WriteByte(McuPCF85063A_ADDRESS_RAM_BYTE, data); } static const char *GetWeekDayString(uint8_t weekday) { static const char *const weekDays[]={"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; if (weekday<=sizeof(weekDays)/sizeof(weekDays[0])) { return weekDays[weekday]; } else { return "error"; } } static uint8_t StrCatHWTimeDate(uint8_t *buf, size_t bufSize) { McuPCF85063A_TDATE tdate; McuPCF85063A_TTIME ttime; if (McuPCF85063A_ReadTimeDate(&ttime, &tdate)!=ERR_OK) { return ERR_FAILED; } if (tdate.dayOfWeek<=6) { McuUtility_strcat(buf, bufSize, (unsigned char*)GetWeekDayString(tdate.dayOfWeek)); } McuUtility_chcat(buf, bufSize, ' '); McuUtility_strcatNum16uFormatted(buf, bufSize, tdate.day, '0', 2); McuUtility_chcat(buf, bufSize, '.'); McuUtility_strcatNum16uFormatted(buf, bufSize, tdate.month, '0', 2); McuUtility_chcat(buf, bufSize, '.'); McuUtility_strcatNum16u(buf, bufSize, (uint16_t)tdate.year); McuUtility_strcat(buf, bufSize, (unsigned char*)", "); McuUtility_strcatNum16sFormatted(buf, bufSize, ttime.hour, '0', 2); McuUtility_chcat(buf, bufSize, ':'); McuUtility_strcatNum16sFormatted(buf, bufSize, ttime.min, '0', 2); McuUtility_chcat(buf, bufSize, ':'); McuUtility_strcatNum16sFormatted(buf, bufSize, ttime.sec, '0', 2); if (ttime.mode==McuPCF85063A_TTIME_MODE_24H) { McuUtility_strcat(buf, bufSize, (unsigned char*)" (24h)"); } else { if (ttime.am_pm==McuPCF85063A_TTIME_AMPM_AM) { McuUtility_strcat(buf, bufSize, (unsigned char*)"am"); } else { McuUtility_strcat(buf, bufSize, (unsigned char*)"pm"); } } return ERR_OK; } static uint8_t StrCatHWAlarm(unsigned char *buf, size_t bufSize) { uint8_t res, data; bool enabled; bool is24h, isAM; McuUtility_strcat(buf, bufSize, (unsigned char*)"h:"); res = McuPCF85063A_ReadAlarmHour(&data, &enabled, &is24h, &isAM); if (res==ERR_OK) { McuUtility_strcatNum8u(buf, bufSize, data); if (!is24h) { if (isAM) { McuUtility_strcat(buf, bufSize, (unsigned char*)"AM"); } else { McuUtility_strcat(buf, bufSize, (unsigned char*)"PM"); } } McuUtility_strcat(buf, bufSize, (unsigned char*)" ("); if (enabled) { McuUtility_strcat(buf, bufSize, (unsigned char*)"on); "); } else { McuUtility_strcat(buf, bufSize, (unsigned char*)"off); "); } } else { McuUtility_strcat(buf, bufSize, (unsigned char*)"ERR"); } McuUtility_strcat(buf, bufSize, (unsigned char*)"m:"); res = McuPCF85063A_ReadAlarmMinute(&data, &enabled); if (res==ERR_OK) { McuUtility_strcatNum8u(buf, bufSize, data); McuUtility_strcat(buf, bufSize, (unsigned char*)" ("); if (enabled) { McuUtility_strcat(buf, bufSize, (unsigned char*)"on); "); } else { McuUtility_strcat(buf, bufSize, (unsigned char*)"off); "); } } else { McuUtility_strcat(buf, bufSize, (unsigned char*)"ERR"); } McuUtility_strcat(buf, bufSize, (unsigned char*)"s:"); res = McuPCF85063A_ReadAlarmSecond(&data, &enabled); if (res==ERR_OK) { McuUtility_strcatNum8u(buf, bufSize, data); McuUtility_strcat(buf, bufSize, (unsigned char*)" ("); if (enabled) { McuUtility_strcat(buf, bufSize, (unsigned char*)"on); "); } else { McuUtility_strcat(buf, bufSize, (unsigned char*)"off); "); } } else { McuUtility_strcat(buf, bufSize, (unsigned char*)"ERR"); } McuUtility_strcat(buf, bufSize, (unsigned char*)"w:"); res = McuPCF85063A_ReadAlarmWeekDay(&data, &enabled); if (res==ERR_OK) { McuUtility_strcatNum8u(buf, bufSize, data); McuUtility_strcat(buf, bufSize, (unsigned char*)", "); McuUtility_strcat(buf, bufSize, (unsigned char*)GetWeekDayString(data)); McuUtility_strcat(buf, bufSize, (unsigned char*)" ("); if (enabled) { McuUtility_strcat(buf, bufSize, (unsigned char*)"on); "); } else { McuUtility_strcat(buf, bufSize, (unsigned char*)"off); "); } } else { McuUtility_strcat(buf, bufSize, (unsigned char*)"ERR"); } return ERR_OK; } static uint8_t DateCmd(const unsigned char *cmd, McuShell_ConstStdIOType *io) { uint8_t day, month; uint16_t year; uint8_t res = ERR_OK; if (McuUtility_ScanDate(&cmd, &day, &month, &year) == ERR_OK) { /* ok, format fine */ /* update real time clock */ res = McuPCF85063A_SetDateInfo(year, month, day); if (res!=ERR_OK) { McuShell_SendStr((unsigned char*)"*** Failure setting RTC\r\n", io->stdErr); res = ERR_FAILED; } } else { McuShell_SendStr((unsigned char*)"*** Error while reading command! ***", io->stdErr); McuShell_SendStr((void *)cmd, io->stdErr); McuShell_SendStr((unsigned char*)"\r\n", io->stdErr); res = ERR_FAILED; } return res; } static uint8_t TimeCmd(const unsigned char *cmd, McuShell_ConstStdIOType *io) { uint8_t hour, minute, second, hSecond; uint8_t res = ERR_OK; if (McuUtility_ScanTime(&cmd, &hour, &minute, &second, &hSecond)==ERR_OK) { /* format fine */ /* set RTC time */ res = McuPCF85063A_SetTimeInfo(hour, minute, second, hSecond); if (res != ERR_OK) { McuShell_SendStr((unsigned char*)"*** Failure setting RTC time\r\n", io->stdErr); res = ERR_FAILED; } } else { McuShell_SendStr((unsigned char*)"*** Error while reading command: ", io->stdErr); McuShell_SendStr(cmd, io->stdErr); McuShell_SendStr((unsigned char*)"\r\n", io->stdErr); res = ERR_FAILED; } return res; } static uint8_t CmdAlarmEnable(const unsigned char *p, bool enable) { uint8_t val; bool dummy; bool is24h, isAM; if (*p=='s') { if (McuPCF85063A_ReadAlarmSecond(&val, &dummy)!=ERR_OK) { return ERR_FAILED; } return McuPCF85063A_WriteAlarmSecond(val, enable); } else if (*p=='m') { if (McuPCF85063A_ReadAlarmMinute(&val, &dummy)!=ERR_OK) { return ERR_FAILED; } return McuPCF85063A_WriteAlarmMinute(val, enable); } else if (*p=='h') { if (McuPCF85063A_ReadAlarmHour(&val, &dummy, &is24h, &isAM)!=ERR_OK) { return ERR_FAILED; } return McuPCF85063A_WriteAlarmHour(val, enable, is24h, isAM); } else if (*p=='w') { if (McuPCF85063A_ReadAlarmWeekDay(&val, &dummy)!=ERR_OK) { return ERR_FAILED; } return McuPCF85063A_WriteAlarmWeekDay(val, enable); } return ERR_FAILED; } static uint8_t PrintStatus(McuShell_ConstStdIOType *io) { unsigned char buf[96]; uint8_t res, data; McuShell_SendStatusStr((unsigned char*)"rtc", (const unsigned char*)"Status of PCF85063A RTC\r\n", io->stdOut); McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x"); McuUtility_strcatNum8Hex(buf, sizeof(buf), McuPCF85063A_I2C_DEVICE_ADDRESS); McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n"); McuShell_SendStatusStr((unsigned char*)" address", buf, io->stdOut); res = McuPCF85063A_ReadControl1(&data); if (res==ERR_OK) { McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x"); McuUtility_strcatNum8Hex(buf, sizeof(buf), data); McuUtility_strcat(buf, sizeof(buf), (unsigned char*)": "); if (data&(1<<7)) { /* EXT_TEST */ McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"7:test(1), "); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"7:normal(0), "); } if (data&(1<<5)) { /* STOP*/ McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"5:RCTstopped(1), "); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"5:RTCruns(0), "); } if (data&(1<<3)) { /* CIE: correction interrupt enable */ McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"3:CIEoff(1), "); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"3:CIEon(0), "); } if (data&(1<<1)) { /* 12_24 */ McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"1:12h(1), "); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"1:24h(0), "); } if (data&(1<<0)) { /* CAP_SEL */ McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"0:12.5pF(1)"); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"0:7pF(0)"); } McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n"); } else { McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"ERROR\r\n"); } McuShell_SendStatusStr((uint8_t*)" Control_1", (unsigned char*)buf, io->stdOut); res = McuPCF85063A_ReadControl2(&data); if (res==ERR_OK) { McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x"); McuUtility_strcatNum8Hex(buf, sizeof(buf), data); McuUtility_strcat(buf, sizeof(buf), (unsigned char*)": "); if (data&(1<<7)) { /* AIE */ McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"7:AIEon(1), "); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"7:AIEoff(0), "); } if (data&(1<<6)) { /* AF */ McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"6:AFon(1), "); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"6:AFoff(0), "); } if (data&(1<<5)) { /* MI */ McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"5:MIon(1), "); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"5:MIoff(0), "); } if (data&(1<<4)) { /* HMI */ McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"4:HMIon(1), "); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"4:HMIoff(0), "); } if (data&(1<<3)) { /* TF */ McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"3:TFon(1), "); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"3:TFoff(0), "); } McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"2..0:COF("); McuUtility_strcatNum8u(buf, sizeof(buf), data&0x0); McuUtility_strcat(buf, sizeof(buf), (unsigned char*)")\r\n"); } else { McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"ERROR\r\n"); } McuShell_SendStatusStr((uint8_t*)" Control_2", (unsigned char*)buf, io->stdOut); res = McuPCF85063A_ReadOffset(&data); if (res==ERR_OK) { McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x"); McuUtility_strcatNum8Hex(buf, sizeof(buf), data); McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n"); } else { McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"ERROR\r\n"); } McuShell_SendStatusStr((uint8_t*)" Offset", (unsigned char*)buf, io->stdOut); res = McuPCF85063A_ReadRamByte(&data); if (res==ERR_OK) { McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x"); McuUtility_strcatNum8Hex(buf, sizeof(buf), data); McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n"); } else { McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"ERROR\r\n"); } McuShell_SendStatusStr((uint8_t*)" RAM byte", (unsigned char*)buf, io->stdOut); buf[0] = '\0'; if (StrCatHWAlarm(buf, sizeof(buf))) { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"ERROR\r\n"); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n"); } McuShell_SendStatusStr((unsigned char*)" alarm", buf, io->stdOut); buf[0] = '\0'; if (StrCatHWTimeDate(buf, sizeof(buf))!=ERR_OK) { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"ERROR\r\n"); } else { McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n"); } McuShell_SendStatusStr((unsigned char*)" time/date", buf, io->stdOut); return ERR_OK; } uint8_t McuPCF85063A_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io) { int32_t val; const unsigned char *p; bool enabled; uint8_t dummy; if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "rtc help")==0) { *handled = true; McuShell_SendHelpStr((unsigned char*)"rtc", (const unsigned char*)"Group of PCF85063 RTC commands\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" help|status", (const unsigned char*)"Print help or status information\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" reset", (const unsigned char*)"Send software reset command to device\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" write ram ", (const unsigned char*)"Write a byte value to the RAM\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" write ctrl1 ", (const unsigned char*)"Write a byte to the Control_1 (00h) register\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" write ctrl2 ", (const unsigned char*)"Write a byte to the Control_2 (01h) register\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" write offset ", (const unsigned char*)"Write a byte to the Offset (02h) register\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" time [hh:mm:ss[,z]]", (const unsigned char*)"Set the current time\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" date [dd.mm.yyyy]", (const unsigned char*)"Set the current date\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" alarm s|m|h|w ", (const unsigned char*)"Set alarm value for second, minute, hour or weekday\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" alarm on|off s|m|h|w", (const unsigned char*)"Enable alarm for second, minute, hour or weekday\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" alarm AIE on|off", (const unsigned char*)"Enable alarm interrupt for second, minute or hour\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" alarm reset AF", (const unsigned char*)"Reset alarm interrupt flag\r\n", io->stdOut); return ERR_OK; } else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "rtc status")==0)) { *handled = true; return PrintStatus(io); } else if (McuUtility_strncmp((char*)cmd, "rtc write ram ", sizeof("rtc write ram ")-1)==0) { *handled = true; p = cmd + sizeof("rtc write ram ")-1; if (McuUtility_xatoi(&p, &val)==ERR_OK && val>=0 && val<=0xff) { return McuPCF85063A_WriteRamByte(val); } } else if (McuUtility_strncmp((char*)cmd, "rtc write ctrl1 ", sizeof("rtc write ctrl1 ")-1)==0) { *handled = true; p = cmd + sizeof("rtc write ctrl1 ")-1; if (McuUtility_xatoi(&p, &val)==ERR_OK && val>=0 && val<=0xff) { return McuPCF85063A_WriteControl1(val); } } else if (McuUtility_strncmp((char*)cmd, "rtc write ctrl2 ", sizeof("rtc write ctrl2 ")-1)==0) { *handled = true; p = cmd + sizeof("rtc write ctrl2 ")-1; if (McuUtility_xatoi(&p, &val)==ERR_OK && val>=0 && val<=0xff) { return McuPCF85063A_WriteControl2(val); } } else if (McuUtility_strncmp((char*)cmd, "rtc write offset ", sizeof("rtc write offset ")-1)==0) { *handled = true; p = cmd + sizeof("rtc write offset ")-1; if (McuUtility_xatoi(&p, &val)==ERR_OK && val>=0 && val<=0xff) { return McuPCF85063A_WriteOffset(val); } } else if (McuUtility_strncmp((char*)cmd, "rtc date ", sizeof("rtc date ")-1)==0) { *handled = TRUE; p = cmd + sizeof("rtc date ")-1; return DateCmd(p, io); } else if (McuUtility_strncmp((char*)cmd, "rtc time ", sizeof("rtc time ")-1)==0) { *handled = TRUE; p = cmd + sizeof("rtc time ")-1; return TimeCmd(p, io); } else if (McuUtility_strncmp((char*)cmd, "rtc alarm s ", sizeof("rtc alarm s ")-1)==0) { *handled = TRUE; p = cmd + sizeof("rtc alarm s ")-1; if (McuPCF85063A_ReadAlarmSecond(&dummy, &enabled)!=ERR_OK) { /* get enabled state */ return ERR_FAILED; } if (McuUtility_xatoi(&p, &val)==ERR_OK && val>=0 && val<=59) { return McuPCF85063A_WriteAlarmSecond(val, enabled); } return ERR_FAILED; } else if (McuUtility_strncmp((char*)cmd, "rtc alarm m ", sizeof("rtc alarm m ")-1)==0) { *handled = TRUE; p = cmd + sizeof("rtc alarm m")-1; if (McuPCF85063A_ReadAlarmMinute(&dummy, &enabled)!=ERR_OK) { /* get enabled state */ return ERR_FAILED; } if (McuUtility_xatoi(&p, &val)==ERR_OK && val>=0 && val<=59) { return McuPCF85063A_WriteAlarmMinute(val, enabled); } return ERR_FAILED; } else if (McuUtility_strncmp((char*)cmd, "rtc alarm h ", sizeof("rtc alarm h ")-1)==0) { bool is24h, isAM; *handled = TRUE; p = cmd + sizeof("rtc alarm h")-1; if (McuPCF85063A_ReadAlarmHour(&dummy, &enabled, &is24h, &isAM)!=ERR_OK) { /* get enabled state */ return ERR_FAILED; } if (McuUtility_xatoi(&p, &val)==ERR_OK && val>=0 && val<=23) { return McuPCF85063A_WriteAlarmHour(val, enabled, true, false); /* only supporting 24h format */ } return ERR_FAILED; } else if (McuUtility_strncmp((char*)cmd, "rtc alarm w ", sizeof("rtc alarm w ")-1)==0) { *handled = TRUE; p = cmd + sizeof("rtc alarm w")-1; if (McuPCF85063A_ReadAlarmWeekDay(&dummy, &enabled)!=ERR_OK) { /* get enabled state */ return ERR_FAILED; } if (McuUtility_xatoi(&p, &val)==ERR_OK && val>=0 && val<=6) { return McuPCF85063A_WriteAlarmWeekDay(val, enabled); } return ERR_FAILED; } else if (McuUtility_strcmp((char*)cmd, "rtc reset")==0) { *handled = true; return McuPCF85063A_WriteSoftwareReset(); } else if (McuUtility_strcmp((char*)cmd, "rtc alarm AIE on")==0) { *handled = true; return McuPCF85063A_WriteAlarmInterrupt(true); } else if (McuUtility_strcmp((char*)cmd, "rtc alarm AIE off")==0) { *handled = true; return McuPCF85063A_WriteAlarmInterrupt(false); } else if (McuUtility_strcmp((char*)cmd, "rtc alarm reset AF")==0) { *handled = true; return McuPCF85063A_WriteResetAlarmInterrupt(); } else if (McuUtility_strncmp((char*)cmd, "rtc alarm on ", sizeof("rtc alarm on ")-1)==0) { *handled = true; return CmdAlarmEnable(cmd+sizeof("rtc alarm on ")-1, true); } else if (McuUtility_strncmp((char*)cmd, "rtc alarm off ", sizeof("rtc alarm off ")-1)==0) { *handled = true; return CmdAlarmEnable(cmd+sizeof("rtc alarm off ")-1, false); } return ERR_OK; } void McuPCF85063A_Init(void) { }