Exemple #1
0
 def toByteCode(self):
   bytes = super(self.__class__, self).toByteCode()
   coded_modules = [codec.VALUE_TO_UNITCODE_MAP[i] for i in self.modules]
   modmask = utils.unmerge_bytes(utils.numbers_to_mask(coded_modules), 2)
   bytes.extend(modmask)
   return bytes
Exemple #2
0
  def toByteCode(self):
    """Convert the timers, macro initiators, macros, DST data,
    sunrise/sunset data and everything else described by this class
    into bytecode suitable for uploading to the CM15."""
    mem = utils.MemoryBuffer(capacity=0x2000)

    assert(0 == (self.sunrise_sunset_resolution >> 8))
    mem[4] = self.sunrise_sunset_resolution & 0xFF
    
    bytes = codec.DST_DAYS.encode(self.dst_data)
    mem.setFromByteArray(5, bytes)

    tranceivedHousecodeMap = dict([(k, 1) for k in self.tranceivedHousecodes])
    for i in range(0,16):
      c = chr(ord('A')+i)
      if c not in tranceivedHousecodeMap:
        tranceivedHousecodeMap[c] = 0
    mem.setFromByteArray(9, codec.HOUSECODE_MASK.encode(tranceivedHousecodeMap))

    # TODO: data between 0x0b and 0x18 not currently understood

    ptr = 0x18

    # the eeprom download seems to contain a lot of single bytes holding
    # the least-significant 8 bits of their address. Presumably this
    # was just a default value fill of the buffer, although these
    # markers do make the rom code a bit easier for a human to read 
    def setLowOrderAddressByte():
      mem[ptr] = ptr & 0xFF
      return ptr + 1
    
    ptr = setLowOrderAddressByte()

    # write the timer initiators. Timers refer to start and stop macro
    # chains, but the addresses of the macros are indirected through a
    # set of 2-byte pointers stored in memory after the timer
    # initiators. My guess is that this is to get around the 10-bit
    # address limitation of the codec, as this scheme allows macros to
    # be placed anywhere in the 16-bit address space while also
    # allowing much of the original eeprom hardware from the CM12 to
    # be reused.
    indirect_table = dict()
    indirect_table_offset = ptr + (len(self.timer_initiators) * codec.TIMER_INITIATOR.codelength)
    indirect_table_offset = utils.alignToBoundary(indirect_table_offset, 4)
    for t in self.timer_initiators:
      hasMacroId = False
      for k in ("start_macro_id", "stop_macro_id"):
        if k in vars(t):
          hasMacroId = True
          id = vars(t)[k]
          indirectPtr = indirect_table.get(id)
          if indirectPtr is None:
            offset = indirect_table_offset + (2 * len(indirect_table))
            indirectPtr = indirect_table[id] = offset
          t.start_macro_ptr = indirectPtr
      assert(hasMacroId)
      bytes = t.toByteCode()
      ptr = mem.setFromByteArray(ptr, bytes)
      ptr = setLowOrderAddressByte()

    # A few bytes here which are not well understood - seems to
    # contain address boundary of the macros:
    ptr = mem.setFromByteArray(ptr, [0x00])
    ptr = setLowOrderAddressByte()
    macro_limits_offset = ptr # need to  write the macro end address here 
    ptr += 2 

    # now set the offset at the start of the eeprom
    macro_initiator_table_offset = ptr + (3 * len(indirect_table))
    mem.setFromByteArray(0, utils.unmerge_bytes(macro_initiator_table_offset, 2))
   
    # write the macro initiators:
    ptr = macro_initiator_table_offset
    for m in self.macro_initiators:
      ptr = setLowOrderAddressByte()
      ptr = mem.setFromByteArray(ptr, m.toByteCode())

    ptr = setLowOrderAddressByte()
    ptr = mem.setFromByteArray(ptr, [0xff, 0xff, 0xff])

    # now write the actual macro chains:
    for m in self.macro_chains:
      ptr = setLowOrderAddressByte()
      ptr = mem.setFromByteArray(ptr, m.toByteCode())

    # go back and write the end address:
    end_of_macros_address = ptr    
    mem.setFromByteArray(macro_limits_offset, utils.unmerge_bytes(end_of_macros_address, 2))

    ptr = setLowOrderAddressByte()
    ptr = mem.setFromByteArray(ptr, [0x00])

    # fill the rest of this row and the next with 0xffs:
    fill_address = utils.alignToBoundary(ptr, 16)
    fill_address += 16
    ptr = mem.setFromByteArray(ptr, [0xff for i in range(ptr, fill_address)])

    # now write the sunrise/sunset times:
    ptr = len(mem) - 12
    for sunrise_sunset_time in reversed(self.sunrise_sunset_times):
      ptr -= codec.DAWN_DUSK_ENTRY.codelength
      mem.setFromByteArray(ptr, codec.DAWN_DUSK_ENTRY.encode(sunrise_sunset_time))

    # write this offset into byte 2:
    start_of_sunrise_sunset_table = ptr
    mem.setFromByteArray(2, utils.unmerge_bytes(start_of_sunrise_sunset_table, 2))

    # TODO: 12 bytes at the end of the eeprom not currently understood

    return mem
Exemple #3
0
 def toByteCode(self):
   bytes = super(self.__class__, self).toByteCode()
   flagmask = utils.unmerge_bytes(utils.numbers_to_mask(self.flags), 2)
   bytes.extend(flagmask)
   return bytes