""" IIC implementation. """ import riscos from pyromaniac.resource import Resource from riscos.modules.pymodules import PyModule from riscos.errors import RISCOSSyntheticError riscos.handlers.iic.name = "IIC" class IIC(PyModule): version = '0.01' date = '08 Jul 2019' swi_base = 0x240 swi_prefix = "IIC" swi_names = ['Control'] def swi(self, swin, regs): if swin == 0: self.iic_control(regs) return True return False def iic_control(self, regs): device_address = regs[0] & ~1 write_flag = not (regs[0] & 1) data = self.ro.memory[regs[1]] size = regs[2] handled = riscos.handlers.iic.dispatch(self.ro, device_address, regs=None, data=data, size=size, write_flag=write_flag) if not handled: op = "write" if write_flag else "read" raise RISCOSSyntheticError(self.ro, "No response from IIC device &%02x for %s" % (device_address, op)) import datetime def to_bcd(value): return (int(value / 10) << 4) | (value % 10) class PCF8583(Resource): """ The PCF 8583 RTC/CMOS storage. The device provides an address latch which is written to by the first byte written. All subsequent bytes written (within the same transfer) will be writtne to addresses within the device starting from that latch location. All subsequent bytes read (within the next transfer) read from increasing locations from that latched address. See https://www.nxp.com/docs/en/data-sheet/PCF8583.pdf for more information. This implementation only supports the clock + 240 bytes of RAM. """ def __init__(self, ro): super(PCF8583, self).__init__(ro) self.address_latch = 0 self.debug_iic = False self.ro.debug_register_ivar('iic', self) def initialise(self): if self.debug_iic: print("PCF8583 initialising") def now(self): """ Read the current time as a DateTime object (applying any offset) """ now = datetime.datetime.now() time_offset = self.ro.config['time.offset'] if time_offset: now += datetime.timedelta(0, time_offset) return now def read(self): """ Read from memory location `address_latch`, incrementing. """ if self.debug_iic: print("PCF8583: read address %i" % (self.address_latch,)) value = 0 if self.address_latch == 0: # control/status pass elif self.address_latch == 1: # centiseconds now = self.now() value = to_bcd(now.microsecond / 10000) elif self.address_latch == 2: # seconds now = self.now() value = to_bcd(now.second) elif self.address_latch == 3: # minutes now = self.now() value = to_bcd(now.minute) elif self.address_latch == 4: # hours now = self.now() value = to_bcd(now.hour) elif self.address_latch == 5: # year/date now = self.now() value = to_bcd(now.day) | ((now.year & 3)<<6) elif self.address_latch == 6: # month now = self.now() value = to_bcd(now.month) elif self.address_latch == 7: # timer pass elif self.address_latch == 8: # alarm control pass elif self.address_latch == 9: # alarm centiseconds pass elif self.address_latch == 10: # alarm seconds pass elif self.address_latch == 11: # alarm minutes pass elif self.address_latch == 12: # alarm hours pass elif self.address_latch == 13: # alarm date pass elif self.address_latch == 14: # alarm month pass elif self.address_latch == 15: # alarm timer pass elif self.address_latch >= 0x10: value = self.ro.resources['NVRAMStorage'][self.address_latch - 0x10] self.address_latch += 1 return value def write(self, value): """ Write to memory location `address_latch`, incrementing. """ if self.debug_iic: print("PCF8583: write address %i" % (self.address_latch,)) if self.address_latch == 0: # control/status pass elif self.address_latch == 1: # centiseconds pass elif self.address_latch == 2: # seconds pass elif self.address_latch == 3: # minutes pass elif self.address_latch == 4: # hours pass elif self.address_latch == 5: # year/date pass elif self.address_latch == 6: # month/weekday pass elif self.address_latch == 7: # timer pass elif self.address_latch == 8: # alarm control pass elif self.address_latch == 9: # alarm centiseconds pass elif self.address_latch == 10: # alarm seconds pass elif self.address_latch == 11: # alarm minutes pass elif self.address_latch == 12: # alarm hours pass elif self.address_latch == 13: # alarm date pass elif self.address_latch == 14: # alarm month pass elif self.address_latch == 15: # alarm timer pass elif self.address_latch >= 0x10: # NVRAM values value = self.ro.resources['NVRAMStorage'][self.address_latch - 0x10] self.address_latch += 1 @riscos.handlers.iic.register(0xa0) def iic_pcf8583(ro, device_address, data, size, write_flag): if write_flag: # If writing, the first byte of the data to write is the address latch ro.resources['pcf8583'].address_latch = data.byte data.address += 1 size -= 1 for offset in range(size): ro.resources['pcf8583'].write(data[offset].byte) else: for offset in range(size): data[offset].byte = ro.resources['pcf8583'].read() return True