diff --git a/drivers/rv3028/CMakeLists.txt b/drivers/rv3028/CMakeLists.txt index 76f5a4198..8184ce44b 100644 --- a/drivers/rv3028/CMakeLists.txt +++ b/drivers/rv3028/CMakeLists.txt @@ -1,10 +1 @@ -add_library(rv3028 INTERFACE) - -target_sources(rv3028 INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/rv3028.cpp -) - -target_include_directories(rv3028 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) - -# Pull in pico libraries that we need -target_link_libraries(rv3028 INTERFACE pico_stdlib hardware_i2c) +include(rv3028.cmake) diff --git a/drivers/rv3028/rv3028.cmake b/drivers/rv3028/rv3028.cmake index 586a93544..8a32686cb 100644 --- a/drivers/rv3028/rv3028.cmake +++ b/drivers/rv3028/rv3028.cmake @@ -1,10 +1,10 @@ -add_library(rv3028 INTERFACE) +set(DRIVER_NAME rv3028) +add_library(${DRIVER_NAME} INTERFACE) -target_sources(rv3028 INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/rv3028.cpp -) +target_sources(${DRIVER_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp) -target_include_directories(rv3028 INTERFACE ${CMAKE_CURRENT_LIST_DIR}) +target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(rv3028 INTERFACE pico_stdlib hardware_i2c) +target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c) diff --git a/drivers/rv3028/rv3028.cpp b/drivers/rv3028/rv3028.cpp index 7ec7db49e..5e5e41b48 100644 --- a/drivers/rv3028/rv3028.cpp +++ b/drivers/rv3028/rv3028.cpp @@ -60,121 +60,154 @@ BUILD_MONTH_OCT | BUILD_MONTH_NOV | BUILD_MONTH_DEC namespace pimoroni { - void RV3028::init() { + bool RV3028::init() { i2c_init(i2c, 400000); - gpio_set_function(sda, GPIO_FUNC_I2C); gpio_pull_up(sda); - gpio_set_function(scl, GPIO_FUNC_I2C); gpio_pull_up(scl); + gpio_set_function(sda, GPIO_FUNC_I2C); + gpio_pull_up(sda); + gpio_set_function(scl, GPIO_FUNC_I2C); + gpio_pull_up(scl); + + if(interrupt != PIN_UNUSED) { + gpio_set_function(interrupt, GPIO_FUNC_SIO); + gpio_set_dir(interrupt, GPIO_IN); + gpio_pull_up(interrupt); + } + + uint8_t chip_id = 0; + read_bytes(RV3028_ID, &chip_id, 1); + if(chip_id != (RV3028_CHIP_ID | RV3028_VERSION)) { + return false; + } + + return true; + } + + void RV3028::reset() { + set_bit(RV3028_CTRL2, CTRL2_RESET); + } + + i2c_inst_t* RV3028::get_i2c() const { + return i2c; + } + + int RV3028::get_sda() const { + return sda; + } + + int RV3028::get_scl() const { + return scl; + } + + int RV3028::get_int() const { + return interrupt; } - bool RV3028::setup(bool set_24Hour, bool disable_TrickleCharge, bool set_LevelSwitchingMode) - { + bool RV3028::setup(bool set_24Hour, bool disable_TrickleCharge, bool set_LevelSwitchingMode) { sleep_ms(1000); - if (set_24Hour) { set24Hour(); sleep_ms(1000); } - if (disable_TrickleCharge) { disableTrickleCharge(); sleep_ms(1000); } + if(set_24Hour) { + set_24_hour(); + sleep_ms(1000); + } - return((set_LevelSwitchingMode ? setBackupSwitchoverMode(3) : true) && writeRegister(RV3028_STATUS, 0x00)); + if(disable_TrickleCharge) { + disable_trickle_charge(); + sleep_ms(1000); + } + + return ((set_LevelSwitchingMode ? set_backup_switchover_mode(3) : true) && write_register(RV3028_STATUS, 0x00)); } - bool RV3028::setTime(uint8_t sec, uint8_t min, uint8_t hour, uint8_t weekday, uint8_t date, uint8_t month, uint16_t year) - { - _time[TIME_SECONDS] = DECtoBCD(sec); - _time[TIME_MINUTES] = DECtoBCD(min); - _time[TIME_HOURS] = DECtoBCD(hour); - _time[TIME_WEEKDAY] = DECtoBCD(weekday); - _time[TIME_DATE] = DECtoBCD(date); - _time[TIME_MONTH] = DECtoBCD(month); - _time[TIME_YEAR] = DECtoBCD(year - 2000); + bool RV3028::set_time(uint8_t sec, uint8_t min, uint8_t hour, uint8_t weekday, uint8_t date, uint8_t month, uint16_t year) { + times[TIME_SECONDS] = dec_to_bcd(sec); + times[TIME_MINUTES] = dec_to_bcd(min); + times[TIME_HOURS] = dec_to_bcd(hour); + times[TIME_WEEKDAY] = dec_to_bcd(weekday); + times[TIME_DATE] = dec_to_bcd(date); + times[TIME_MONTH] = dec_to_bcd(month); + times[TIME_YEAR] = dec_to_bcd(year - 2000); bool status = false; - if (is12Hour()) { - set24Hour(); - status = setTime(_time, TIME_ARRAY_LENGTH); - set12Hour(); - } else { - status = setTime(_time, TIME_ARRAY_LENGTH); + if(is_12_hour()) { + set_24_hour(); + status = set_time(times, TIME_ARRAY_LENGTH); + set_12_hour(); + } + else { + status = set_time(times, TIME_ARRAY_LENGTH); } return status; } // setTime -- Set time and date/day registers of RV3028 (using data array) - bool RV3028::setTime(uint8_t * time, uint8_t len) - { - if (len != TIME_ARRAY_LENGTH) + bool RV3028::set_time(uint8_t * time, uint8_t len) { + if(len != TIME_ARRAY_LENGTH) return false; - return writeMultipleRegisters(RV3028_SECONDS, time, len); + return write_multiple_registers(RV3028_SECONDS, time, len); } - bool RV3028::setSeconds(uint8_t value) - { - _time[TIME_SECONDS] = DECtoBCD(value); - return setTime(_time, TIME_ARRAY_LENGTH); + bool RV3028::set_seconds(uint8_t value) { + times[TIME_SECONDS] = dec_to_bcd(value); + return set_time(times, TIME_ARRAY_LENGTH); } - bool RV3028::setMinutes(uint8_t value) - { - _time[TIME_MINUTES] = DECtoBCD(value); - return setTime(_time, TIME_ARRAY_LENGTH); + bool RV3028::set_minutes(uint8_t value) { + times[TIME_MINUTES] = dec_to_bcd(value); + return set_time(times, TIME_ARRAY_LENGTH); } - bool RV3028::setHours(uint8_t value) - { - _time[TIME_HOURS] = DECtoBCD(value); - return setTime(_time, TIME_ARRAY_LENGTH); + bool RV3028::set_hours(uint8_t value) { + times[TIME_HOURS] = dec_to_bcd(value); + return set_time(times, TIME_ARRAY_LENGTH); } - bool RV3028::setWeekday(uint8_t value) - { - _time[TIME_WEEKDAY] = DECtoBCD(value); - return setTime(_time, TIME_ARRAY_LENGTH); + bool RV3028::set_weekday(uint8_t value) { + times[TIME_WEEKDAY] = dec_to_bcd(value); + return set_time(times, TIME_ARRAY_LENGTH); } - bool RV3028::setDate(uint8_t value) - { - _time[TIME_DATE] = DECtoBCD(value); - return setTime(_time, TIME_ARRAY_LENGTH); + bool RV3028::set_date(uint8_t value) { + times[TIME_DATE] = dec_to_bcd(value); + return set_time(times, TIME_ARRAY_LENGTH); } - bool RV3028::setMonth(uint8_t value) - { - _time[TIME_MONTH] = DECtoBCD(value); - return setTime(_time, TIME_ARRAY_LENGTH); + bool RV3028::set_month(uint8_t value) { + times[TIME_MONTH] = dec_to_bcd(value); + return set_time(times, TIME_ARRAY_LENGTH); } - bool RV3028::setYear(uint16_t value) - { - _time[TIME_YEAR] = DECtoBCD(value - 2000); - return setTime(_time, TIME_ARRAY_LENGTH); + bool RV3028::set_year(uint16_t value) { + times[TIME_YEAR] = dec_to_bcd(value - 2000); + return set_time(times, TIME_ARRAY_LENGTH); } - //Takes the time from the last build and uses it as the current time - //Works very well as an arduino sketch - bool RV3028::setToCompilerTime() - { - _time[TIME_SECONDS] = DECtoBCD(BUILD_SECOND); - _time[TIME_MINUTES] = DECtoBCD(BUILD_MINUTE); - _time[TIME_HOURS] = DECtoBCD(BUILD_HOUR); + // Takes the time from the last build and uses it as the current time + bool RV3028::set_to_compiler_time() { + times[TIME_SECONDS] = dec_to_bcd(BUILD_SECOND); + times[TIME_MINUTES] = dec_to_bcd(BUILD_MINUTE); + times[TIME_HOURS] = dec_to_bcd(BUILD_HOUR); - //Build_Hour is 0-23, convert to 1-12 if needed - if (is12Hour()) { + // Build_Hour is 0-23, convert to 1-12 if needed + if(is_12_hour()) { uint8_t hour = BUILD_HOUR; bool pm = false; - if (hour == 0) + if(hour == 0) hour += 12; - else if (hour == 12) + else if(hour == 12) pm = true; - else if (hour > 12) { + else if(hour > 12) { hour -= 12; pm = true; } - _time[TIME_HOURS] = DECtoBCD(hour); //Load the modified hours + times[TIME_HOURS] = dec_to_bcd(hour); // Load the modified hours - if (pm == true) _time[TIME_HOURS] |= (1 << HOURS_AM_PM); //Set AM/PM bit if needed + if(pm == true) + times[TIME_HOURS] |= (1 << HOURS_AM_PM); // Set AM/PM bit if needed } // Calculate weekday (from here: http://stackoverflow.com/a/21235587) @@ -183,217 +216,194 @@ namespace pimoroni { uint16_t m = BUILD_MONTH; uint16_t y = BUILD_YEAR; uint16_t weekday = (d += m < 3 ? y-- : y - 2, 23 * m / 9 + d + 4 + y / 4 - y / 100 + y / 400) % 7 + 1; - _time[TIME_WEEKDAY] = DECtoBCD(weekday); + times[TIME_WEEKDAY] = dec_to_bcd(weekday); - _time[TIME_DATE] = DECtoBCD(BUILD_DATE); - _time[TIME_MONTH] = DECtoBCD(BUILD_MONTH); - _time[TIME_YEAR] = DECtoBCD(BUILD_YEAR - 2000); //! Not Y2K (or Y2.1K)-proof :( + times[TIME_DATE] = dec_to_bcd(BUILD_DATE); + times[TIME_MONTH] = dec_to_bcd(BUILD_MONTH); + times[TIME_YEAR] = dec_to_bcd(BUILD_YEAR - 2000); // ! Not Y2K (or Y2.1K)-proof :( - return setTime(_time, TIME_ARRAY_LENGTH); + return set_time(times, TIME_ARRAY_LENGTH); } - //Move the hours, mins, sec, etc registers from RV-3028-C7 into the _time array - //Needs to be called before printing time or date - //We do not protect the GPx registers. They will be overwritten. The user has plenty of RAM if they need it. - bool RV3028::updateTime() - { - if (readMultipleRegisters(RV3028_SECONDS, _time, TIME_ARRAY_LENGTH) == false) - return(false); //Something went wrong + // Move the hours, mins, sec, etc registers from RV-3028-C7 into the _time array + // Needs to be called before printing time or date + // We do not protect the GPx registers. They will be overwritten. The user has plenty of RAM if they need it. + bool RV3028::update_time() { + if(read_multiple_registers(RV3028_SECONDS, times, TIME_ARRAY_LENGTH) == false) + return false; // Something went wrong - if (is12Hour()) _time[TIME_HOURS] &= ~(1 << HOURS_AM_PM); //Remove this bit from value + if(is_12_hour()) + times[TIME_HOURS] &= ~(1 << HOURS_AM_PM); // Remove this bit from value return true; } - //Returns a pointer to array of chars that are the date in mm/dd/yyyy format because they're weird - char* RV3028::stringDateUSA() - { - static char date[11]; //Max of mm/dd/yyyy with \0 terminator - sprintf(date, "%02hhu/%02hhu/20%02hhu", BCDtoDEC(_time[TIME_MONTH]), BCDtoDEC(_time[TIME_DATE]), BCDtoDEC(_time[TIME_YEAR])); - return(date); + // Returns a pointer to array of chars that are the date in mm/dd/yyyy format because they're weird + char* RV3028::string_date_usa() { + static char date[11 + 3]; // Max of mm/dd/yyyy with \0 terminator (plus extra for worst case conversion) + sprintf(date, "%02hhu/%02hhu/20%02hhu", bcd_to_dec(times[TIME_MONTH]), bcd_to_dec(times[TIME_DATE]), bcd_to_dec(times[TIME_YEAR])); + return date; } - //Returns a pointer to array of chars that are the date in dd/mm/yyyy format - char* RV3028::stringDate() - { - static char date[11]; //Max of dd/mm/yyyy with \0 terminator - sprintf(date, "%02hhu/%02hhu/20%02hhu", BCDtoDEC(_time[TIME_DATE]), BCDtoDEC(_time[TIME_MONTH]), BCDtoDEC(_time[TIME_YEAR])); - return(date); + // Returns a pointer to array of chars that are the date in dd/mm/yyyy format + char* RV3028::string_date() { + static char date[11 + 3]; // Max of dd/mm/yyyy with \0 terminator (plus extra for worst case conversion) + sprintf(date, "%02hhu/%02hhu/20%02hhu", bcd_to_dec(times[TIME_DATE]), bcd_to_dec(times[TIME_MONTH]), bcd_to_dec(times[TIME_YEAR])); + return date; } - //Returns a pointer to array of chars that represents the time in hh:mm:ss format - //Adds AM/PM if in 12 hour mode - char* RV3028::stringTime() - { - static char time[11]; //Max of hh:mm:ssXM with \0 terminator + // Returns a pointer to array of chars that represents the time in hh:mm:ss format + // Adds AM/PM if in 12 hour mode + char* RV3028::string_time() { + static char time[11 + 3]; // Max of hh:mm:ssXM with \0 terminator (plus extra for worst case conversion) - if (is12Hour() == true) - { + if(is_12_hour() == true) { char half = 'A'; - if (isPM()) half = 'P'; + if(is_pm()) half = 'P'; - sprintf(time, "%02hhu:%02hhu:%02hhu%cM", BCDtoDEC(_time[TIME_HOURS]), BCDtoDEC(_time[TIME_MINUTES]), BCDtoDEC(_time[TIME_SECONDS]), half); + sprintf(time, "%02hhu:%02hhu:%02hhu%cM", bcd_to_dec(times[TIME_HOURS]), bcd_to_dec(times[TIME_MINUTES]), bcd_to_dec(times[TIME_SECONDS]), half); } else - sprintf(time, "%02hhu:%02hhu:%02hhu", BCDtoDEC(_time[TIME_HOURS]), BCDtoDEC(_time[TIME_MINUTES]), BCDtoDEC(_time[TIME_SECONDS])); + sprintf(time, "%02hhu:%02hhu:%02hhu", bcd_to_dec(times[TIME_HOURS]), bcd_to_dec(times[TIME_MINUTES]), bcd_to_dec(times[TIME_SECONDS])); - return(time); + return time; } - char* RV3028::stringTimeStamp() - { - static char timeStamp[25]; //Max of yyyy-mm-ddThh:mm:ss.ss with \0 terminator + char* RV3028::string_time_stamp() { + static char time_stamp[25 + 4]; // Max of yyyy-mm-ddThh:mm:ss.ss with \0 terminator (plus extra for worst case conversion) - if (is12Hour() == true) - { + if(is_12_hour() == true) { char half = 'A'; - if (isPM()) half = 'P'; + if(is_pm()) half = 'P'; - sprintf(timeStamp, "20%02hhu-%02hhu-%02hhu %02hhu:%02hhu:%02hhu%cM", BCDtoDEC(_time[TIME_YEAR]), BCDtoDEC(_time[TIME_MONTH]), BCDtoDEC(_time[TIME_DATE]), BCDtoDEC(_time[TIME_HOURS]), BCDtoDEC(_time[TIME_MINUTES]), BCDtoDEC(_time[TIME_SECONDS]), half); + sprintf(time_stamp, "20%02hhu-%02hhu-%02hhu %02hhu:%02hhu:%02hhu%cM", bcd_to_dec(times[TIME_YEAR]), bcd_to_dec(times[TIME_MONTH]), bcd_to_dec(times[TIME_DATE]), bcd_to_dec(times[TIME_HOURS]), bcd_to_dec(times[TIME_MINUTES]), bcd_to_dec(times[TIME_SECONDS]), half); } else - sprintf(timeStamp, "20%02hhu-%02hhu-%02hhu %02hhu:%02hhu:%02hhu", BCDtoDEC(_time[TIME_YEAR]), BCDtoDEC(_time[TIME_MONTH]), BCDtoDEC(_time[TIME_DATE]), BCDtoDEC(_time[TIME_HOURS]), BCDtoDEC(_time[TIME_MINUTES]), BCDtoDEC(_time[TIME_SECONDS])); + sprintf(time_stamp, "20%02hhu-%02hhu-%02hhu %02hhu:%02hhu:%02hhu", bcd_to_dec(times[TIME_YEAR]), bcd_to_dec(times[TIME_MONTH]), bcd_to_dec(times[TIME_DATE]), bcd_to_dec(times[TIME_HOURS]), bcd_to_dec(times[TIME_MINUTES]), bcd_to_dec(times[TIME_SECONDS])); - return(timeStamp); + return time_stamp; } - uint8_t RV3028::getSeconds() - { - return BCDtoDEC(_time[TIME_SECONDS]); + uint8_t RV3028::get_seconds() { + return bcd_to_dec(times[TIME_SECONDS]); } - uint8_t RV3028::getMinutes() - { - return BCDtoDEC(_time[TIME_MINUTES]); + uint8_t RV3028::get_minutes() { + return bcd_to_dec(times[TIME_MINUTES]); } - uint8_t RV3028::getHours() - { - return BCDtoDEC(_time[TIME_HOURS]); + uint8_t RV3028::get_hours() { + return bcd_to_dec(times[TIME_HOURS]); } - uint8_t RV3028::getWeekday() - { - return BCDtoDEC(_time[TIME_WEEKDAY]); + uint8_t RV3028::get_weekday() { + return bcd_to_dec(times[TIME_WEEKDAY]); } - uint8_t RV3028::getDate() - { - return BCDtoDEC(_time[TIME_DATE]); + uint8_t RV3028::get_date() { + return bcd_to_dec(times[TIME_DATE]); } - uint8_t RV3028::getMonth() - { - return BCDtoDEC(_time[TIME_MONTH]); + uint8_t RV3028::get_month() { + return bcd_to_dec(times[TIME_MONTH]); } - uint16_t RV3028::getYear() - { - return BCDtoDEC(_time[TIME_YEAR]) + 2000; + uint16_t RV3028::get_year() { + return bcd_to_dec(times[TIME_YEAR]) + 2000; } - //Returns true if RTC has been configured for 12 hour mode - bool RV3028::is12Hour() - { - uint8_t controlRegister2 = readRegister(RV3028_CTRL2); - return(controlRegister2 & (1 << CTRL2_12_24)); + // Returns true if RTC has been configured for 12 hour mode + bool RV3028::is_12_hour() { + uint8_t controlRegister2 = read_register(RV3028_CTRL2); + return (controlRegister2 & (1 << CTRL2_12_24)); } - //Returns true if RTC has PM bit set and 12Hour bit set - bool RV3028::isPM() - { - uint8_t hourRegister = readRegister(RV3028_HOURS); - if (is12Hour() && (hourRegister & (1 << HOURS_AM_PM))) - return(true); - return(false); + // Returns true if RTC has PM bit set and 12Hour bit set + bool RV3028::is_pm() { + uint8_t hourRegister = read_register(RV3028_HOURS); + if(is_12_hour() && (hourRegister & (1 << HOURS_AM_PM))) + return true; + return false; } - //Configure RTC to output 1-12 hours - //Converts any current hour setting to 12 hour - void RV3028::set12Hour() - { - //Do we need to change anything? - if (is12Hour() == false) - { - uint8_t hour = BCDtoDEC(readRegister(RV3028_HOURS)); //Get the current hour in the RTC + // Configure RTC to output 1-12 hours + // Converts any current hour setting to 12 hour + void RV3028::set_12_hour() { + // Do we need to change anything? + if(is_12_hour() == false) { + uint8_t hour = bcd_to_dec(read_register(RV3028_HOURS)); // Get the current hour in the RTC - //Set the 12/24 hour bit - uint8_t setting = readRegister(RV3028_CTRL2); + // Set the 12/24 hour bit + uint8_t setting = read_register(RV3028_CTRL2); setting |= (1 << CTRL2_12_24); - writeRegister(RV3028_CTRL2, setting); + write_register(RV3028_CTRL2, setting); - //Take the current hours and convert to 12, complete with AM/PM bit + // Take the current hours and convert to 12, complete with AM/PM bit bool pm = false; - if (hour == 0) + if(hour == 0) hour += 12; - else if (hour == 12) + else if(hour == 12) pm = true; - else if (hour > 12) - { + else if(hour > 12) { hour -= 12; pm = true; } - hour = DECtoBCD(hour); //Convert to BCD + hour = dec_to_bcd(hour); // Convert to BCD - if (pm == true) hour |= (1 << HOURS_AM_PM); //Set AM/PM bit if needed + if(pm == true) hour |= (1 << HOURS_AM_PM); // Set AM/PM bit if needed - writeRegister(RV3028_HOURS, hour); //Record this to hours register + write_register(RV3028_HOURS, hour); // Record this to hours register } } - //Configure RTC to output 0-23 hours - //Converts any current hour setting to 24 hour - void RV3028::set24Hour() - { - //Do we need to change anything? - if (is12Hour() == true) - { - //Not sure what changing the CTRL2 register will do to hour register so let's get a copy - uint8_t hour = readRegister(RV3028_HOURS); //Get the current 12 hour formatted time in BCD + // Configure RTC to output 0-23 hours + // Converts any current hour setting to 24 hour + void RV3028::set_24_hour() { + // Do we need to change anything? + if(is_12_hour() == true) { + // Not sure what changing the CTRL2 register will do to hour register so let's get a copy + uint8_t hour = read_register(RV3028_HOURS); //Get the current 12 hour formatted time in BCD bool pm = false; - if (hour & (1 << HOURS_AM_PM)) //Is the AM/PM bit set? - { + if(hour & (1 << HOURS_AM_PM)) { // Is the AM/PM bit set? pm = true; - hour &= ~(1 << HOURS_AM_PM); //Clear the bit + hour &= ~(1 << HOURS_AM_PM); // Clear the bit } - //Change to 24 hour mode - uint8_t setting = readRegister(RV3028_CTRL2); - setting &= ~(1 << CTRL2_12_24); //Clear the 12/24 hr bit - writeRegister(RV3028_CTRL2, setting); + // Change to 24 hour mode + uint8_t setting = read_register(RV3028_CTRL2); + setting &= ~(1 << CTRL2_12_24); // Clear the 12/24 hr bit + write_register(RV3028_CTRL2, setting); - //Given a BCD hour in the 1-12 range, make it 24 - hour = BCDtoDEC(hour); //Convert core of register to DEC + // Given a BCD hour in the 1-12 range, make it 24 + hour = bcd_to_dec(hour); // Convert core of register to DEC - if (pm == true) hour += 12; //2PM becomes 14 - if (hour == 12) hour = 0; //12AM stays 12, but should really be 0 - if (hour == 24) hour = 12; //12PM becomes 24, but should really be 12 + if(pm == true) hour += 12; // 2PM becomes 14 + if(hour == 12) hour = 0; // 12AM stays 12, but should really be 0 + if(hour == 24) hour = 12; // 12PM becomes 24, but should really be 12 - hour = DECtoBCD(hour); //Convert to BCD + hour = dec_to_bcd(hour); // Convert to BCD - writeRegister(RV3028_HOURS, hour); //Record this to hours register + write_register(RV3028_HOURS, hour); // Record this to hours register } } - //ATTENTION: Real Time and UNIX Time are INDEPENDENT! - bool RV3028::setUNIX(uint32_t value) - { + // ATTENTION: Real Time and UNIX Time are INDEPENDENT! + bool RV3028::set_unix(uint32_t value) { uint8_t unix_reg[4]; unix_reg[0] = value; unix_reg[1] = value >> 8; unix_reg[2] = value >> 16; unix_reg[3] = value >> 24; - return writeMultipleRegisters(RV3028_UNIX_TIME0, unix_reg, 4); + return write_multiple_registers(RV3028_UNIX_TIME0, unix_reg, 4); } - //ATTENTION: Real Time and UNIX Time are INDEPENDENT! - uint32_t RV3028::getUNIX() - { + // ATTENTION: Real Time and UNIX Time are INDEPENDENT! + uint32_t RV3028::get_unix() { uint8_t unix_reg[4]; - readMultipleRegisters(RV3028_UNIX_TIME0, unix_reg, 4); + read_multiple_registers(RV3028_UNIX_TIME0, unix_reg, 4); return ((uint32_t)unix_reg[3] << 24) | ((uint32_t)unix_reg[2] << 16) | ((uint32_t)unix_reg[1] << 8) | unix_reg[0]; } @@ -409,197 +419,179 @@ namespace pimoroni { 7: All disabled � Default value If you want to set a weekday alarm (setWeekdayAlarm_not_Date = true), set 'date_or_weekday' from 0 (Sunday) to 6 (Saturday) ********************************/ - void RV3028::enableAlarmInterrupt(uint8_t min, uint8_t hour, uint8_t date_or_weekday, bool setWeekdayAlarm_not_Date, uint8_t mode, bool enable_clock_output) - { - //disable Alarm Interrupt to prevent accidental interrupts during configuration - disableAlarmInterrupt(); - clearAlarmInterruptFlag(); - - //ENHANCEMENT: Add Alarm in 12 hour mode - set24Hour(); - - //Set WADA bit (Weekday/Date Alarm) - if (setWeekdayAlarm_not_Date) - clearBit(RV3028_CTRL1, CTRL1_WADA); + void RV3028::enable_alarm_interrupt(uint8_t min, uint8_t hour, uint8_t date_or_weekday, bool set_weekday_alarm_not_date, uint8_t mode, bool enable_clock_output) { + // disable Alarm Interrupt to prevent accidental interrupts during configuration + disable_alarm_interrupt(); + clear_alarm_interrupt_flag(); + + // ENHANCEMENT: Add Alarm in 12 hour mode + set_24_hour(); + + // Set WADA bit (Weekday/Date Alarm) + if(set_weekday_alarm_not_date) + clear_bit(RV3028_CTRL1, CTRL1_WADA); else - setBit(RV3028_CTRL1, CTRL1_WADA); + set_bit(RV3028_CTRL1, CTRL1_WADA); - //Write alarm settings in registers 0x07 to 0x09 + // Write alarm settings in registers 0x07 to 0x09 uint8_t alarmTime[3]; - alarmTime[0] = DECtoBCD(min); //minutes - alarmTime[1] = DECtoBCD(hour); //hours - alarmTime[2] = DECtoBCD(date_or_weekday); //date or weekday - //shift alarm enable bits - if (mode > 0b111) mode = 0b111; //0 to 7 is valid - if (mode & 0b001) + alarmTime[0] = dec_to_bcd(min); //minutes + alarmTime[1] = dec_to_bcd(hour); //hours + alarmTime[2] = dec_to_bcd(date_or_weekday); //date or weekday + // shift alarm enable bits + if(mode > 0b111) + mode = 0b111; // 0 to 7 is valid + + if(mode & 0b001) alarmTime[0] |= 1 << MINUTESALM_AE_M; - if (mode & 0b010) + if(mode & 0b010) alarmTime[1] |= 1 << HOURSALM_AE_H; - if (mode & 0b100) + if(mode & 0b100) alarmTime[2] |= 1 << DATE_AE_WD; - //Write registers - writeMultipleRegisters(RV3028_MINUTES_ALM, alarmTime, 3); - //enable Alarm Interrupt - enableAlarmInterrupt(); + write_multiple_registers(RV3028_MINUTES_ALM, alarmTime, 3); - //Clock output? - if (enable_clock_output) - setBit(RV3028_INT_MASK, IMT_MASK_CAIE); + enable_alarm_interrupt(); + + // Clock output? + if(enable_clock_output) + set_bit(RV3028_INT_MASK, IMT_MASK_CAIE); else - clearBit(RV3028_INT_MASK, IMT_MASK_CAIE); + clear_bit(RV3028_INT_MASK, IMT_MASK_CAIE); } - void RV3028::enableAlarmInterrupt() - { - setBit(RV3028_CTRL2, CTRL2_AIE); + void RV3028::enable_alarm_interrupt() { + set_bit(RV3028_CTRL2, CTRL2_AIE); } - //Only disables the interrupt (not the alarm flag) - void RV3028::disableAlarmInterrupt() - { - clearBit(RV3028_CTRL2, CTRL2_AIE); + // Only disables the interrupt (not the alarm flag) + void RV3028::disable_alarm_interrupt() { + clear_bit(RV3028_CTRL2, CTRL2_AIE); } - bool RV3028::readAlarmInterruptFlag() - { - return readBit(RV3028_STATUS, STATUS_AF); + bool RV3028::read_alarm_interrupt_flag() { + return read_bit(RV3028_STATUS, STATUS_AF); } - void RV3028::clearAlarmInterruptFlag() - { - clearBit(RV3028_STATUS, STATUS_AF); + void RV3028::clear_alarm_interrupt_flag() { + clear_bit(RV3028_STATUS, STATUS_AF); } /********************************* Countdown Timer Interrupt ********************************/ - void RV3028::setTimer(bool timer_repeat, uint16_t timer_frequency, uint16_t timer_value, bool set_interrupt, bool start_timer, bool enable_clock_output) - { - disableTimer(); - disableTimerInterrupt(); - clearTimerInterruptFlag(); + void RV3028::set_timer(bool timer_repeat, uint16_t timer_frequency, uint16_t timer_value, bool set_interrupt, bool start_timer, bool enable_clock_output) { + disable_timer(); + disable_timer_interrupt(); + clear_timer_interrupt_flag(); - writeRegister(RV3028_TIMERVAL_0, timer_value & 0xff); - writeRegister(RV3028_TIMERVAL_1, timer_value >> 8); + write_register(RV3028_TIMERVAL_0, timer_value & 0xff); + write_register(RV3028_TIMERVAL_1, timer_value >> 8); - uint8_t ctrl1_val = readRegister(RV3028_CTRL1); - if (timer_repeat) { + uint8_t ctrl1_val = read_register(RV3028_CTRL1); + if(timer_repeat) { ctrl1_val |= 1 << CTRL1_TRPT; - } else { + } + else { ctrl1_val &= ~(1 << CTRL1_TRPT); } - switch (timer_frequency) { - case 4096: // 4096Hz (default) // up to 122us error on first time + + switch(timer_frequency) { + case 4096: // 4096Hz (default) // up to 122us error on first time ctrl1_val &= ~3; // Clear both the bits break; - case 64: // 64Hz // up to 7.813ms error on first time + case 64: // 64Hz // up to 7.813ms error on first time ctrl1_val &= ~3; // Clear both the bits ctrl1_val |= 1; break; - case 1: // 1Hz // up to 7.813ms error on first time + case 1: // 1Hz // up to 7.813ms error on first time ctrl1_val &= ~3; // Clear both the bits ctrl1_val |= 2; break; - case 60000: // 1/60Hz // up to 7.813ms error on first time + case 60000: // 1/60Hz // up to 7.813ms error on first time ctrl1_val |= 3; // Set both bits break; } - if (set_interrupt) { - enableTimerInterrupt(); + if(set_interrupt) { + enable_timer_interrupt(); } - if (start_timer) { + if(start_timer) { ctrl1_val |= (1 << CTRL1_TE); } - writeRegister(RV3028_CTRL1, ctrl1_val); + write_register(RV3028_CTRL1, ctrl1_val); - //Clock output? - if (enable_clock_output) - setBit(RV3028_INT_MASK, IMT_MASK_CTIE); + // Clock output? + if(enable_clock_output) + set_bit(RV3028_INT_MASK, IMT_MASK_CTIE); else - clearBit(RV3028_INT_MASK, IMT_MASK_CTIE); + clear_bit(RV3028_INT_MASK, IMT_MASK_CTIE); } - uint16_t RV3028::getTimerCount(void) - { + uint16_t RV3028::get_timer_count() { // Reads the number of remaining timer ticks - uint8_t r0 =readRegister(RV3028_TIMERSTAT_0); - return(r0 + (readRegister(RV3028_TIMERSTAT_1) << 8)); + uint8_t r0 = read_register(RV3028_TIMERSTAT_0); + return (r0 + (read_register(RV3028_TIMERSTAT_1) << 8)); } - void RV3028::enableTimerInterrupt() - { - setBit(RV3028_CTRL2, CTRL2_TIE); + void RV3028::enable_timer_interrupt() { + set_bit(RV3028_CTRL2, CTRL2_TIE); } - void RV3028::disableTimerInterrupt() - { - clearBit(RV3028_CTRL2, CTRL2_TIE); + void RV3028::disable_timer_interrupt() { + clear_bit(RV3028_CTRL2, CTRL2_TIE); } - bool RV3028::readTimerInterruptFlag() - { - return readBit(RV3028_STATUS, STATUS_TF); + bool RV3028::read_timer_interrupt_flag() { + return read_bit(RV3028_STATUS, STATUS_TF); } - void RV3028::clearTimerInterruptFlag() - { - clearBit(RV3028_STATUS, STATUS_TF); + void RV3028::clear_timer_interrupt_flag() { + clear_bit(RV3028_STATUS, STATUS_TF); } - void RV3028::enableTimer() - { - setBit(RV3028_CTRL1, CTRL1_TE); + void RV3028::enable_timer() { + set_bit(RV3028_CTRL1, CTRL1_TE); } - void RV3028::disableTimer() - { - clearBit(RV3028_CTRL1, CTRL1_TE); + void RV3028::disable_timer() { + clear_bit(RV3028_CTRL1, CTRL1_TE); } /********************************* Periodic Time Update Interrupt ********************************/ - void RV3028::enablePeriodicUpdateInterrupt(bool every_second, bool enable_clock_output) - { - disablePeriodicUpdateInterrupt(); - clearPeriodicUpdateInterruptFlag(); - - if (every_second) - { - clearBit(RV3028_CTRL1, CTRL1_USEL); - } - else - { // every minute - setBit(RV3028_CTRL1, CTRL1_USEL); - } + void RV3028::enable_periodic_update_interrupt(bool every_second, bool enable_clock_output) { + disable_periodic_update_interrupt(); + clear_periodic_update_interrupt_flag(); + + if(every_second) + clear_bit(RV3028_CTRL1, CTRL1_USEL); + else // every minute + set_bit(RV3028_CTRL1, CTRL1_USEL); - setBit(RV3028_CTRL2, CTRL2_UIE); + set_bit(RV3028_CTRL2, CTRL2_UIE); - //Clock output? - if (enable_clock_output) - setBit(RV3028_INT_MASK, IMT_MASK_CUIE); + // Clock output? + if(enable_clock_output) + set_bit(RV3028_INT_MASK, IMT_MASK_CUIE); else - clearBit(RV3028_INT_MASK, IMT_MASK_CUIE); + clear_bit(RV3028_INT_MASK, IMT_MASK_CUIE); } - void RV3028::disablePeriodicUpdateInterrupt() - { - clearBit(RV3028_CTRL2, CTRL2_UIE); + void RV3028::disable_periodic_update_interrupt() { + clear_bit(RV3028_CTRL2, CTRL2_UIE); } - bool RV3028::readPeriodicUpdateInterruptFlag() - { - return readBit(RV3028_STATUS, STATUS_UF); + bool RV3028::read_periodic_update_interrupt_flag() { + return read_bit(RV3028_STATUS, STATUS_UF); } - void RV3028::clearPeriodicUpdateInterruptFlag() - { - clearBit(RV3028_STATUS, STATUS_UF); + void RV3028::clear_periodic_update_interrupt_flag() { + clear_bit(RV3028_STATUS, STATUS_UF); } /********************************* @@ -609,29 +601,28 @@ namespace pimoroni { TCR_9K = 9kOhm TCR_15K = 15kOhm *********************************/ - void RV3028::enableTrickleCharge(uint8_t tcr) - { - if (tcr > 3) return; + void RV3028::enable_trickle_charge(uint8_t tcr) { + if(tcr > 3) + return; - //Read EEPROM Backup Register (0x37) - uint8_t EEPROMBackup = readConfigEEPROM_RAMmirror(EEPROM_Backup_Register); - //Set TCR Bits (Trickle Charge Resistor) - EEPROMBackup &= EEPROMBackup_TCR_CLEAR; //Clear TCR Bits - EEPROMBackup |= tcr << EEPROMBackup_TCR_SHIFT; //Shift values into EEPROM Backup Register - //Write 1 to TCE Bit - EEPROMBackup |= 1 << EEPROMBackup_TCE_BIT; - //Write EEPROM Backup Register - writeConfigEEPROM_RAMmirror(EEPROM_Backup_Register, EEPROMBackup); + // Read EEPROM Backup Register (0x37) + uint8_t eeprom_backup = read_config_eeprom_ram_mirror(EEPROM_Backup_Register); + // Set TCR Bits (Trickle Charge Resistor) + eeprom_backup &= EEPROMBackup_TCR_CLEAR; // Clear TCR Bits + eeprom_backup |= tcr << EEPROMBackup_TCR_SHIFT; // Shift values into EEPROM Backup Register + // Write 1 to TCE Bit + eeprom_backup |= 1 << EEPROMBackup_TCE_BIT; + // Write EEPROM Backup Register + write_config_eeprom_ram_mirror(EEPROM_Backup_Register, eeprom_backup); } - void RV3028::disableTrickleCharge() - { - //Read EEPROM Backup Register (0x37) - uint8_t EEPROMBackup = readConfigEEPROM_RAMmirror(EEPROM_Backup_Register); - //Write 0 to TCE Bit - EEPROMBackup &= ~(1 << EEPROMBackup_TCE_BIT); - //Write EEPROM Backup Register - writeConfigEEPROM_RAMmirror(EEPROM_Backup_Register, EEPROMBackup); + void RV3028::disable_trickle_charge() { + // Read EEPROM Backup Register (0x37) + uint8_t eeprom_backup = read_config_eeprom_ram_mirror(EEPROM_Backup_Register); + // Write 0 to TCE Bit + eeprom_backup &= ~(1 << EEPROMBackup_TCE_BIT); + // Write EEPROM Backup Register + write_config_eeprom_ram_mirror(EEPROM_Backup_Register, eeprom_backup); } @@ -641,21 +632,27 @@ namespace pimoroni { 2 = Standby Mode 3 = Level Switching Mode *********************************/ - bool RV3028::setBackupSwitchoverMode(uint8_t val) - { - if (val > 3)return false; + bool RV3028::set_backup_switchover_mode(uint8_t val) { + if(val > 3) + return false; + bool success = true; - //Read EEPROM Backup Register (0x37) - uint8_t EEPROMBackup = readConfigEEPROM_RAMmirror(EEPROM_Backup_Register); - if (EEPROMBackup == 0xFF) success = false; - //Ensure FEDE Bit is set to 1 - EEPROMBackup |= 1 << EEPROMBackup_FEDE_BIT; - //Set BSM Bits (Backup Switchover Mode) - EEPROMBackup &= EEPROMBackup_BSM_CLEAR; //Clear BSM Bits of EEPROM Backup Register - EEPROMBackup |= val << EEPROMBackup_BSM_SHIFT; //Shift values into EEPROM Backup Register - //Write EEPROM Backup Register - if (!writeConfigEEPROM_RAMmirror(EEPROM_Backup_Register, EEPROMBackup)) success = false; + // Read EEPROM Backup Register (0x37) + uint8_t eeprom_backup = read_config_eeprom_ram_mirror(EEPROM_Backup_Register); + if(eeprom_backup == 0xFF) + success = false; + + // Ensure FEDE Bit is set to 1 + eeprom_backup |= 1 << EEPROMBackup_FEDE_BIT; + + // Set BSM Bits (Backup Switchover Mode) + eeprom_backup &= EEPROMBackup_BSM_CLEAR; // Clear BSM Bits of EEPROM Backup Register + eeprom_backup |= val << EEPROMBackup_BSM_SHIFT; // Shift values into EEPROM Backup Register + + // Write EEPROM Backup Register + if(!write_config_eeprom_ram_mirror(EEPROM_Backup_Register, eeprom_backup)) + success = false; return success; } @@ -664,228 +661,224 @@ namespace pimoroni { /********************************* Clock Out functions ********************************/ - void RV3028::enableClockOut(uint8_t freq) - { - if (freq > 7) return; // check out of bounds - //Read EEPROM CLKOUT Register (0x35) - uint8_t EEPROMClkout = readConfigEEPROM_RAMmirror(EEPROM_Clkout_Register); - //Ensure CLKOE Bit is set to 1 - EEPROMClkout |= 1 << EEPROMClkout_CLKOE_BIT; - //Shift values into EEPROM Backup Register - EEPROMClkout |= freq << EEPROMClkout_FREQ_SHIFT; - //Write EEPROM Backup Register - writeConfigEEPROM_RAMmirror(EEPROM_Clkout_Register, EEPROMClkout); - } - - void RV3028::enableInterruptControlledClockout(uint8_t freq) - { - if (freq > 7) return; // check out of bounds - //Read EEPROM CLKOUT Register (0x35) - uint8_t EEPROMClkout = readConfigEEPROM_RAMmirror(EEPROM_Clkout_Register); - //Shift values into EEPROM Backup Register - EEPROMClkout |= freq << EEPROMClkout_FREQ_SHIFT; - //Write EEPROM Backup Register - writeConfigEEPROM_RAMmirror(EEPROM_Clkout_Register, EEPROMClkout); + void RV3028::enable_clock_out(uint8_t freq) { + if(freq > 7) + return; // check out of bounds - //Set CLKIE Bit - setBit(RV3028_CTRL2, CTRL2_CLKIE); + // Read EEPROM CLKOUT Register (0x35) + uint8_t eeprom_clkout = read_config_eeprom_ram_mirror(EEPROM_Clkout_Register); + // Ensure CLKOE Bit is set to 1 + eeprom_clkout |= 1 << EEPROMClkout_CLKOE_BIT; + // Shift values into EEPROM Backup Register + eeprom_clkout |= freq << EEPROMClkout_FREQ_SHIFT; + // Write EEPROM Backup Register + write_config_eeprom_ram_mirror(EEPROM_Clkout_Register, eeprom_clkout); } - void RV3028::disableClockOut() - { - //Read EEPROM CLKOUT Register (0x35) - uint8_t EEPROMClkout = readConfigEEPROM_RAMmirror(EEPROM_Clkout_Register); - //Clear CLKOE Bit - EEPROMClkout &= ~(1 << EEPROMClkout_CLKOE_BIT); - //Write EEPROM CLKOUT Register - writeConfigEEPROM_RAMmirror(EEPROM_Clkout_Register, EEPROMClkout); + void RV3028::enable_interrupt_controlled_clockout(uint8_t freq) { + if(freq > 7) + return; // check out of bounds - //Clear CLKIE Bit - clearBit(RV3028_CTRL2, CTRL2_CLKIE); - } + // Read EEPROM CLKOUT Register (0x35) + uint8_t eeprom_clkout = read_config_eeprom_ram_mirror(EEPROM_Clkout_Register); + // Shift values into EEPROM Backup Register + eeprom_clkout |= freq << EEPROMClkout_FREQ_SHIFT; + // Write EEPROM Backup Register + write_config_eeprom_ram_mirror(EEPROM_Clkout_Register, eeprom_clkout); - bool RV3028::readClockOutputInterruptFlag() - { - return readBit(RV3028_STATUS, STATUS_CLKF); + // Set CLKIE Bit + set_bit(RV3028_CTRL2, CTRL2_CLKIE); } - void RV3028::clearClockOutputInterruptFlag() - { - clearBit(RV3028_STATUS, STATUS_CLKF); - } + void RV3028::disable_clock_out() { + // Read EEPROM CLKOUT Register (0x35) + uint8_t eeprom_clkout = read_config_eeprom_ram_mirror(EEPROM_Clkout_Register); + // Clear CLKOE Bit + eeprom_clkout &= ~(1 << EEPROMClkout_CLKOE_BIT); + // Write EEPROM CLKOUT Register + write_config_eeprom_ram_mirror(EEPROM_Clkout_Register, eeprom_clkout); - - //Returns the status byte - uint8_t RV3028::status(void) - { - return(readRegister(RV3028_STATUS)); + // Clear CLKIE Bit + clear_bit(RV3028_CTRL2, CTRL2_CLKIE); } - void RV3028::clearInterrupts() //Read the status register to clear the current interrupt flags - { - writeRegister(RV3028_STATUS, 0); + bool RV3028::read_clock_output_interrupt_flag() { + return read_bit(RV3028_STATUS, STATUS_CLKF); } - - - - // i2c functions - - int RV3028::write_bytes(uint8_t reg, uint8_t *buf, int len) { - uint8_t buffer[len + 1]; - buffer[0] = reg; - for(int x = 0; x < len; x++) { - buffer[x + 1] = buf[x]; - } - return i2c_write_blocking(i2c, address, buffer, len + 1, false); - }; - - int RV3028::read_bytes(uint8_t reg, uint8_t *buf, int len) { - i2c_write_blocking(i2c, address, ®, 1, true); - i2c_read_blocking(i2c, address, buf, len, false); - return len; - }; - - uint8_t RV3028::get_bits(uint8_t reg, uint8_t shift, uint8_t mask) { - uint8_t value; - this->read_bytes(reg, &value, 1); - return value & (mask << shift); + void RV3028::clear_clock_output_interrupt_flag() { + clear_bit(RV3028_STATUS, STATUS_CLKF); } - void RV3028::set_bits(uint8_t reg, uint8_t shift, uint8_t mask) { - uint8_t value; - this->read_bytes(reg, &value, 1); - value |= mask << shift; - this->write_bytes(reg, &value, 1); + // Returns the status byte + uint8_t RV3028::status(void) { + return(read_register(RV3028_STATUS)); } - void RV3028::clear_bits(uint8_t reg, uint8_t shift, uint8_t mask) { - uint8_t value; - this->read_bytes(reg, &value, 1); - value &= ~(mask << shift); - this->write_bytes(reg, &value, 1); + void RV3028::clear_interrupts() { // Read the status register to clear the current interrupt flags + write_register(RV3028_STATUS, 0); } /********************************* FOR INTERNAL USE ********************************/ - uint8_t RV3028::BCDtoDEC(uint8_t val) - { + uint8_t RV3028::bcd_to_dec(uint8_t val) { return ((val / 0x10) * 10) + (val % 0x10); } // BCDtoDEC -- convert decimal to binary-coded decimal (BCD) - uint8_t RV3028::DECtoBCD(uint8_t val) - { + uint8_t RV3028::dec_to_bcd(uint8_t val) { return ((val / 10) * 0x10) + (val % 10); } - uint8_t RV3028::readRegister(uint8_t addr) - { + uint8_t RV3028::read_register(uint8_t addr) { uint8_t b1[2]; - if ( 1 == RV3028::read_bytes(addr, b1, 1)) { + if(1 == RV3028::read_bytes(addr, b1, 1)) return b1[0]; - } else { - return (0xFF); //Error - } + else + return 0xFF; //Error } - bool RV3028::writeRegister(uint8_t addr, uint8_t val) - { + bool RV3028::write_register(uint8_t addr, uint8_t val) { uint8_t b1[2]; b1[0] = val; b1[1] = 0; return(RV3028::write_bytes(addr, b1, 1)); } - bool RV3028::readMultipleRegisters(uint8_t addr, uint8_t * dest, uint8_t len) - { + bool RV3028::read_multiple_registers(uint8_t addr, uint8_t *dest, uint8_t len) { return(RV3028::read_bytes(addr, dest, len)); } - bool RV3028::writeMultipleRegisters(uint8_t addr, uint8_t * values, uint8_t len) - { + bool RV3028::write_multiple_registers(uint8_t addr, uint8_t *values, uint8_t len) { return(RV3028::write_bytes(addr, values, len)); } - bool RV3028::writeConfigEEPROM_RAMmirror(uint8_t eepromaddr, uint8_t val) - { - bool success = waitforEEPROM(); + bool RV3028::write_config_eeprom_ram_mirror(uint8_t eeprom_addr, uint8_t val) { + bool success = wait_for_eeprom(); - //Disable auto refresh by writing 1 to EERD control bit in CTRL1 register - uint8_t ctrl1 = readRegister(RV3028_CTRL1); + // Disable auto refresh by writing 1 to EERD control bit in CTRL1 register + uint8_t ctrl1 = read_register(RV3028_CTRL1); ctrl1 |= 1 << CTRL1_EERD; - if (!writeRegister(RV3028_CTRL1, ctrl1)) success = false; - //Write Configuration RAM Register - writeRegister(eepromaddr, val); - //Update EEPROM (All Configuration RAM -> EEPROM) - writeRegister(RV3028_EEPROM_CMD, EEPROMCMD_First); - writeRegister(RV3028_EEPROM_CMD, EEPROMCMD_Update); - if (!waitforEEPROM()) success = false; - //Reenable auto refresh by writing 0 to EERD control bit in CTRL1 register - ctrl1 = readRegister(RV3028_CTRL1); - if (ctrl1 == 0x00)success = false; + + if(!write_register(RV3028_CTRL1, ctrl1)) + success = false; + + // Write Configuration RAM Register + write_register(eeprom_addr, val); + + // Update EEPROM (All Configuration RAM -> EEPROM) + write_register(RV3028_EEPROM_CMD, EEPROMCMD_First); + write_register(RV3028_EEPROM_CMD, EEPROMCMD_Update); + + if(!wait_for_eeprom()) + success = false; + + // Reenable auto refresh by writing 0 to EERD control bit in CTRL1 register + ctrl1 = read_register(RV3028_CTRL1); + if(ctrl1 == 0x00) + success = false; + ctrl1 &= ~(1 << CTRL1_EERD); - writeRegister(RV3028_CTRL1, ctrl1); - if (!waitforEEPROM()) success = false; + write_register(RV3028_CTRL1, ctrl1); + + if(!wait_for_eeprom()) + success = false; return success; } - uint8_t RV3028::readConfigEEPROM_RAMmirror(uint8_t eepromaddr) - { - bool success = waitforEEPROM(); + uint8_t RV3028::read_config_eeprom_ram_mirror(uint8_t eeprom_addr) { + bool success = wait_for_eeprom(); - //Disable auto refresh by writing 1 to EERD control bit in CTRL1 register - uint8_t ctrl1 = readRegister(RV3028_CTRL1); + // Disable auto refresh by writing 1 to EERD control bit in CTRL1 register + uint8_t ctrl1 = read_register(RV3028_CTRL1); ctrl1 |= 1 << CTRL1_EERD; - if (!writeRegister(RV3028_CTRL1, ctrl1)) success = false; - //Read EEPROM Register - writeRegister(RV3028_EEPROM_ADDR, eepromaddr); - writeRegister(RV3028_EEPROM_CMD, EEPROMCMD_First); - writeRegister(RV3028_EEPROM_CMD, EEPROMCMD_ReadSingle); - if (!waitforEEPROM()) success = false; - uint8_t eepromdata = readRegister(RV3028_EEPROM_DATA); - if (!waitforEEPROM()) success = false; - //Reenable auto refresh by writing 0 to EERD control bit in CTRL1 register - ctrl1 = readRegister(RV3028_CTRL1); - if (ctrl1 == 0x00)success = false; + if(!write_register(RV3028_CTRL1, ctrl1)) + success = false; + + // Read EEPROM Register + write_register(RV3028_EEPROM_ADDR, eeprom_addr); + write_register(RV3028_EEPROM_CMD, EEPROMCMD_First); + write_register(RV3028_EEPROM_CMD, EEPROMCMD_ReadSingle); + + if(!wait_for_eeprom()) + success = false; + + uint8_t eeprom_data = read_register(RV3028_EEPROM_DATA); + if(!wait_for_eeprom()) + success = false; + + // Reenable auto refresh by writing 0 to EERD control bit in CTRL1 register + ctrl1 = read_register(RV3028_CTRL1); + if(ctrl1 == 0x00) + success = false; + ctrl1 &= ~(1 << CTRL1_EERD); - writeRegister(RV3028_CTRL1, ctrl1); + write_register(RV3028_CTRL1, ctrl1); - if (!success) return 0xFF; - return eepromdata; + if(!success) + return 0xFF; + + return eeprom_data; } - //True if success, false if timeout occured - bool RV3028::waitforEEPROM() - { + // True if success, false if timeout occured + bool RV3028::wait_for_eeprom() { // Timeout is number of loops round while - don't have access to millisecond counter unsigned long timeout = 500; - while ((readRegister(RV3028_STATUS) & 1 << STATUS_EEBUSY) && --timeout > 0); + while ((read_register(RV3028_STATUS) & 1 << STATUS_EEBUSY) && --timeout > 0); return timeout > 0; } - void RV3028::reset() - { - setBit(RV3028_CTRL2, CTRL2_RESET); - } - - void RV3028::setBit(uint8_t reg_addr, uint8_t bit_num) - { + void RV3028::set_bit(uint8_t reg_addr, uint8_t bit_num) { RV3028::set_bits(reg_addr, bit_num, 0x01); } - void RV3028::clearBit(uint8_t reg_addr, uint8_t bit_num) - { + void RV3028::clear_bit(uint8_t reg_addr, uint8_t bit_num) { RV3028::clear_bits(reg_addr, bit_num, 0x01); } - bool RV3028::readBit(uint8_t reg_addr, uint8_t bit_num) - { + bool RV3028::read_bit(uint8_t reg_addr, uint8_t bit_num) { uint8_t value = RV3028::get_bits(reg_addr, bit_num, 0x01); return value; } -} + // i2c functions + int RV3028::write_bytes(uint8_t reg, uint8_t *buf, int len) { + uint8_t buffer[len + 1]; + buffer[0] = reg; + for(int x = 0; x < len; x++) { + buffer[x + 1] = buf[x]; + } + return i2c_write_blocking(i2c, address, buffer, len + 1, false); + }; + + int RV3028::read_bytes(uint8_t reg, uint8_t *buf, int len) { + i2c_write_blocking(i2c, address, ®, 1, true); + i2c_read_blocking(i2c, address, buf, len, false); + return len; + }; + + uint8_t RV3028::get_bits(uint8_t reg, uint8_t shift, uint8_t mask) { + uint8_t value; + read_bytes(reg, &value, 1); + return value & (mask << shift); + } + + void RV3028::set_bits(uint8_t reg, uint8_t shift, uint8_t mask) { + uint8_t value; + read_bytes(reg, &value, 1); + value |= mask << shift; + write_bytes(reg, &value, 1); + } + + void RV3028::clear_bits(uint8_t reg, uint8_t shift, uint8_t mask) { + uint8_t value; + read_bytes(reg, &value, 1); + value &= ~(mask << shift); + write_bytes(reg, &value, 1); + } + +} \ No newline at end of file diff --git a/drivers/rv3028/rv3028.hpp b/drivers/rv3028/rv3028.hpp index 10c8010c0..4ef2f1ec6 100644 --- a/drivers/rv3028/rv3028.hpp +++ b/drivers/rv3028/rv3028.hpp @@ -18,160 +18,162 @@ Distributed as-is; no warranty is given. #include #include "pico/stdlib.h" -//The 7-bit I2C ADDRESS of the RV3028 -#define RV3028_ADDR 0x52 +// The 7-bit I2C ADDRESS of the RV3028 +#define RV3028_ADDR 0x52 -//REGISTERS -//Clock registers +// REGISTERS +// Clock registers #define RV3028_SECONDS 0x00 #define RV3028_MINUTES 0x01 #define RV3028_HOURS 0x02 -//Calendar registers -#define RV3028_WEEKDAY 0x03 +// Calendar registers +#define RV3028_WEEKDAY 0x03 #define RV3028_DATE 0x04 #define RV3028_MONTHS 0x05 #define RV3028_YEARS 0x06 -//Alarm registers +// Alarm registers #define RV3028_MINUTES_ALM 0x07 #define RV3028_HOURS_ALM 0x08 #define RV3028_DATE_ALM 0x09 -//Periodic Countdown Timer registers -#define RV3028_TIMERVAL_0 0x0A -#define RV3028_TIMERVAL_1 0x0B -#define RV3028_TIMERSTAT_0 0x0C -#define RV3028_TIMERSTAT_1 0x0D +// Periodic Countdown Timer registers +#define RV3028_TIMERVAL_0 0x0A +#define RV3028_TIMERVAL_1 0x0B +#define RV3028_TIMERSTAT_0 0x0C +#define RV3028_TIMERSTAT_1 0x0D -//Configuration registers -#define RV3028_STATUS 0x0E +// Configuration registers +#define RV3028_STATUS 0x0E #define RV3028_CTRL1 0x0F #define RV3028_CTRL2 0x10 -#define RV3028_GPBITS 0x11 -#define RV3028_INT_MASK 0x12 - -//Eventcontrol/Timestamp registers -#define RV3028_EVENTCTRL 0x13 -#define RV3028_COUNT_TS 0x14 -#define RV3028_SECONDS_TS 0x15 -#define RV3028_MINUTES_TS 0x16 -#define RV3028_HOURS_TS 0x17 -#define RV3028_DATE_TS 0x18 -#define RV3028_MONTH_TS 0x19 -#define RV3028_YEAR_TS 0x1A - -//Unix Time registers -#define RV3028_UNIX_TIME0 0x1B -#define RV3028_UNIX_TIME1 0x1C -#define RV3028_UNIX_TIME2 0x1D -#define RV3028_UNIX_TIME3 0x1E - -//RAM registers -#define RV3028_USER_RAM1 0x1F -#define RV3028_USER_RAM2 0x20 - -//Password registers -#define RV3028_PASSWORD0 0x21 -#define RV3028_PASSWORD1 0x22 -#define RV3028_PASSWORD2 0x23 -#define RV3028_PASSWORD3 0x24 - -//EEPROM Memory Control registers -#define RV3028_EEPROM_ADDR 0x25 -#define RV3028_EEPROM_DATA 0x26 -#define RV3028_EEPROM_CMD 0x27 - -//ID register -#define RV3028_ID 0x28 - -//EEPROM Registers -#define EEPROM_Clkout_Register 0x35 -#define RV3028_EEOffset_8_1 0x36 //bits 8 to 1 of EEOffset. Bit 0 is bit 7 of register 0x37 -#define EEPROM_Backup_Register 0x37 - - -//BITS IN IMPORTANT REGISTERS - -//Bits in Status Register -#define STATUS_EEBUSY 7 -#define STATUS_CLKF 6 +#define RV3028_GPBITS 0x11 +#define RV3028_INT_MASK 0x12 + +// Eventcontrol/Timestamp registers +#define RV3028_EVENTCTRL 0x13 +#define RV3028_COUNT_TS 0x14 +#define RV3028_SECONDS_TS 0x15 +#define RV3028_MINUTES_TS 0x16 +#define RV3028_HOURS_TS 0x17 +#define RV3028_DATE_TS 0x18 +#define RV3028_MONTH_TS 0x19 +#define RV3028_YEAR_TS 0x1A + +// Unix Time registers +#define RV3028_UNIX_TIME0 0x1B +#define RV3028_UNIX_TIME1 0x1C +#define RV3028_UNIX_TIME2 0x1D +#define RV3028_UNIX_TIME3 0x1E + +// RAM registers +#define RV3028_USER_RAM1 0x1F +#define RV3028_USER_RAM2 0x20 + +// Password registers +#define RV3028_PASSWORD0 0x21 +#define RV3028_PASSWORD1 0x22 +#define RV3028_PASSWORD2 0x23 +#define RV3028_PASSWORD3 0x24 + +// EEPROM Memory Control registers +#define RV3028_EEPROM_ADDR 0x25 +#define RV3028_EEPROM_DATA 0x26 +#define RV3028_EEPROM_CMD 0x27 + +// ID register +#define RV3028_ID 0x28 +#define RV3028_CHIP_ID 0x30 +#define RV3028_VERSION 0x03 + +// EEPROM Registers +#define EEPROM_Clkout_Register 0x35 +#define RV3028_EEOffset_8_1 0x36 // bits 8 to 1 of EEOffset. Bit 0 is bit 7 of register 0x37 +#define EEPROM_Backup_Register 0x37 + + +// BITS IN IMPORTANT REGISTERS + +// Bits in Status Register +#define STATUS_EEBUSY 7 +#define STATUS_CLKF 6 #define STATUS_BSF 5 -#define STATUS_UF 4 -#define STATUS_TF 3 -#define STATUS_AF 2 +#define STATUS_UF 4 +#define STATUS_TF 3 +#define STATUS_AF 2 #define STATUS_EVF 1 -#define STATUS_PORF 0 +#define STATUS_PORF 0 -//Bits in Control1 Register +// Bits in Control1 Register #define CTRL1_TRPT 7 -#define CTRL1_WADA 5//Bit 6 not implemented +#define CTRL1_WADA 5 // Bit 6 not implemented #define CTRL1_USEL 4 #define CTRL1_EERD 3 -#define CTRL1_TE 2 -#define CTRL1_TD1 1 -#define CTRL1_TD0 0 - -//Bits in Control2 Register -#define CTRL2_TSE 7 -#define CTRL2_CLKIE 6 -#define CTRL2_UIE 5 -#define CTRL2_TIE 4 -#define CTRL2_AIE 3 -#define CTRL2_EIE 2 -#define CTRL2_12_24 1 -#define CTRL2_RESET 0 - -//Bits in Hours register -#define HOURS_AM_PM 5 - -//Bits in Alarm registers -#define MINUTESALM_AE_M 7 -#define HOURSALM_AE_H 7 +#define CTRL1_TE 2 +#define CTRL1_TD1 1 +#define CTRL1_TD0 0 + +// Bits in Control2 Register +#define CTRL2_TSE 7 +#define CTRL2_CLKIE 6 +#define CTRL2_UIE 5 +#define CTRL2_TIE 4 +#define CTRL2_AIE 3 +#define CTRL2_EIE 2 +#define CTRL2_12_24 1 +#define CTRL2_RESET 0 + +// Bits in Hours register +#define HOURS_AM_PM 5 + +// Bits in Alarm registers +#define MINUTESALM_AE_M 7 +#define HOURSALM_AE_H 7 #define DATE_AE_WD 7 -//Commands for EEPROM Command Register (0x27) -#define EEPROMCMD_First 0x00 -#define EEPROMCMD_Update 0x11 +// Commands for EEPROM Command Register (0x27) +#define EEPROMCMD_First 0x00 +#define EEPROMCMD_Update 0x11 #define EEPROMCMD_Refresh 0x12 -#define EEPROMCMD_WriteSingle 0x21 -#define EEPROMCMD_ReadSingle 0x22 +#define EEPROMCMD_WriteSingle 0x21 +#define EEPROMCMD_ReadSingle 0x22 -//Bits in EEPROM Backup Register -#define EEPROMBackup_TCE_BIT 5 //Trickle Charge Enable Bit -#define EEPROMBackup_FEDE_BIT 4 //Fast Edge Detection Enable Bit (for Backup Switchover Mode) -#define EEPROMBackup_BSM_SHIFT 2 //Backup Switchover Mode shift -#define EEPROMBackup_TCR_SHIFT 0 //Trickle Charge Resistor shift +// Bits in EEPROM Backup Register +#define EEPROMBackup_TCE_BIT 5 // Trickle Charge Enable Bit +#define EEPROMBackup_FEDE_BIT 4 // Fast Edge Detection Enable Bit (for Backup Switchover Mode) +#define EEPROMBackup_BSM_SHIFT 2 // Backup Switchover Mode shift +#define EEPROMBackup_TCR_SHIFT 0 // Trickle Charge Resistor shift -#define EEPROMBackup_BSM_CLEAR 0b11110011 //Backup Switchover Mode clear -#define EEPROMBackup_TCR_CLEAR 0b11111100 //Trickle Charge Resistor clear -#define TCR_3K 0b00 //Trickle Charge Resistor 3kOhm -#define TCR_5K 0b01 //Trickle Charge Resistor 5kOhm -#define TCR_9K 0b10 //Trickle Charge Resistor 9kOhm -#define TCR_15K 0b11 //Trickle Charge Resistor 15kOhm +#define EEPROMBackup_BSM_CLEAR 0b11110011 // Backup Switchover Mode clear +#define EEPROMBackup_TCR_CLEAR 0b11111100 // Trickle Charge Resistor clear +#define TCR_3K 0b00 // Trickle Charge Resistor 3kOhm +#define TCR_5K 0b01 // Trickle Charge Resistor 5kOhm +#define TCR_9K 0b10 // Trickle Charge Resistor 9kOhm +#define TCR_15K 0b11 // Trickle Charge Resistor 15kOhm // Clock output register (0x35) -#define EEPROMClkout_CLKOE_BIT 7 //1 = CLKOUT pin is enabled. – Default value on delivery -#define EEPROMClkout_CLKSY_BIT 6 +#define EEPROMClkout_CLKOE_BIT 7 // 1 = CLKOUT pin is enabled. – Default value on delivery +#define EEPROMClkout_CLKSY_BIT 6 // Bits 5 and 4 not implemented -#define EEPROMClkout_PORIE 3 //0 = No interrupt, or canceled, signal on INT pin at POR. – Default value on delivery - //1 = An interrupt signal on INT pin at POR. Retained until the PORF flag is cleared to 0 (no automatic cancellation). -#define EEPROMClkout_FREQ_SHIFT 0 //frequency shift -#define FD_CLKOUT_32k 0b000 //32.768 kHz – Default value on delivery -#define FD_CLKOUT_8192 0b001 //8192 Hz -#define FD_CLKOUT_1024 0b010 //1024 Hz -#define FD_CLKOUT_64 0b011 //64 Hz -#define FD_CLKOUT_32 0b100 //32 Hz -#define FD_CLKOUT_1 0b101 //1 Hz -#define FD_CLKOUT_TIMER 0b110 //Predefined periodic countdown timer interrupt -#define FD_CLKOUT_LOW 0b111 //CLKOUT = LOW +#define EEPROMClkout_PORIE 3 // 0 = No interrupt, or canceled, signal on INT pin at POR. – Default value on delivery + // 1 = An interrupt signal on INT pin at POR. Retained until the PORF flag is cleared to 0 (no automatic cancellation). +#define EEPROMClkout_FREQ_SHIFT 0 // frequency shift +#define FD_CLKOUT_32k 0b000 // 32.768 kHz – Default value on delivery +#define FD_CLKOUT_8192 0b001 // 8192 Hz +#define FD_CLKOUT_1024 0b010 // 1024 Hz +#define FD_CLKOUT_64 0b011 // 64 Hz +#define FD_CLKOUT_32 0b100 // 32 Hz +#define FD_CLKOUT_1 0b101 // 1 Hz +#define FD_CLKOUT_TIMER 0b110 // Predefined periodic countdown timer interrupt +#define FD_CLKOUT_LOW 0b111 // CLKOUT = LOW -#define IMT_MASK_CEIE 3 //Clock output when Event Interrupt bit. -#define IMT_MASK_CAIE 2 //Clock output when Alarm Interrupt bit. -#define IMT_MASK_CTIE 1 //Clock output when Periodic Countdown Timer Interrupt bit. -#define IMT_MASK_CUIE 0 //Clock output when Periodic Time Update Interrupt bit. +#define IMT_MASK_CEIE 3 // Clock output when Event Interrupt bit. +#define IMT_MASK_CAIE 2 // Clock output when Alarm Interrupt bit. +#define IMT_MASK_CTIE 1 // Clock output when Periodic Countdown Timer Interrupt bit. +#define IMT_MASK_CUIE 0 // Clock output when Periodic Time Update Interrupt bit. #define TIME_ARRAY_LENGTH 7 // Total number of writable values in device @@ -179,131 +181,160 @@ Distributed as-is; no warranty is given. namespace pimoroni { enum time_order { - TIME_SECONDS, // 0 - TIME_MINUTES, // 1 - TIME_HOURS, // 2 - TIME_WEEKDAY, // 3 - TIME_DATE, // 4 - TIME_MONTH, // 5 - TIME_YEAR, // 6 + TIME_SECONDS, // 0 + TIME_MINUTES, // 1 + TIME_HOURS, // 2 + TIME_WEEKDAY, // 3 + TIME_DATE, // 4 + TIME_MONTH, // 5 + TIME_YEAR, // 6 }; - class RV3028 - { + class RV3028 { + //-------------------------------------------------- + // Constants + //-------------------------------------------------- + public: + static const uint8_t DEFAULT_I2C_ADDRESS = RV3028_ADDR; + static const uint8_t DEFAULT_SDA_PIN = 20; + static const uint8_t DEFAULT_SCL_PIN = 21; + static const uint8_t DEFAULT_INT_PIN = 22; + static const uint8_t PIN_UNUSED = UINT8_MAX; + + + //-------------------------------------------------- + // Variables + //-------------------------------------------------- + private: i2c_inst_t *i2c = i2c0; + // interface pins with our standard defaults where appropriate - int8_t sda = 20; - int8_t scl = 21; - int8_t interrupt = 22; - public: - RV3028() {} - - RV3028(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt) : - i2c(i2c), sda(sda), scl(scl), interrupt(interrupt) {} - - void init(); - - bool setup(bool set_24Hour = true, bool disable_TrickleCharge = true, bool set_LevelSwitchingMode = true); - bool setTime(uint8_t sec, uint8_t min, uint8_t hour, uint8_t weekday, uint8_t date, uint8_t month, uint16_t year); - bool setTime(uint8_t * time, uint8_t len); - bool setSeconds(uint8_t value); - bool setMinutes(uint8_t value); - bool setHours(uint8_t value); - bool setWeekday(uint8_t value); - bool setDate(uint8_t value); - bool setMonth(uint8_t value); - bool setYear(uint16_t value); - bool setToCompilerTime(); //Uses the hours, mins, etc from compile time to set RTC - - bool updateTime() ; //Update the local array with the RTC registers - - char* stringDateUSA(); //Return date in mm-dd-yyyy - char* stringDate(); //Return date in dd-mm-yyyy - char* stringTime(); //Return time hh:mm:ss with AM/PM if in 12 hour mode - char* stringTimeStamp(); //Return timeStamp in ISO 8601 format yyyy-mm-ddThh:mm:ss - - uint8_t getSeconds(); - uint8_t getMinutes(); - uint8_t getHours(); - uint8_t getWeekday(); - uint8_t getDate(); - uint8_t getMonth(); - uint16_t getYear(); - - - bool is12Hour(); //Returns true if 12hour bit is set - bool isPM(); //Returns true if is12Hour and PM bit is set - void set12Hour(); - void set24Hour(); - - bool setUNIX(uint32_t value);//Set the UNIX Time (Real Time and UNIX Time are INDEPENDENT!) - uint32_t getUNIX(); - - void enableAlarmInterrupt(uint8_t min, uint8_t hour, uint8_t date_or_weekday, bool setWeekdayAlarm_not_Date, uint8_t mode, bool enable_clock_output = false); - void enableAlarmInterrupt(); - void disableAlarmInterrupt(); - bool readAlarmInterruptFlag(); - void clearAlarmInterruptFlag(); - - void setTimer(bool timer_repeat, uint16_t timer_frequency, uint16_t timer_value, bool setInterrupt, bool start_timer, bool enable_clock_output = false); - uint16_t getTimerCount(void); - void enableTimer(); - void disableTimer(); - void enableTimerInterrupt(); - void disableTimerInterrupt(); - bool readTimerInterruptFlag(); - void clearTimerInterruptFlag(); - - void enablePeriodicUpdateInterrupt(bool every_second, bool enable_clock_output = false); - void disablePeriodicUpdateInterrupt(); - bool readPeriodicUpdateInterruptFlag(); - void clearPeriodicUpdateInterruptFlag(); - - void enableTrickleCharge(uint8_t tcr = TCR_15K); //Trickle Charge Resistor default 15k - void disableTrickleCharge(); - bool setBackupSwitchoverMode(uint8_t val); - - void enableClockOut(uint8_t freq); - void enableInterruptControlledClockout(uint8_t freq); - void disableClockOut(); - bool readClockOutputInterruptFlag(); - void clearClockOutputInterruptFlag(); - - uint8_t status(); //Returns the status byte - void clearInterrupts(); - - //Values in RTC are stored in Binary Coded Decimal. These functions convert to/from Decimal - uint8_t BCDtoDEC(uint8_t val); - uint8_t DECtoBCD(uint8_t val); - - uint8_t readRegister(uint8_t addr); - bool writeRegister(uint8_t addr, uint8_t val); - bool readMultipleRegisters(uint8_t addr, uint8_t * dest, uint8_t len); - bool writeMultipleRegisters(uint8_t addr, uint8_t * values, uint8_t len); - - bool writeConfigEEPROM_RAMmirror(uint8_t eepromaddr, uint8_t val); - uint8_t readConfigEEPROM_RAMmirror(uint8_t eepromaddr); - bool waitforEEPROM(); - void reset(); - - void setBit(uint8_t reg_addr, uint8_t bit_num); - void clearBit(uint8_t reg_addr, uint8_t bit_num); - bool readBit(uint8_t reg_addr, uint8_t bit_num); - private: - uint8_t _time[TIME_ARRAY_LENGTH]; - i2c_inst_t *_i2cPort; - int8_t address = RV3028_ADDR; - - // From i2cdevice - int write_bytes(uint8_t reg, uint8_t *buf, int len); - int read_bytes(uint8_t reg, uint8_t *buf, int len); - uint8_t get_bits(uint8_t reg, uint8_t shift, uint8_t mask=0b1); - void set_bits(uint8_t reg, uint8_t shift, uint8_t mask=0b1); - void clear_bits(uint8_t reg, uint8_t shift, uint8_t mask=0b1); + int8_t address = DEFAULT_I2C_ADDRESS; + int8_t sda = DEFAULT_SDA_PIN; + int8_t scl = DEFAULT_SCL_PIN; + int8_t interrupt = DEFAULT_INT_PIN; + + uint8_t times[TIME_ARRAY_LENGTH]; + + + //-------------------------------------------------- + // Constructors/Destructor + //-------------------------------------------------- + public: + RV3028() {} + + RV3028(i2c_inst_t *i2c, uint8_t sda, uint8_t scl, uint8_t interrupt = PIN_UNUSED) : + i2c(i2c), sda(sda), scl(scl), interrupt(interrupt) {} + + + //-------------------------------------------------- + // Methods + //-------------------------------------------------- + public: + bool init(); + void reset(); + + i2c_inst_t* get_i2c() const; + int get_sda() const; + int get_scl() const; + int get_int() const; + + bool setup(bool set_24Hour = true, bool disable_TrickleCharge = true, bool set_LevelSwitchingMode = true); + bool set_time(uint8_t sec, uint8_t min, uint8_t hour, uint8_t weekday, uint8_t date, uint8_t month, uint16_t year); + bool set_time(uint8_t *time, uint8_t len); + bool set_seconds(uint8_t value); + bool set_minutes(uint8_t value); + bool set_hours(uint8_t value); + bool set_weekday(uint8_t value); + bool set_date(uint8_t value); + bool set_month(uint8_t value); + bool set_year(uint16_t value); + bool set_to_compiler_time(); // Uses the hours, mins, etc from compile time to set RTC + + bool update_time(); // Update the local array with the RTC registers + + char* string_date_usa(); // Return date in mm-dd-yyyy + char* string_date(); // Return date in dd-mm-yyyy + char* string_time(); // Return time hh:mm:ss with AM/PM if in 12 hour mode + char* string_time_stamp(); // Return timeStamp in ISO 8601 format yyyy-mm-ddThh:mm:ss + + uint8_t get_seconds(); + uint8_t get_minutes(); + uint8_t get_hours(); + uint8_t get_weekday(); + uint8_t get_date(); + uint8_t get_month(); + uint16_t get_year(); + + bool is_12_hour(); // Returns true if 12hour bit is set + bool is_pm(); // Returns true if is12Hour and PM bit is set + void set_12_hour(); + void set_24_hour(); + + bool set_unix(uint32_t value); // Set the UNIX Time (Real Time and UNIX Time are INDEPENDENT!) + uint32_t get_unix(); + + void enable_alarm_interrupt(uint8_t min, uint8_t hour, uint8_t date_or_weekday, bool set_weekday_alarm_not_date, uint8_t mode, bool enable_clock_output = false); + void enable_alarm_interrupt(); + void disable_alarm_interrupt(); + bool read_alarm_interrupt_flag(); + void clear_alarm_interrupt_flag(); + + void set_timer(bool timer_repeat, uint16_t timer_frequency, uint16_t timer_value, bool set_interrupt, bool start_timer, bool enable_clock_output = false); + uint16_t get_timer_count(); + void enable_timer(); + void disable_timer(); + void enable_timer_interrupt(); + void disable_timer_interrupt(); + bool read_timer_interrupt_flag(); + void clear_timer_interrupt_flag(); + + void enable_periodic_update_interrupt(bool every_second, bool enable_clock_output = false); + void disable_periodic_update_interrupt(); + bool read_periodic_update_interrupt_flag(); + void clear_periodic_update_interrupt_flag(); + + void enable_trickle_charge(uint8_t tcr = TCR_15K); // Trickle Charge Resistor default 15k + void disable_trickle_charge(); + bool set_backup_switchover_mode(uint8_t val); + + void enable_clock_out(uint8_t freq); + void enable_interrupt_controlled_clockout(uint8_t freq); + void disable_clock_out(); + bool read_clock_output_interrupt_flag(); + void clear_clock_output_interrupt_flag(); + + uint8_t status(); // Returns the status byte + void clear_interrupts(); + +private: + // Values in RTC are stored in Binary Coded Decimal. These functions convert to/from Decimal + uint8_t bcd_to_dec(uint8_t val); + uint8_t dec_to_bcd(uint8_t val); + + uint8_t read_register(uint8_t addr); + bool write_register(uint8_t addr, uint8_t val); + bool read_multiple_registers(uint8_t addr, uint8_t *dest, uint8_t len); + bool write_multiple_registers(uint8_t addr, uint8_t *values, uint8_t len); + + bool write_config_eeprom_ram_mirror(uint8_t eepromaddr, uint8_t val); + uint8_t read_config_eeprom_ram_mirror(uint8_t eepromaddr); + bool wait_for_eeprom(); + + void set_bit(uint8_t reg_addr, uint8_t bit_num); + void clear_bit(uint8_t reg_addr, uint8_t bit_num); + bool read_bit(uint8_t reg_addr, uint8_t bit_num); + + // From i2cdevice + int write_bytes(uint8_t reg, uint8_t *buf, int len); + int read_bytes(uint8_t reg, uint8_t *buf, int len); + uint8_t get_bits(uint8_t reg, uint8_t shift, uint8_t mask = 0b1); + void set_bits(uint8_t reg, uint8_t shift, uint8_t mask = 0b1); + void clear_bits(uint8_t reg, uint8_t shift, uint8_t mask = 0b1); }; - //POSSIBLE ENHANCEMENTS : - //ENHANCEMENT: Battery Interrupt / check battery voltage - //ENHANCEMENT: External Event Interrupt + // POSSIBLE ENHANCEMENTS : + // ENHANCEMENT: Battery Interrupt / check battery voltage + // ENHANCEMENT: External Event Interrupt } diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 18bb4c935..156f45d0d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(breakout_rgbmatrix5x5) add_subdirectory(breakout_matrix11x7) add_subdirectory(breakout_mics6814) add_subdirectory(breakout_potentiometer) +add_subdirectory(breakout_rtc) add_subdirectory(breakout_trackball) add_subdirectory(breakout_sgp30) add_subdirectory(breakout_colourlcd240x240) diff --git a/examples/breakout_rtc/CMakeLists.txt b/examples/breakout_rtc/CMakeLists.txt new file mode 100644 index 000000000..70c13b2ed --- /dev/null +++ b/examples/breakout_rtc/CMakeLists.txt @@ -0,0 +1,16 @@ +set(OUTPUT_NAME rtc_demo) + +add_executable( + ${OUTPUT_NAME} + demo.cpp +) + +# enable usb output, disable uart output +pico_enable_stdio_usb(${OUTPUT_NAME} 1) +pico_enable_stdio_uart(${OUTPUT_NAME} 0) + +# Pull in pico libraries that we need +target_link_libraries(${OUTPUT_NAME} pico_stdlib breakout_rtc) + +# create map/bin/hex file etc. +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/breakout_rtc/demo.cpp b/examples/breakout_rtc/demo.cpp new file mode 100644 index 000000000..f8d8c1786 --- /dev/null +++ b/examples/breakout_rtc/demo.cpp @@ -0,0 +1,47 @@ +#include "pico/stdlib.h" + +#include "breakout_rtc.hpp" + +using namespace pimoroni; + +BreakoutRTC rtc; + +int main() { + stdio_init_all(); + + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + + if(!rtc.init()) { + printf("Init failed! Check your connections and i2c pin choices.\n"); + } + // rtc.setup(false); + + // Uncomment the below line on first run to set the RTC date and time to the program's compiler time + // rtc.set_to_compiler_time(); + + // Make sure we have 24-hour time + if(rtc.is_12_hour()) + rtc.set_24_hour(); + + // Set to update once per second + rtc.enable_periodic_update_interrupt(true); + + while(true) { + // Has a second passed? + if(rtc.read_periodic_update_interrupt_flag()) { + rtc.clear_periodic_update_interrupt_flag(); + + // Update the locally stored time from the RTC + if(rtc.update_time()) { + printf("Date: %s, Time: %s\n", rtc.string_date(), rtc.string_time()); + gpio_put(PICO_DEFAULT_LED_PIN, true); + sleep_ms(100); + gpio_put(PICO_DEFAULT_LED_PIN, false); + } + } + sleep_ms(100); + } + + return 0; +} diff --git a/examples/pico_rtc_display/CMakeLists.txt b/examples/pico_rtc_display/CMakeLists.txt index 50726a17b..8f03ce481 100644 --- a/examples/pico_rtc_display/CMakeLists.txt +++ b/examples/pico_rtc_display/CMakeLists.txt @@ -1,10 +1,12 @@ +set(OUTPUT_NAME rtc_display) + add_executable( - rtc_display + ${OUTPUT_NAME} demo.cpp ) # Pull in pico libraries that we need -target_link_libraries(rtc_display pico_stdlib pico_explorer pico_display rv3028) +target_link_libraries(${OUTPUT_NAME} pico_stdlib pico_explorer pico_display breakout_rtc) # create map/bin/hex file etc. -pico_add_extra_outputs(rtc_display) +pico_add_extra_outputs(${OUTPUT_NAME}) diff --git a/examples/pico_rtc_display/demo.cpp b/examples/pico_rtc_display/demo.cpp index d0613d80e..266d70b8b 100644 --- a/examples/pico_rtc_display/demo.cpp +++ b/examples/pico_rtc_display/demo.cpp @@ -25,7 +25,7 @@ #else #include "pico_display.hpp" #endif -#include "rv3028.hpp" +#include "breakout_rtc.hpp" #define MODE_DISP_CLOCK 0 #define MODE_DISP_TIMER 1 @@ -47,15 +47,17 @@ uint16_t screen_width = PicoDisplay::WIDTH; uint16_t screen_height = PicoDisplay::HEIGHT; #endif -RV3028 rv3028; +BreakoutRTC rtc; #define LOW_COUNT_MOD 40 #define HIGH_COUNT_MOD 20 + bool repeat_count_reached(uint16_t curr_count) { // Check whether the current counter means that a key has repeated - if (curr_count <= 10*LOW_COUNT_MOD) { + if(curr_count <= 10*LOW_COUNT_MOD) { return (0 == (curr_count % LOW_COUNT_MOD)); - } else { + } + else { return (0 == (curr_count % HIGH_COUNT_MOD)); } } @@ -65,10 +67,11 @@ void flash_led(uint32_t curr_count) { // Flash the LED based on the current loop counter // curr_count=0 will turn LED off #ifndef USE_PICO_EXPLORER - if ((curr_count % FLASH_MOD) < (FLASH_MOD / 2)) { + if((curr_count % FLASH_MOD) < (FLASH_MOD / 2)) { // value less than half modded number - LED off pico_display.set_led(0, 0, 0); - } else { + } + else { // value more than half modded number - LED on pico_display.set_led(128, 128, 128); } @@ -78,11 +81,12 @@ void flash_led(uint32_t curr_count) { int main() { pico_display.init(); - rv3028.init(); - // rv3028.setup(false); + rtc.init(); + // rtc.setup(false); - // Make sure we have 24-hour time (smaller dsplay!) - if (rv3028.is12Hour()) rv3028.set24Hour(); + // Make sure we have 24-hour time (smaller display!) + if(rtc.is_12_hour()) + rtc.set_24_hour(); // Use these variables to make the buttons single-shot // Counts number of loops pressed, 0 if not pressed @@ -108,71 +112,80 @@ int main() { while(true) { - if (a_pressed == 0 && pico_display.is_pressed(pico_display.A)) { + if(a_pressed == 0 && pico_display.is_pressed(pico_display.A)) { a_pressed = 1; - if (display_mode == MODE_DISP_CLOCK) { + if(display_mode == MODE_DISP_CLOCK) { // We were displaying clock = set up timer display_mode = MODE_SET_TIMER; - } else if (display_mode == MODE_SET_TIMER) { + } + else if(display_mode == MODE_SET_TIMER) { // We were setting up the timer - run it - rv3028.setTimer(false, 1, timer_count, true, true, false); + rtc.set_timer(false, 1, timer_count, true, true, false); display_mode = MODE_DISP_TIMER; - } else if (display_mode == MODE_DISP_TIMER) { + } + else if(display_mode == MODE_DISP_TIMER) { // We were running the timer - go back to setting up - if (0 == (timer_count = rv3028.getTimerCount())) { + if(0 == (timer_count = rtc.get_timer_count())) { timer_count = DEFAULT_TIMER_COUNT; } - rv3028.disableTimerInterrupt(); - rv3028.disableTimer(); - rv3028.clearTimerInterruptFlag(); + rtc.disable_timer_interrupt(); + rtc.disable_timer(); + rtc.clear_timer_interrupt_flag(); display_mode = MODE_SET_TIMER; } - } else if (a_pressed >= 1 && !pico_display.is_pressed(pico_display.A)) { + } + else if(a_pressed >= 1 && !pico_display.is_pressed(pico_display.A)) { a_pressed = 0; } - if (b_pressed == 0 && pico_display.is_pressed(pico_display.B)) { + if(b_pressed == 0 && pico_display.is_pressed(pico_display.B)) { b_pressed = 1; - if ((display_mode == MODE_DISP_TIMER) + if((display_mode == MODE_DISP_TIMER) || (display_mode == MODE_SET_TIMER)) { // We were setting or displaying timer - revert to clock - rv3028.disableTimerInterrupt(); - rv3028.disableTimer(); - rv3028.clearTimerInterruptFlag(); + rtc.disable_timer_interrupt(); + rtc.disable_timer(); + rtc.clear_timer_interrupt_flag(); display_mode = MODE_DISP_CLOCK; timer_count = DEFAULT_TIMER_COUNT; } - } else if (b_pressed >= 1 && !pico_display.is_pressed(pico_display.B)) { + } + else if(b_pressed >= 1 && !pico_display.is_pressed(pico_display.B)) { b_pressed = 0; } - if (x_pressed == 0 && pico_display.is_pressed(pico_display.X)) { + if(x_pressed == 0 && pico_display.is_pressed(pico_display.X)) { x_pressed = 1; - if (display_mode == MODE_SET_TIMER) { + if(display_mode == MODE_SET_TIMER) { // Setting timer - Increment count timer_count++; } - } else if (x_pressed >= 1 && pico_display.is_pressed(pico_display.X)) { + } + else if(x_pressed >= 1 && pico_display.is_pressed(pico_display.X)) { // Button still pressed - check if has reached repeat count - if (repeat_count_reached(x_pressed++)) { + if(repeat_count_reached(x_pressed++)) { timer_count++; } - } else if (x_pressed >= 1 && !pico_display.is_pressed(pico_display.X)) { + } + else if(x_pressed >= 1 && !pico_display.is_pressed(pico_display.X)) { x_pressed = 0; } - if (y_pressed == 0 && pico_display.is_pressed(pico_display.Y)) { + if(y_pressed == 0 && pico_display.is_pressed(pico_display.Y)) { y_pressed = 1; - if (display_mode == MODE_SET_TIMER) { + if(display_mode == MODE_SET_TIMER) { // Setting timer - Decrement count if (timer_count >= 1) timer_count--; } - } else if (y_pressed >= 1 && pico_display.is_pressed(pico_display.Y)) { + } + else if(y_pressed >= 1 && pico_display.is_pressed(pico_display.Y)) { // Button still pressed - check if has reached repeat count - if (repeat_count_reached(y_pressed++)) { - if (timer_count >= 1) timer_count--; + if(repeat_count_reached(y_pressed++)) { + if(timer_count >= 1) + timer_count--; } - } else if (y_pressed >= 1 && !pico_display.is_pressed(pico_display.Y)) { + } + else if(y_pressed >= 1 && !pico_display.is_pressed(pico_display.Y)) { y_pressed = 0; } @@ -182,32 +195,34 @@ int main() { // text_box.deflate(10); pico_display.set_clip(text_box); pico_display.set_pen(255, 255, 255); - switch (display_mode) { + switch(display_mode) { case MODE_DISP_CLOCK: // Show the clock face flash_led(0); - if (rv3028.updateTime()) { + if(rtc.update_time()) { pico_display.text("Set Timer", Point(text_box.x, text_box.y+2), 230, 1); pico_display.set_pen(0, 255, 0); - pico_display.text(rv3028.stringDate(), + pico_display.text(rtc.string_date(), Point(text_box.x, text_box.y+20), 230, 4); pico_display.set_pen(255, 0, 0); - pico_display.text(rv3028.stringTime(), + pico_display.text(rtc.string_time(), Point(text_box.x, text_box.y+60), 230, 6); pico_display.set_pen(255, 255, 255); pico_display.text("Clock", Point(text_box.x, text_box.y+screen_height-20), 230, 1); - } else { - sprintf(buf, "Time: rv3028.updateTime() ret err"); + } + else { + sprintf(buf, "Time: rtc.updateTime() ret err"); pico_display.text(buf, Point(text_box.x, text_box.y), 30, 2); } break; + case MODE_DISP_TIMER: pico_display.text("Set Timer", Point(text_box.x, text_box.y+2), 230, 1); - if (rv3028.readTimerInterruptFlag()) { + if(rtc.read_timer_interrupt_flag()) { // Go periodic time interupt - say loop ended pico_display.set_pen(255, 0, 0); sprintf(buf, "%s", "Timer complete"); @@ -215,14 +230,16 @@ int main() { Point(text_box.x, text_box.y+30), 230, 4); pico_display.set_pen(255, 255, 255); flash_led(i); - } else { - sprintf(buf, "%s %d", "Timer running", rv3028.getTimerCount()); + } + else { + sprintf(buf, "%s %d", "Timer running", rtc.get_timer_count()); pico_display.text(buf, Point(text_box.x, text_box.y+30), 230, 3); } pico_display.text("Clock", Point(text_box.x, text_box.y+screen_height-20), 230, 1); break; + case MODE_SET_TIMER: flash_led(0); pico_display.text("Run Timer", @@ -248,5 +265,5 @@ int main() { i++; } - return 0; + return 0; } diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 197851e97..ae8ffd384 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(breakout_rgbmatrix5x5) add_subdirectory(breakout_matrix11x7) add_subdirectory(breakout_mics6814) add_subdirectory(breakout_potentiometer) +add_subdirectory(breakout_rtc) add_subdirectory(breakout_trackball) add_subdirectory(breakout_sgp30) add_subdirectory(breakout_as7262) diff --git a/libraries/breakout_rtc/CMakeLists.txt b/libraries/breakout_rtc/CMakeLists.txt new file mode 100644 index 000000000..5fb1ebf4c --- /dev/null +++ b/libraries/breakout_rtc/CMakeLists.txt @@ -0,0 +1 @@ +include(breakout_rtc.cmake) diff --git a/libraries/breakout_rtc/breakout_rtc.cmake b/libraries/breakout_rtc/breakout_rtc.cmake new file mode 100644 index 000000000..3752f4213 --- /dev/null +++ b/libraries/breakout_rtc/breakout_rtc.cmake @@ -0,0 +1,11 @@ +set(LIB_NAME breakout_rtc) +add_library(${LIB_NAME} INTERFACE) + +target_sources(${LIB_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp +) + +target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib rv3028) diff --git a/libraries/breakout_rtc/breakout_rtc.cpp b/libraries/breakout_rtc/breakout_rtc.cpp new file mode 100644 index 000000000..a76531b8c --- /dev/null +++ b/libraries/breakout_rtc/breakout_rtc.cpp @@ -0,0 +1,5 @@ +#include "breakout_rtc.hpp" + +namespace pimoroni { + +} diff --git a/libraries/breakout_rtc/breakout_rtc.hpp b/libraries/breakout_rtc/breakout_rtc.hpp new file mode 100644 index 000000000..722db95cb --- /dev/null +++ b/libraries/breakout_rtc/breakout_rtc.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../../drivers/rv3028/rv3028.hpp" + +namespace pimoroni { + + typedef RV3028 BreakoutRTC; +} diff --git a/micropython/examples/breakout_rtc/demo.py b/micropython/examples/breakout_rtc/demo.py new file mode 100644 index 000000000..e0bf227d4 --- /dev/null +++ b/micropython/examples/breakout_rtc/demo.py @@ -0,0 +1,17 @@ +from breakout_rtc import BreakoutRTC + +rtc = BreakoutRTC() + +if rtc.is_12_hour(): + rtc.set_24_hour() + +rtc.enable_periodic_update_interrupt(True) + +while True: + if rtc.read_periodic_update_interrupt_flag(): + rtc.clear_periodic_update_interrupt_flag() + + if rtc.update_time(): + date = rtc.string_date() + time = rtc.string_time() + print("Date: ", date, ", Time: ", time, sep="") diff --git a/micropython/modules/breakout_rtc/breakout_rtc.c b/micropython/modules/breakout_rtc/breakout_rtc.c new file mode 100644 index 000000000..82661b14a --- /dev/null +++ b/micropython/modules/breakout_rtc/breakout_rtc.c @@ -0,0 +1,167 @@ +#include "breakout_rtc.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// BreakoutRTC Class +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Methods *****/ +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_reset_obj, BreakoutRTC_reset); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_setup_obj, BreakoutRTC_setup); + +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_time_obj, 8, BreakoutRTC_set_time); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_seconds_obj, 2, BreakoutRTC_set_seconds); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_minutes_obj, 2, BreakoutRTC_set_minutes); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_hours_obj, 2, BreakoutRTC_set_hours); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_weekday_obj, 2, BreakoutRTC_set_weekday); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_date_obj, 2, BreakoutRTC_set_date); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_month_obj, 2, BreakoutRTC_set_month); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_year_obj, 2, BreakoutRTC_set_year); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_set_to_compiler_time_obj, BreakoutRTC_set_to_compiler_time); + +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_update_time_obj, BreakoutRTC_update_time); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_string_date_usa_obj, BreakoutRTC_string_date_usa); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_string_date_obj, BreakoutRTC_string_date); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_string_time_obj, BreakoutRTC_string_time); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_string_time_stamp_obj, BreakoutRTC_string_time_stamp); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_get_seconds_obj, BreakoutRTC_get_seconds); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_get_minutes_obj, BreakoutRTC_get_minutes); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_get_hours_obj, BreakoutRTC_get_hours); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_get_weekday_obj, BreakoutRTC_get_weekday); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_get_date_obj, BreakoutRTC_get_date); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_get_month_obj, BreakoutRTC_get_month); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_get_year_obj, BreakoutRTC_get_year); + +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_is_12_hour_obj, BreakoutRTC_is_12_hour); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_is_pm_obj, BreakoutRTC_is_pm); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_set_12_hour_obj, BreakoutRTC_set_12_hour); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_set_24_hour_obj, BreakoutRTC_set_24_hour); + +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_unix_obj, 2, BreakoutRTC_set_unix); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_get_unix_obj, BreakoutRTC_get_unix); + +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_enable_alarm_interrupt_obj, 6, BreakoutRTC_enable_alarm_interrupt); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_disable_alarm_interrupt_obj, BreakoutRTC_disable_alarm_interrupt); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_read_alarm_interrupt_flag_obj, BreakoutRTC_read_alarm_interrupt_flag); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_clear_alarm_interrupt_flag_obj, BreakoutRTC_clear_alarm_interrupt_flag); + +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_timer_obj, 6, BreakoutRTC_set_timer); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_get_timer_count_obj, BreakoutRTC_get_timer_count); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_enable_timer_obj, BreakoutRTC_enable_timer); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_disable_timer_obj, BreakoutRTC_disable_timer); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_enable_timer_interupt_obj, BreakoutRTC_enable_timer_interupt); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_disable_timer_interrupt_obj, BreakoutRTC_disable_timer_interrupt); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_read_timer_interrupt_flag_obj, BreakoutRTC_read_timer_interrupt_flag); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_clear_timer_interrupt_flag_obj, BreakoutRTC_clear_timer_interrupt_flag); + +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_enable_periodic_update_interrupt_obj, 2, BreakoutRTC_enable_periodic_update_interrupt); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_disable_periodic_update_interrupt_obj, BreakoutRTC_disable_periodic_update_interrupt); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_read_periodic_update_interrupt_flag_obj, BreakoutRTC_read_periodic_update_interrupt_flag); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_clear_periodic_update_interrupt_flag_obj, BreakoutRTC_clear_periodic_update_interrupt_flag); + +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_enable_trickle_charge_obj, 2, BreakoutRTC_enable_trickle_charge); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_disable_trickle_charge_obj, BreakoutRTC_disable_trickle_charge); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_set_backup_switchover_mode_obj, 2, BreakoutRTC_set_backup_switchover_mode); + +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_enable_clock_out_obj, 2, BreakoutRTC_enable_clock_out); +MP_DEFINE_CONST_FUN_OBJ_KW(BreakoutRTC_enable_interrupt_controlled_clockout_obj, 2, BreakoutRTC_enable_interrupt_controlled_clockout); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_disable_clock_out_obj, BreakoutRTC_disable_clock_out); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_read_clock_output_interrupt_flag_obj, BreakoutRTC_read_clock_output_interrupt_flag); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_clear_clock_output_interrupt_flag_obj, BreakoutRTC_clear_clock_output_interrupt_flag); + +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_status_obj, BreakoutRTC_status); +MP_DEFINE_CONST_FUN_OBJ_1(BreakoutRTC_clear_interrupts_obj, BreakoutRTC_clear_interrupts); + +/***** Binding of Methods *****/ +STATIC const mp_rom_map_elem_t BreakoutRTC_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&BreakoutRTC_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_setup), MP_ROM_PTR(&BreakoutRTC_setup_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_time), MP_ROM_PTR(&BreakoutRTC_set_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_seconds), MP_ROM_PTR(&BreakoutRTC_set_seconds_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_minutes), MP_ROM_PTR(&BreakoutRTC_set_minutes_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_hours), MP_ROM_PTR(&BreakoutRTC_set_hours_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_weekday), MP_ROM_PTR(&BreakoutRTC_set_weekday_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_date), MP_ROM_PTR(&BreakoutRTC_set_date_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_month), MP_ROM_PTR(&BreakoutRTC_set_month_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_year), MP_ROM_PTR(&BreakoutRTC_set_year_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_to_compiler_time), MP_ROM_PTR(&BreakoutRTC_set_to_compiler_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_update_time), MP_ROM_PTR(&BreakoutRTC_update_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_string_date_usa), MP_ROM_PTR(&BreakoutRTC_string_date_usa_obj) }, + { MP_ROM_QSTR(MP_QSTR_string_date), MP_ROM_PTR(&BreakoutRTC_string_date_obj) }, + { MP_ROM_QSTR(MP_QSTR_string_time), MP_ROM_PTR(&BreakoutRTC_string_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_string_time_stamp), MP_ROM_PTR(&BreakoutRTC_string_time_stamp_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_seconds), MP_ROM_PTR(&BreakoutRTC_get_seconds_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_minutes), MP_ROM_PTR(&BreakoutRTC_get_minutes_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_hours), MP_ROM_PTR(&BreakoutRTC_get_hours_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_weekday), MP_ROM_PTR(&BreakoutRTC_get_weekday_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_date), MP_ROM_PTR(&BreakoutRTC_get_date_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_month), MP_ROM_PTR(&BreakoutRTC_get_month_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_year), MP_ROM_PTR(&BreakoutRTC_get_year_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_12_hour), MP_ROM_PTR(&BreakoutRTC_is_12_hour_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_pm), MP_ROM_PTR(&BreakoutRTC_is_pm_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_12_hour), MP_ROM_PTR(&BreakoutRTC_set_12_hour_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_24_hour), MP_ROM_PTR(&BreakoutRTC_set_24_hour_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_unix), MP_ROM_PTR(&BreakoutRTC_set_unix_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_unix), MP_ROM_PTR(&BreakoutRTC_get_unix_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_alarm_interrupt), MP_ROM_PTR(&BreakoutRTC_enable_alarm_interrupt_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_alarm_interrupt), MP_ROM_PTR(&BreakoutRTC_disable_alarm_interrupt_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_alarm_interrupt_flag), MP_ROM_PTR(&BreakoutRTC_read_alarm_interrupt_flag_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_alarm_interrupt_flag), MP_ROM_PTR(&BreakoutRTC_clear_alarm_interrupt_flag_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_timer), MP_ROM_PTR(&BreakoutRTC_set_timer_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_timer_count), MP_ROM_PTR(&BreakoutRTC_get_timer_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_timer), MP_ROM_PTR(&BreakoutRTC_enable_timer_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_timer), MP_ROM_PTR(&BreakoutRTC_disable_timer_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_timer_interrupt), MP_ROM_PTR(&BreakoutRTC_enable_timer_interupt_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_timer_interrupt), MP_ROM_PTR(&BreakoutRTC_disable_timer_interrupt_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_timer_interrupt_flag), MP_ROM_PTR(&BreakoutRTC_read_timer_interrupt_flag_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_timer_interrupt_flag), MP_ROM_PTR(&BreakoutRTC_clear_timer_interrupt_flag_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_periodic_update_interrupt), MP_ROM_PTR(&BreakoutRTC_enable_periodic_update_interrupt_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_periodic_update_interrupt), MP_ROM_PTR(&BreakoutRTC_disable_periodic_update_interrupt_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_periodic_update_interrupt_flag), MP_ROM_PTR(&BreakoutRTC_read_periodic_update_interrupt_flag_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_periodic_update_interrupt_flag), MP_ROM_PTR(&BreakoutRTC_clear_periodic_update_interrupt_flag_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_trickle_charge), MP_ROM_PTR(&BreakoutRTC_enable_trickle_charge_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_trickle_charge), MP_ROM_PTR(&BreakoutRTC_disable_trickle_charge_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_backup_switchover_mode), MP_ROM_PTR(&BreakoutRTC_set_backup_switchover_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_clock_out), MP_ROM_PTR(&BreakoutRTC_enable_clock_out_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_interrupt_controlled_clockout), MP_ROM_PTR(&BreakoutRTC_enable_interrupt_controlled_clockout_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_clock_out), MP_ROM_PTR(&BreakoutRTC_disable_clock_out_obj) }, + { MP_ROM_QSTR(MP_QSTR_read_clock_output_interrupt_flag), MP_ROM_PTR(&BreakoutRTC_read_clock_output_interrupt_flag_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_clock_output_interrupt_flag), MP_ROM_PTR(&BreakoutRTC_clear_clock_output_interrupt_flag_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_status), MP_ROM_PTR(&BreakoutRTC_status_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear_interrupts), MP_ROM_PTR(&BreakoutRTC_clear_interrupts_obj) }, + { MP_ROM_QSTR(MP_QSTR_TCR_3K), MP_ROM_INT(MP_TCR_3K) }, + { MP_ROM_QSTR(MP_QSTR_TCR_5K), MP_ROM_INT(MP_TCR_5K) }, + { MP_ROM_QSTR(MP_QSTR_TCR_9K), MP_ROM_INT(MP_TCR_9K) }, + { MP_ROM_QSTR(MP_QSTR_TCR_15K), MP_ROM_INT(MP_TCR_15K) }, +}; +STATIC MP_DEFINE_CONST_DICT(BreakoutRTC_locals_dict, BreakoutRTC_locals_dict_table); + +/***** Class Definition *****/ +const mp_obj_type_t breakout_rtc_BreakoutRTC_type = { + { &mp_type_type }, + .name = MP_QSTR_breakout_rtc, + .print = BreakoutRTC_print, + .make_new = BreakoutRTC_make_new, + .locals_dict = (mp_obj_dict_t*)&BreakoutRTC_locals_dict, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// breakout_rtc Module +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/***** Globals Table *****/ +STATIC const mp_map_elem_t breakout_rtc_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_breakout_rtc) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BreakoutRTC), (mp_obj_t)&breakout_rtc_BreakoutRTC_type }, +}; +STATIC MP_DEFINE_CONST_DICT(mp_module_breakout_rtc_globals, breakout_rtc_globals_table); + +/***** Module Definition *****/ +const mp_obj_module_t breakout_rtc_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_breakout_rtc_globals, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +MP_REGISTER_MODULE(MP_QSTR_breakout_rtc, breakout_rtc_user_cmodule, MODULE_BREAKOUT_RTC_ENABLED); +//////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/micropython/modules/breakout_rtc/breakout_rtc.cpp b/micropython/modules/breakout_rtc/breakout_rtc.cpp new file mode 100644 index 000000000..027b38c4e --- /dev/null +++ b/micropython/modules/breakout_rtc/breakout_rtc.cpp @@ -0,0 +1,765 @@ +#include "../../../libraries/breakout_rtc/breakout_rtc.hpp" +#include +#include + +#define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) + +// SDA/SCL on even/odd pins, I2C0/I2C1 on even/odd pairs of pins. +#define IS_VALID_SCL(i2c, pin) (((pin) & 1) == 1 && (((pin) & 2) >> 1) == (i2c)) +#define IS_VALID_SDA(i2c, pin) (((pin) & 1) == 0 && (((pin) & 2) >> 1) == (i2c)) + + +using namespace pimoroni; + + +extern "C" { +#include "breakout_rtc.h" + +/***** Variables Struct *****/ +typedef struct _breakout_rtc_BreakoutRTC_obj_t { + mp_obj_base_t base; + BreakoutRTC *breakout; +} breakout_rtc_BreakoutRTC_obj_t; + +/***** Print *****/ +void BreakoutRTC_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; //Unused input parameter + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + BreakoutRTC* breakout = self->breakout; + mp_print_str(print, "BreakoutRTC("); + + mp_print_str(print, "i2c = "); + mp_obj_print_helper(print, mp_obj_new_int((breakout->get_i2c() == i2c0) ? 0 : 1), PRINT_REPR); + + mp_print_str(print, ", sda = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_sda()), PRINT_REPR); + + mp_print_str(print, ", scl = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_scl()), PRINT_REPR); + + mp_print_str(print, ", int = "); + mp_obj_print_helper(print, mp_obj_new_int(breakout->get_int()), PRINT_REPR); + + mp_print_str(print, ")"); +} + +/***** Constructor *****/ +mp_obj_t BreakoutRTC_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + breakout_rtc_BreakoutRTC_obj_t *self = nullptr; + + if(n_args == 0) { + mp_arg_check_num(n_args, n_kw, 0, 0, true); + self = m_new_obj(breakout_rtc_BreakoutRTC_obj_t); + self->base.type = &breakout_rtc_BreakoutRTC_type; + self->breakout = new BreakoutRTC(); + } + else { + enum { ARG_i2c, ARG_sda, ARG_scl, ARG_interrupt }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_interrupt, MP_ARG_INT, {.u_int = BreakoutRTC::PIN_UNUSED} }, + }; + + // Parse args. + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Get I2C bus. + int i2c_id = args[ARG_i2c].u_int; + if(i2c_id < 0 || i2c_id > 1) { + mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("I2C(%d) doesn't exist"), i2c_id); + } + + int sda = args[ARG_sda].u_int; + if (!IS_VALID_SDA(i2c_id, sda)) { + mp_raise_ValueError(MP_ERROR_TEXT("bad SDA pin")); + } + + int scl = args[ARG_scl].u_int; + if (!IS_VALID_SCL(i2c_id, scl)) { + mp_raise_ValueError(MP_ERROR_TEXT("bad SCL pin")); + } + + self = m_new_obj(breakout_rtc_BreakoutRTC_obj_t); + self->base.type = &breakout_rtc_BreakoutRTC_type; + + i2c_inst_t *i2c = (i2c_id == 0) ? i2c0 : i2c1; + self->breakout = new BreakoutRTC(i2c, sda, scl, args[ARG_interrupt].u_int); + } + + self->breakout->init(); + + return MP_OBJ_FROM_PTR(self); +} + +mp_obj_t BreakoutRTC_reset(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->reset(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_setup(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->setup(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_time(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_sec, ARG_min, ARG_hour, ARG_weekday, ARG_date, ARG_month, ARG_year }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_sec, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_min, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_hour, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_weekday, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_date, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_month, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_year, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int sec = args[ARG_sec].u_int; + int min = args[ARG_min].u_int; + int hour = args[ARG_hour].u_int; + int weekday = args[ARG_weekday].u_int; + int date = args[ARG_date].u_int; + int month = args[ARG_month].u_int; + int year = args[ARG_year].u_int; + + if(sec < 0 || sec > 59) + mp_raise_ValueError("sec out of range. Expected 0 to 59"); + else if(min < 0 || min > 59) + mp_raise_ValueError("min out of range. Expected 0 to 59"); + else if(hour < 0 || hour > 23) + mp_raise_ValueError("hour out of range. Expected 0 to 23"); + else if(weekday < 0 || weekday > 6) + mp_raise_ValueError("weekday out of range. Expected 0 to 6"); + else if(date < 1 || date > 31) + mp_raise_ValueError("date out of range. Expected 1 to 31"); + else if(month < 1 || month > 12) + mp_raise_ValueError("month out of range. Expected 1 to 12"); + else if(year < 0 || year > 99) + mp_raise_ValueError("year out of range. Expected 0 to 99"); + else + return mp_obj_new_bool(self->breakout->set_time(sec, min, hour, weekday, date, month, year)); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_seconds(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_sec}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_sec, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int sec = args[ARG_sec].u_int; + + if(sec < 0 || sec > 59) + mp_raise_ValueError("sec out of range. Expected 0 to 59"); + else + return mp_obj_new_bool(self->breakout->set_seconds(sec)); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_minutes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_min }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_min, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int min = args[ARG_min].u_int; + + if(min < 0 || min > 59) + mp_raise_ValueError("min out of range. Expected 0 to 59"); + else + return mp_obj_new_bool(self->breakout->set_minutes(min)); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_hours(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_hour }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_hour, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int hour = args[ARG_hour].u_int; + + if(hour < 0 || hour > 23) + mp_raise_ValueError("hour out of range. Expected 0 to 23"); + else + return mp_obj_new_bool(self->breakout->set_hours(hour)); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_weekday(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_weekday }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_weekday, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int weekday = args[ARG_weekday].u_int; + + if(weekday < 0 || weekday > 6) + mp_raise_ValueError("weekday out of range. Expected 0 to 6"); + else + return mp_obj_new_bool(self->breakout->set_weekday(weekday)); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_date(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_date }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_date, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int date = args[ARG_date].u_int; + + if(date < 1 || date > 31) + mp_raise_ValueError("date out of range. Expected 1 to 31"); + else + return mp_obj_new_bool(self->breakout->set_date(date)); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_month(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_month }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_month, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int month = args[ARG_month].u_int; + + if(month < 1 || month > 12) + mp_raise_ValueError("month out of range. Expected 1 to 12"); + else + return mp_obj_new_bool(self->breakout->set_month(month)); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_year(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_year }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_year, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int year = args[ARG_year].u_int; + + if(year < 0 || year > 99) + mp_raise_ValueError("year out of range. Expected 0 to 99"); + else + return mp_obj_new_bool(self->breakout->set_year(year)); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_to_compiler_time(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_bool(self->breakout->set_to_compiler_time()); +} + +mp_obj_t BreakoutRTC_update_time(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_bool(self->breakout->update_time()); +} + +mp_obj_t BreakoutRTC_string_date_usa(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + + const char* date = self->breakout->string_date_usa(); + std::string str_date(date, strlen(date)); + return mp_obj_new_str(str_date.c_str(), str_date.length()); +} + +mp_obj_t BreakoutRTC_string_date(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + + const char* date = self->breakout->string_date(); + std::string str_date(date, strlen(date)); + return mp_obj_new_str(str_date.c_str(), str_date.length()); +} + +mp_obj_t BreakoutRTC_string_time(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + + const char* time = self->breakout->string_time(); + std::string str_time(time, strlen(time)); + return mp_obj_new_str(str_time.c_str(), str_time.length()); +} + +mp_obj_t BreakoutRTC_string_time_stamp(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + + const char* time_stamp = self->breakout->string_time_stamp(); + std::string str_time_stamp(time_stamp, strlen(time_stamp)); + return mp_obj_new_str(str_time_stamp.c_str(), str_time_stamp.length()); +} + +mp_obj_t BreakoutRTC_get_seconds(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->get_seconds()); +} + +mp_obj_t BreakoutRTC_get_minutes(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->get_minutes()); +} + +mp_obj_t BreakoutRTC_get_hours(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->get_hours()); +} + +mp_obj_t BreakoutRTC_get_weekday(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->get_weekday()); +} + +mp_obj_t BreakoutRTC_get_date(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->get_date()); +} + +mp_obj_t BreakoutRTC_get_month(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->get_month()); +} + +mp_obj_t BreakoutRTC_get_year(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->get_year()); +} + +mp_obj_t BreakoutRTC_is_12_hour(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_bool(self->breakout->is_12_hour()); +} + +mp_obj_t BreakoutRTC_is_pm(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_bool(self->breakout->is_pm()); +} + +mp_obj_t BreakoutRTC_set_12_hour(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->set_12_hour(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_24_hour(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->set_24_hour(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_unix(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int value = args[ARG_value].u_int; + + return mp_obj_new_bool(self->breakout->set_unix((uint32_t)value)); +} + +mp_obj_t BreakoutRTC_get_unix(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->get_unix()); +} + +mp_obj_t BreakoutRTC_enable_alarm_interrupt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + if(n_args == 1) { + enum { ARG_self }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + self->breakout->enable_alarm_interrupt(); + } + else { + enum { ARG_self, ARG_min, ARG_hour, ARG_date_or_weekday, ARG_set_weekday_alarm_not_date, ARG_mode, ARG_enable_clock_output }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_min, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_hour, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_date_or_weekday, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_set_weekday_alarm_not_date, MP_ARG_REQUIRED | MP_ARG_BOOL }, + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_enable_clock_output, MP_ARG_BOOL, {.u_bool = false} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int min = args[ARG_min].u_int; + int hour = args[ARG_hour].u_int; + int date_or_weekday = args[ARG_date_or_weekday].u_int; + bool set_weekday_alarm_not_date = args[ARG_set_weekday_alarm_not_date].u_bool; + int mode = args[ARG_mode].u_int; + bool enable_clock_output = args[ARG_enable_clock_output].u_bool; + + if(min < 0 || min > 59) + mp_raise_ValueError("min out of range. Expected 0 to 59"); + else if(hour < 0 || hour > 23) + mp_raise_ValueError("hour out of range. Expected 0 to 23"); + else { + if(set_weekday_alarm_not_date) { + if(date_or_weekday < 0 || date_or_weekday > 6) + mp_raise_ValueError("date_or_weekday out of range. Expected 0 to 6"); + } + else { + if(date_or_weekday < 1 || date_or_weekday > 31) + mp_raise_ValueError("date_or_weekday out of range. Expected 1 to 31"); + } + self->breakout->enable_alarm_interrupt(min, hour, date_or_weekday, set_weekday_alarm_not_date, mode, enable_clock_output); + } + } + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_disable_alarm_interrupt(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->disable_alarm_interrupt(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_read_alarm_interrupt_flag(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_bool(self->breakout->read_alarm_interrupt_flag()); +} + +mp_obj_t BreakoutRTC_clear_alarm_interrupt_flag(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->clear_alarm_interrupt_flag(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_timer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_timer_repeat, ARG_timer_frequency, ARG_timer_value, ARG_set_interrupt, ARG_start_timer, ARG_enable_clock_output }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_timer_repeat, MP_ARG_REQUIRED | MP_ARG_BOOL }, + { MP_QSTR_timer_frequency, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_timer_value, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_set_interrupt, MP_ARG_REQUIRED | MP_ARG_BOOL }, + { MP_QSTR_start_timer, MP_ARG_REQUIRED | MP_ARG_BOOL }, + { MP_QSTR_enable_clock_output, MP_ARG_BOOL, {.u_bool = false} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + bool timer_repeat = args[ARG_timer_repeat].u_bool; + int timer_frequency = args[ARG_timer_frequency].u_int; + int timer_value = args[ARG_timer_value].u_int; + bool set_interrupt = args[ARG_set_interrupt].u_bool; + bool start_timer = args[ARG_start_timer].u_bool; + bool enable_clock_output = args[ARG_enable_clock_output].u_bool; + + if(timer_value < 0 || timer_value > 4065) { + mp_raise_ValueError("timer_value out of range. Expected 0 to 4095"); + } + else { + switch(timer_frequency) { + case 4096: // 4096Hz (default) // up to 122us error on first time + case 64: // 64Hz // up to 7.813ms error on first time + case 1: // 1Hz // up to 7.813ms error on first time + case 60000: // 1/60Hz // up to 7.813ms error on first time + self->breakout->set_timer(timer_repeat, timer_frequency, timer_value, set_interrupt, start_timer, enable_clock_output); + break; + + default: + mp_raise_ValueError("timer_frequency not valid. Expected, 4096, 64, 1, or 60000"); + break; + } + } + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_get_timer_count(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->get_timer_count()); +} + +mp_obj_t BreakoutRTC_enable_timer(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->enable_timer(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_disable_timer(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->disable_timer(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_enable_timer_interupt(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->enable_timer_interrupt(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_disable_timer_interrupt(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->disable_timer_interrupt(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_read_timer_interrupt_flag(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_bool(self->breakout->read_timer_interrupt_flag()); +} + +mp_obj_t BreakoutRTC_clear_timer_interrupt_flag(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->clear_timer_interrupt_flag(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_enable_periodic_update_interrupt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_every_second, ARG_enable_clock_output }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_every_second, MP_ARG_REQUIRED | MP_ARG_BOOL }, + { MP_QSTR_enable_clock_output, MP_ARG_BOOL, {.u_bool = false} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + bool every_second = args[ARG_every_second].u_bool; + bool enable_clock_output = args[ARG_enable_clock_output].u_bool; + self->breakout->enable_periodic_update_interrupt(every_second, enable_clock_output); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_disable_periodic_update_interrupt(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->disable_periodic_update_interrupt(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_read_periodic_update_interrupt_flag(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_bool(self->breakout->read_periodic_update_interrupt_flag()); +} + +mp_obj_t BreakoutRTC_clear_periodic_update_interrupt_flag(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->clear_periodic_update_interrupt_flag(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_enable_trickle_charge(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_tcr }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_tcr, MP_ARG_INT, {.u_int = TCR_15K} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int tcr = args[ARG_tcr].u_int; + + if(tcr < 0 || tcr > 3) + mp_raise_ValueError("tcr out of range. Expected 0 to 3 (TCR_3K, TCR_5K, TCR_9K, TCR_15K)"); + else + self->breakout->enable_trickle_charge(tcr); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_disable_trickle_charge(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->disable_trickle_charge(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_set_backup_switchover_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_val }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_val, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int val = args[ARG_val].u_int; + + if(val < 0 || val > 3) + mp_raise_ValueError("tcr out of range. Expected 0 to 3"); + else + self->breakout->set_backup_switchover_mode(val); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_enable_clock_out(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_freq }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_freq, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int freq = args[ARG_freq].u_int; + + if(freq < 0 || freq > 7) + mp_raise_ValueError("freq out of range. Expected 0 to 7"); + else + self->breakout->enable_clock_out(freq); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_enable_interrupt_controlled_clockout(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_freq }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_freq, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, breakout_rtc_BreakoutRTC_obj_t); + + int freq = args[ARG_freq].u_int; + + if(freq < 0 || freq > 7) + mp_raise_ValueError("freq out of range. Expected 0 to 7"); + else + self->breakout->enable_interrupt_controlled_clockout(freq); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_disable_clock_out(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->disable_clock_out(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_read_clock_output_interrupt_flag(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->read_clock_output_interrupt_flag()); +} + +mp_obj_t BreakoutRTC_clear_clock_output_interrupt_flag(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->clear_clock_output_interrupt_flag(); + + return mp_const_none; +} + +mp_obj_t BreakoutRTC_status(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + return mp_obj_new_int(self->breakout->status()); +} + +mp_obj_t BreakoutRTC_clear_interrupts(mp_obj_t self_in) { + breakout_rtc_BreakoutRTC_obj_t *self = MP_OBJ_TO_PTR2(self_in, breakout_rtc_BreakoutRTC_obj_t); + self->breakout->clear_interrupts(); + + return mp_const_none; +} +} \ No newline at end of file diff --git a/micropython/modules/breakout_rtc/breakout_rtc.h b/micropython/modules/breakout_rtc/breakout_rtc.h new file mode 100644 index 000000000..1344b98e6 --- /dev/null +++ b/micropython/modules/breakout_rtc/breakout_rtc.h @@ -0,0 +1,84 @@ +// Include MicroPython API. +#include "py/runtime.h" +//#include "py/objstr.h" + +/***** Constants *****/ +enum TCR { + MP_TCR_3K = 0b00, //Trickle Charge Resistor 3kOhm + MP_TCR_5K = 0b01, //Trickle Charge Resistor 5kOhm + MP_TCR_9K = 0b10, //Trickle Charge Resistor 9kOhm + MP_TCR_15K = 0b11, //Trickle Charge Resistor 15kOhm +}; + +/***** Extern of Class Definition *****/ +extern const mp_obj_type_t breakout_rtc_BreakoutRTC_type; + +/***** Extern of Class Methods *****/ +extern void BreakoutRTC_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); +extern mp_obj_t BreakoutRTC_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); + +extern mp_obj_t BreakoutRTC_reset(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_setup(mp_obj_t self_in); + +extern mp_obj_t BreakoutRTC_set_time(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_set_seconds(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_set_minutes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_set_hours(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_set_weekday(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_set_date(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_set_month(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_set_year(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_set_to_compiler_time(mp_obj_t self_in); + +extern mp_obj_t BreakoutRTC_update_time(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_string_date_usa(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_string_date(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_string_time(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_string_time_stamp(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_get_seconds(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_get_minutes(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_get_hours(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_get_weekday(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_get_date(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_get_month(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_get_year(mp_obj_t self_in); + +extern mp_obj_t BreakoutRTC_is_12_hour(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_is_pm(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_set_12_hour(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_set_24_hour(mp_obj_t self_in); + +extern mp_obj_t BreakoutRTC_set_unix(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_get_unix(mp_obj_t self_in); + +extern mp_obj_t BreakoutRTC_enable_alarm_interrupt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_disable_alarm_interrupt(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_read_alarm_interrupt_flag(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_clear_alarm_interrupt_flag(mp_obj_t self_in); + +extern mp_obj_t BreakoutRTC_set_timer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_get_timer_count(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_enable_timer(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_disable_timer(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_enable_timer_interupt(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_disable_timer_interrupt(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_read_timer_interrupt_flag(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_clear_timer_interrupt_flag(mp_obj_t self_in); + +extern mp_obj_t BreakoutRTC_enable_periodic_update_interrupt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_disable_periodic_update_interrupt(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_read_periodic_update_interrupt_flag(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_clear_periodic_update_interrupt_flag(mp_obj_t self_in); + +extern mp_obj_t BreakoutRTC_enable_trickle_charge(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_disable_trickle_charge(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_set_backup_switchover_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); + +extern mp_obj_t BreakoutRTC_enable_clock_out(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_enable_interrupt_controlled_clockout(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t BreakoutRTC_disable_clock_out(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_read_clock_output_interrupt_flag(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_clear_clock_output_interrupt_flag(mp_obj_t self_in); + +extern mp_obj_t BreakoutRTC_status(mp_obj_t self_in); +extern mp_obj_t BreakoutRTC_clear_interrupts(mp_obj_t self_in); \ No newline at end of file diff --git a/micropython/modules/breakout_rtc/micropython.cmake b/micropython/modules/breakout_rtc/micropython.cmake new file mode 100644 index 000000000..2783bb6a3 --- /dev/null +++ b/micropython/modules/breakout_rtc/micropython.cmake @@ -0,0 +1,20 @@ +set(MOD_NAME breakout_rtc) +string(TOUPPER ${MOD_NAME} MOD_NAME_UPPER) +add_library(usermod_${MOD_NAME} INTERFACE) + +target_sources(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c + ${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../libraries/${MOD_NAME}/${MOD_NAME}.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../../drivers/rv3028/rv3028.cpp +) + +target_include_directories(usermod_${MOD_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_${MOD_NAME} INTERFACE + -DMODULE_${MOD_NAME_UPPER}_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_${MOD_NAME}) \ No newline at end of file diff --git a/micropython/modules/breakout_rtc/micropython.mk b/micropython/modules/breakout_rtc/micropython.mk new file mode 100755 index 000000000..8f251f4a6 --- /dev/null +++ b/micropython/modules/breakout_rtc/micropython.mk @@ -0,0 +1,13 @@ +set(MOD_NAME breakout_rtc) +BREAKOUT_MOD_DIR := $(USERMOD_DIR) + +# Add our source files to the respective variables. +SRC_USERMOD += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.c +SRC_USERMOD_CXX += $(BREAKOUT_MOD_DIR)/${MOD_NAME}.cpp + +# Add our module directory to the include path. +CFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR) +CXXFLAGS_USERMOD += -I$(BREAKOUT_MOD_DIR) + +# We use C++ features so have to link against the standard library. +LDFLAGS_USERMOD += -lstdc++ \ No newline at end of file diff --git a/micropython/modules/micropython.cmake b/micropython/modules/micropython.cmake index 3493560c0..9d54d435a 100644 --- a/micropython/modules/micropython.cmake +++ b/micropython/modules/micropython.cmake @@ -12,6 +12,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/breakout_matrix11x7/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_msa301/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_mics6814/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_potentiometer/micropython.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/breakout_rtc/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_trackball/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_sgp30/micropython.cmake) include(${CMAKE_CURRENT_LIST_DIR}/breakout_colourlcd240x240/micropython.cmake)