Advertisement
Guest User

Arduino remote programmer by SISTEMAS O.R.P.

a guest
Nov 2nd, 2014
567
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.45 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. # Copyright (C) 2014 SISTEMAS O.R.P.
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation, either version 3 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  
  18. import sys
  19. import binascii
  20. import time
  21. import struct
  22. import select
  23. import socket
  24. import errno
  25.  
  26. MAX_TIMEOUT = 500
  27. SUCCESS = "success"
  28. FAILED = "failed"
  29. PORT = 50000
  30.  
  31. class Data:
  32.     def __init__(self, begin, data):
  33.         self.begin = begin
  34.         self.data = data
  35.         self.count = len(data)
  36.        
  37. def treat_line(line):
  38.         ok = False
  39.         size = int(line[1:3], 16)
  40.         direction = int(line[3:7], 16)
  41.         type = int(line[7:9], 16)
  42.         data = binascii.a2b_hex(line[9:-3])
  43.         checksum = int(line[-3:], 16)
  44.        
  45.         #checking if checksum is correct
  46.         sum = size + (direction >> 8) + (direction & 0xFF) + type
  47.         for byte in data:
  48.             sum += ord(byte)
  49.  
  50.         if (~(sum & 0xFF) + 1) & 0xFF == checksum:
  51.             ok = True
  52.  
  53.         return (size, direction, type, data, checksum, ok)
  54.  
  55. def read_hex_file(chunks, path):
  56.     try:
  57.         file = open(path, 'r')
  58.     except IOError:
  59.         print "1", binascii.b2a_hex(path)
  60.         return False
  61.     line = file.readline()
  62.     if line[0] != ':':
  63.         print "The file seems to be a not valid .hex file"
  64.         file.close()
  65.         return False
  66.        
  67.     size, direction, type, data, checksum, ok = treat_line(line)
  68.     if not ok:
  69.         print "The checksum in line 1 is wrong"
  70.         file.close()
  71.         return False
  72.  
  73.     chunks.append(Data(direction, data))
  74.  
  75.     # Read the other lines
  76.     index = 0
  77.     count = 2
  78.     for line in file:
  79.         size, direction, type, data, checksum, ok = treat_line(line)
  80.         if not ok:
  81.             print "The checksum in line", count, "is wrong"
  82.             file.close()
  83.             return False
  84.  
  85.         if chunks[index].begin + chunks[index].count == direction:
  86.             chunks[index].count += size
  87.             for code in data:
  88.                 chunks[index].data += code
  89.         else:
  90.             chunks.append(Data(direction, data))
  91.             index += 1
  92.         count += 1
  93.    
  94.     return True
  95.    
  96. def init_server():
  97.     server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  98.     server.bind(('', PORT))
  99.     server.listen(1)
  100.     return server
  101.    
  102.    
  103. def send_command(cli, command):
  104.     cli.send(command)
  105.  
  106. def wait_for(cli, response, timeout):
  107.     inputs = [cli]
  108.     received = ""
  109.     milliseconds = 0
  110.     while milliseconds < timeout:
  111.         rlist, wlist, xlist = select.select(inputs,[],[], 0.001)
  112.         if len(rlist) > 0:
  113.             received += cli.recv(1)
  114.             #print binascii.b2a_hex(received)
  115.             if response in received:
  116.                 return True, received
  117.         milliseconds += 1
  118.        
  119.     return False, received
  120.    
  121.    
  122.    
  123. def return_data(cli, timeout, length = 1):
  124.     inputs = [cli]
  125.     received = ""
  126.     milliseconds = 0
  127.     while milliseconds < timeout:
  128.         rlist, wlist, xlist = select.select(inputs,[],[], 0.001)
  129.         if len(rlist) > 0:
  130.             received = cli.recv(length)
  131.             #print binascii.b2a_hex(received)
  132.             return True, received
  133.         milliseconds += 1
  134.        
  135.     return False, received
  136.  
  137. def acknowledge(cli):
  138.     if wait_for(cli, "\x14\x10", MAX_TIMEOUT)[0]: #STK_INSYNC, STK_OK
  139.         print SUCCESS
  140.         return True
  141.     else:
  142.         print FAILED
  143.         return False
  144.        
  145. def program_process(chunks, cli):
  146.     print "Connection to Arduino bootloader:",
  147.    
  148.     counter = 0
  149.     for index in range(3):
  150.         send_command(cli, "\x30\x20") #STK_GET_SYNCH, SYNC_CRC_EOP
  151.         if wait_for(cli, "\x14\x10", MAX_TIMEOUT)[0]: #STK_INSYNC, STK_OK
  152.             counter += 1
  153.             if counter == 3:
  154.                 break;
  155.  
  156.     if counter < 2:
  157.         print FAILED
  158.         return
  159.            
  160.     print SUCCESS
  161.  
  162.     print "Enter in programming mode:",
  163.     send_command(cli, "\x50\x20") #STK_ENTER_PROGMODE, SYNC_CRC_EOP
  164.     if not acknowledge(cli):
  165.         return
  166.        
  167.     print "Read device signature:",
  168.     send_command(cli, "\x75\x20") #STK_READ_SIGN, SYNC_CRC_EOP
  169.     if wait_for(cli, "\x14", MAX_TIMEOUT)[0]: #STK_INSYNC
  170.         ok,received = return_data(cli, MAX_TIMEOUT, 3)
  171.         print binascii.b2a_hex(received)
  172.         if not wait_for(cli, "\x10", MAX_TIMEOUT)[0]: #STK_INSYNC
  173.             print FAILED
  174.             return
  175.     else:
  176.         print FAILED
  177.         return
  178.  
  179.     for chunk in chunks:
  180.         total = chunk.count
  181.         if total > 0: #avoid the last block (the last line of .hex file)
  182.             current_page = chunk.begin
  183.             pages = total / 0x80
  184.             index = 0
  185.            
  186.             for page in range(pages):
  187.                 print "Load memory address",current_page,":",
  188.                 send_command(cli, struct.pack("<BHB", 0x55, current_page, 0x20)) #STK_LOAD_ADDRESS, address, SYNC_CRC_EOP
  189.                 if not acknowledge(cli):
  190.                     return
  191.                
  192.                 print "Program memory address:",
  193.                 send_command(cli, "\x64\x00\x80\x46" + chunk.data[index:index + 0x80] + "\x20") #STK_PROGRAM_PAGE, page size, flash memory, data, SYNC_CRC_EOP
  194.                 if not acknowledge(cli):
  195.                     return
  196.                 current_page += 0x40
  197.                 total -= 0x80
  198.                 index += 0x80
  199.            
  200.             if total > 0:
  201.                 print "Load memory address",current_page,":",
  202.                 send_command(cli, struct.pack("<BHB", 0x55, current_page, 0x20)) #STK_LOAD_ADDRESS, address, SYNC_CRC_EOP
  203.                 if not acknowledge(cli):
  204.                     return
  205.                
  206.                 print "Program memory address:",
  207.                 send_command(cli, struct.pack(">BHB", 0x64, total, 0x20) + chunk.data[index:index + total] + "\x20") #STK_PROGRAM_PAGE, page size, flash memory, data, SYNC_CRC_EOP
  208.                 if not acknowledge(cli):
  209.                     return
  210.  
  211.     print "Leave programming mode:",   
  212.     send_command(cli, "\x51\x20") #STK_LEAVE_PROGMODE, SYNC_CRC_EOP
  213.     acknowledge(cli)
  214.        
  215. def main():
  216.  
  217.     inputs = []
  218.  
  219.     print "Arduino remote programmer 2014 (c) SISTEMAS O.R.P"
  220.    
  221.     print "Listen to connections"
  222.     ser = init_server()
  223.     inputs.append(ser)
  224.    
  225.     while True:
  226.         rlist, wlist, xlist = select.select(inputs,[],[])
  227.         for s in rlist:
  228.             if s == ser:
  229.                 cli, addr = s.accept()
  230.                 print addr[0], "connected"
  231.                 if wait_for(cli, "hello", 5000)[0]:
  232.                     send_command(cli, "welcome")
  233.                     ok, received = wait_for(cli, "hex", 5000)
  234.                     if ok:
  235.                         chunks = []
  236.                         print "Read hex file", received.strip()
  237.                         if read_hex_file(chunks, received.strip()):
  238.                             send_command(cli, "ok")
  239.                             if wait_for(cli, "\x00", MAX_TIMEOUT)[0]:
  240.                                 program_process(chunks, cli)
  241.                         else:
  242.                             send_command(cli, "error")
  243.                 cli.close()
  244.                 print "Listen to connections"
  245.                
  246. if __name__ == "__main__":
  247.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement