#! /usr/bin/python

# To do:  Change spimodule.c to allow setting of speed and to disable chip selection
#             so that GPIO can do it all.

import spidev
import RPi.GPIO
from time import time,sleep
chipSelectPin=24
RPi.GPIO.setwarnings(False)
RPi.GPIO.cleanup()    # We leave the chip select pin high after programming
                      #    to let the ATmega328P run the program.
                      #    cleanup() is run to regain control without an warning.
RPi.GPIO.setmode(RPi.GPIO.BOARD)
RPi.GPIO.setup(chipSelectPin,RPi.GPIO.OUT,RPi.GPIO.PUD_UP,0)  
sleep(0.02)

chipSelect=0
spiPort = spidev.SpiDev()
spiPort.open(0,chipSelect)
spiPort.max_speed_hz=10000    # must be after spiPort.open command


# First data is loaded into temporary page storage by the following instructions.
programmingEnable=[0xAC,0x53,0x00,0x00]	# Returns the 53 in the 3rd byte of reply if sync is ok.
chipErase=[0xAC,0x80,0x00,0x00]	# 
pollReadyBusy=[0xF0,0x00,0x00,0x00]	# If bit 0 of 4th byte or reply is 1, it is still busy.  If 0, ok.
loadProgramMemoryPageLowByte=[0x40,0x00]	# Low byte must be loaded before high byte.
loadProgramMemoryPageHighByte=[0x48,0x00]
writeProgramMemoryPage=[0x4C]	# When page is full or after last load, this makes it so.
readProgramMemoryLowByte=[0x20]
readProgramMemoryHighByte=[0x28]
wordsPerPage=64

f=open("loggingWithSPIInterrupts.obj","r")

code=f.read()
print 'code file length=',len(code)
offsetToSourceFilenames=((ord(code[0])*256+ord(code[1]))*256+ord(code[2]))*256+ord(code[3])
offsetToObjectRecords=((ord(code[4])*256+ord(code[5]))*256+ord(code[6]))*256+ord(code[7])
bytesPerRecord=ord(code[8])
print bytesPerRecord,'bytes per record'
filenamesStoredInTrailer=ord(code[9])
print (offsetToSourceFilenames-offsetToObjectRecords)/9,'words of actual code'
codeIndex=10
assemblerName=''
while codeIndex<offsetToObjectRecords:
    assemblerName=assemblerName+code[codeIndex]
    codeIndex=codeIndex+1
f.close()

print 'Enabling programming...',
response=spiPort.xfer2([0xAC,0x53,0x00,0x00])
sleep(0.005)

print 'Erasing chip...',
response=spiPort.xfer2([0xAC,0x80,0x00,0x00])
sleep(0.25)


print assemblerName
print
print '      Object           Source'
print 'Address    Code      File   Line  Macro  Commands Sent           Replies'


def poll():
    while True:
        response = spiPort.xfer2([0xF0,0x00,0x00,0x00])
        if response[3]%2!=1:
            break
        sleep(0.005)
print
poll()

page=0
lastPageAddress=0

def myHex2(n):
    x=hex(n)[2:]
    return (2-len(x))*'0'+x


def commitPage():
    global lastPageAddress
#    print 'Committing page',lastPageAddress,lastPageAddress[0:2],lastPageAddress[2:4]
    response=spiPort.xfer2([0x4C,int(lastPageAddress[0:2],16),int(lastPageAddress[2:4],16),0])
#    print 'response:',response
    poll()

address='000000'
lastPage=0
while codeIndex<offsetToSourceFilenames:
    lastPageAddress=address[2:]
    wordCount=(ord(code[codeIndex])*256+ord(code[codeIndex+1]))*256+ord(code[codeIndex+2])
    address=hex(wordCount)[2:]
    address=(6-len(address))*'0'+address
    print address,

    if lastPage!=wordCount/wordsPerPage:
        commitPage()
        lastPage=wordCount/wordsPerPage

    codeIndex=codeIndex+3

    highDataByte=ord(code[codeIndex])
    print myHex2(highDataByte),
    codeIndex=codeIndex+1

    lowDataByte=ord(code[codeIndex])
    print myHex2(lowDataByte),
    codeIndex=codeIndex+1

    spiPort.xfer2([0x40,0x00,int(address[4:],16),lowDataByte])
    spiPort.xfer2([0x48,0x00,int(address[4:],16),highDataByte])

    sourceFile=ord(code[codeIndex])
    sourceLine=ord(code[codeIndex+1])*256+ord(code[codeIndex+2])
    macroIndicator=ord(code[codeIndex+3])
    codeIndex=codeIndex+4
    print '{0:3d}  {1:5d}'.format(sourceFile,sourceLine),
    if macroIndicator:
        print 'Macro  ',
    else:
        print '       ',

    print

lastPageAddress=address[2:]
commitPage()
print
print 'Source files:'
for j in range(filenamesStoredInTrailer):
    filename=''
    while code[codeIndex]!=chr(0):
        filename=filename+code[codeIndex]
        codeIndex=codeIndex+1
    print '  ',filename
    codeIndex=codeIndex+1
print
spiPort.close()
sleep(0.25)
RPi.GPIO.setup(chipSelectPin,RPi.GPIO.OUT,RPi.GPIO.PUD_UP,1)
#RPi.GPIO.cleanup()    # Note: We do not clean up so that the ATmega will not be reset
                      #       cleanup() leaves the chipSelectPin low.

