Subversion Repositories HomeAutomation

Rev

Rev 612 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. #!/usr/bin/python
  2.  
  3. import can
  4. import uncen
  5.  
  6. import sys
  7. from array import array
  8. from binascii import unhexlify
  9.  
  10. class Job( uncen.UncenJob ):
  11.     name = "UncenDude"
  12.     version = "0.01"
  13.     listen = False
  14.  
  15.     mynodeid = 0
  16.  
  17.     cnt = 0
  18.  
  19.     programming = False
  20.  
  21.     MODE_APP   = 0
  22.     MODE_BIOS  = 1
  23.     MODE_START = 2
  24.     MODE_RESET = 3
  25.  
  26.     def getstatus( self ):
  27.         return "Pkt sent: %d" % (self.cnt,)
  28.  
  29.     def __init__( self, core, args ):
  30.         self.job_init( core )
  31.  
  32.  
  33.         self.cid = self.can_connect( args[0] )
  34.  
  35.         if len(args[1])>2 and args[1][:2] == "0x":
  36.             self.nodeid = int( args[1], 16 )
  37.         else:
  38.             self.nodeid = int( args[1] )
  39.  
  40.         self.mode = { \
  41.             "app":   self.MODE_APP,   \
  42.             "bios":  self.MODE_BIOS,  \
  43.             "start": self.MODE_START, \
  44.             "reset": self.MODE_RESET, \
  45.             }[args[2]]
  46.  
  47.         if self.mode == self.MODE_APP or self.mode == self.MODE_BIOS:
  48.             self.hexfile = Hexfile( args[3] )
  49.             self.finished = False
  50.             self.programming = True
  51.             self.dosend_file()
  52.         elif self.mode == self.MODE_RESET:
  53.             self.finished = True
  54.             canp = can.CanPacket( can.nmt_id( can.CAN_NMT_RESET, self.nodeid, self.mynodeid ), [] )
  55.             self.can_send( self.cid, canp )
  56.         elif self.mode == self.MODE_START:
  57.             self.finished = True
  58.             canp = can.CanPacket( can.nmt_id( can.CAN_NMT_START_APP, self.nodeid, self.mynodeid ), [] )
  59.             self.can_send( self.cid, canp )
  60.             self.close()
  61.  
  62.     def dosend_file( self ):
  63.         if self.programming:
  64.             rec = self.hexfile.pop( 6 )
  65.  
  66.             if rec[0] == Hexfile.TYPE_DATA:
  67.                 type, offset, data = rec
  68.                 self.cnt += 1
  69.                 canp = can.CanPacket( can.nmt_id( can.CAN_NMT_PGM_DATA, self.nodeid, self.mynodeid ), [(offset) & 0xFF, (offset>>8) & 0xFF] + data )
  70.                 self.can_send( self.cid, canp )
  71.             elif rec[0] == Hexfile.TYPE_OFFSET:
  72.                 type, offset = rec
  73.                 self.cnt += 1
  74.                 canp = can.CanPacket( can.nmt_id( can.CAN_NMT_PGM_START, self.nodeid, self.mynodeid ), [ (offset>>24) & 0xFF, (offset>>16) & 0xFF, (offset>>8 ) & 0xFF, (offset    ) & 0xFF ] )
  75.                 self.can_send( self.cid, canp )
  76.             elif rec[0] == Hexfile.TYPE_EOF:
  77.                 self.finished = True
  78.                 canp = can.CanPacket( can.nmt_id( can.CAN_NMT_PGM_END, self.nodeid, self.mynodeid ), [] )
  79.                 self.programming=False
  80.                 self.can_send( self.cid, canp )
  81.         else:
  82.             canp = can.CanPacket( can.nmt_id( can.CAN_NMT_RESET, self.nodeid, self.mynodeid ), [] )
  83.             self.can_send( self.cid, canp )
  84.  
  85.  
  86.     def can_recieve( self, cid, canp ):
  87.         if canp.id == can.nmt_id( can.CAN_NMT_PGM_ACK, self.mynodeid, self.nodeid ):
  88.             self.dosend_file()
  89.         elif canp.id == can.nmt_id( can.CAN_NMT_PGM_NACK, self.mynodeid, self.nodeid ):
  90.             self.core.term.write( "Error programming" )
  91.         elif canp.id == can.nmt_id( can.CAN_NMT_BIOS_START, self.mynodeid, self.nodeid ):
  92.             self.core.term.write( "Node resetted, bios 0x%02x%02x, application: %d" % (canp.data[1], canp.data[0], canp.data[2]) )
  93.             if not self.finished:
  94.                 self.core.term.write( "WARNING: Programming not finished" )
  95.             self.close()
  96.  
  97.     def close( self ):
  98.         self.job_close()
  99.  
  100. class Hexfile:
  101.     TYPE_DATA = 0
  102.     TYPE_EOF = 1
  103.     TYPE_OFFSET = 2
  104.  
  105.     def __init__( self, filename ):
  106.         self.file = file( filename, "r" )
  107.         self.records = [(self.TYPE_OFFSET, 0)]
  108.         for line in self.file:
  109.             line = line.rstrip("\n\r")
  110.             try:
  111.                 self.records.append( self.parse( line ) )
  112.             except IllegalRecord:
  113.                 pass
  114.         self.file.close()
  115.  
  116.     def parse( self, line ):
  117.         if line == "":
  118.             raise IllegalRecord()
  119.  
  120.         if line[0] != ":":
  121.             raise IllegalRecord()
  122.  
  123.         data = array('B', unhexlify( line[1:] ) )
  124.         if len( data ) < 5:
  125.             raise IllegalRecord()
  126.  
  127.         crc = 0
  128.         for i in range( len( data )-1 ):
  129.             crc += data[i]
  130.         crc = (1+(0xFF^crc))&0xFF
  131.  
  132.         if data[-1] != crc:
  133.             raise IllegalRecord()
  134.  
  135.         length = data[0]
  136.         addr = data[1]*256 + data[2]
  137.         type = data[3]
  138.         content = data[4:-1].tolist()
  139.  
  140.         val = 0
  141.         for x in content:
  142.             val = (val<<8) | x
  143.  
  144.         if len( content ) != length:
  145.             raise IllegalRecord()
  146.  
  147.         if type==0x00:
  148.             return (self.TYPE_DATA, addr, content)
  149.  
  150.         if type==0x01:
  151.             return (self.TYPE_EOF,)
  152.  
  153.         if type==0x02:
  154.             return (self.TYPE_OFFSET, contentint*0x10)
  155.  
  156.         if type==0x04:
  157.             return (self.TYPE_OFFSET, contentint*0x10000)
  158.  
  159.     def pop( self, maxlength=None ):
  160.         try:
  161.             rec = self.records.pop(0)
  162.         except IndexError:
  163.             rec = (self.TYPE_EOF,)
  164.         if rec[0] != self.TYPE_DATA or maxlength is None:
  165.             return rec
  166.  
  167.         type, addr, content = rec
  168.         length = len( content )
  169.  
  170.         if length > maxlength:
  171.             newaddr = addr+maxlength
  172.             newcontent = content[maxlength:]
  173.             content = content[:maxlength]
  174.  
  175.             self.records.insert(0, (type, newaddr, newcontent ) )
  176.             return (type, addr, content)
  177.         elif length < maxlength:
  178.             if self.records[0][0] == type and self.records[0][1] == addr+length:
  179.                 nextrec = self.pop( maxlength-length )
  180.                 content = content+nextrec[2]
  181.                 return (type, addr, content)
  182.             return rec
  183.         else:
  184.             return rec
  185.  
  186. class IllegalRecord:
  187.     pass
  188.