#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
#=======================================================================
# Copyright:	Christian Aichinger
# Author:		Christian Aichinger
# License:		THE BEER-WARE LICENSE
#				http://de.wikipedia.org/wiki/Beerware
# Date:			07.03.2012
# Version:		1.03
# Project:		STK500 Interface
# Description:	
#			
#=======================================================================

import serial
#import sys
#import os
#import time

SerPort = "/dev/ttyS0"

ErrorStr = ""
seqnum = 0

#***********************************************************************
# Die folgenden Konstanten und die Protkoll-Beschreibung sind aus
# der Atmel AVR Application-Note AVR068 (doc2591.pdf).  www.atmel.com
#***********************************************************************
#*****************[ STK message constants ]*****************************
MESSAGE_START = 0x1B        #= ESC = 27 decimal
TOKEN = 0x0E
#*****************[ STK general command constants ]*********************
CMD_SIGN_ON = 0x01
CMD_SET_PARAMETER = 0x02
CMD_GET_PARAMETER = 0x03
CMD_SET_DEVICE_PARAMETERS = 0x04
CMD_OSCCAL = 0x05
CMD_LOAD_ADDRESS = 0x06
CMD_FIRMWARE_UPGRADE = 0x07
#*****************[ STK ISP command constants ]*************************
CMD_ENTER_PROGMODE_ISP = 0x10
CMD_LEAVE_PROGMODE_ISP = 0x11
CMD_CHIP_ERASE_ISP = 0x12
CMD_PROGRAM_FLASH_ISP = 0x13
CMD_READ_FLASH_ISP = 0x14
CMD_PROGRAM_EEPROM_ISP = 0x15
CMD_READ_EEPROM_ISP = 0x16
CMD_PROGRAM_FUSE_ISP = 0x17
CMD_READ_FUSE_ISP = 0x18
CMD_PROGRAM_LOCK_ISP = 0x19
CMD_READ_LOCK_ISP = 0x1A
CMD_READ_SIGNATURE_ISP = 0x1B
CMD_READ_OSCCAL_ISP = 0x1C
CMD_SPI_MULTI = 0x1D
#*****************[ STK PP command constants ]**************************
CMD_ENTER_PROGMODE_PP = 0x20
CMD_LEAVE_PROGMODE_PP = 0x21
CMD_CHIP_ERASE_PP = 0x22
CMD_PROGRAM_FLASH_PP = 0x23
CMD_READ_FLASH_PP = 0x24
CMD_PROGRAM_EEPROM_PP = 0x25
CMD_READ_EEPROM_PP = 0x26
CMD_PROGRAM_FUSE_PP = 0x27
CMD_READ_FUSE_PP = 0x28
CMD_PROGRAM_LOCK_PP = 0x29
CMD_READ_LOCK_PP = 0x2A
CMD_READ_SIGNATURE_PP = 0x2B
CMD_READ_OSCCAL_PP = 0x2C    
CMD_SET_CONTROL_STACK = 0x2D
#*****************[ STK HVSP command constants ]************************
CMD_ENTER_PROGMODE_HVSP = 0x30
CMD_LEAVE_PROGMODE_HVSP = 0x31
CMD_CHIP_ERASE_HVSP = 0x32
CMD_PROGRAM_FLASH_HVSP = 0x33
CMD_READ_FLASH_HVSP = 0x34
CMD_PROGRAM_EEPROM_HVSP = 0x35
CMD_READ_EEPROM_HVSP = 0x36
CMD_PROGRAM_FUSE_HVSP = 0x37
CMD_READ_FUSE_HVSP = 0x38
CMD_PROGRAM_LOCK_HVSP = 0x39
CMD_READ_LOCK_HVSP = 0x3A
CMD_READ_SIGNATURE_HVSP = 0x3B
CMD_READ_OSCCAL_HVSP = 0x3C
#*****************[ STK status constants ]******************************
# Success
STATUS_CMD_OK = 0x00
# Warnings
STATUS_CMD_TOUT = 0x80
STATUS_RDY_BSY_TOUT = 0x81
STATUS_SET_PARAM_MISSING = 0x82
# Errors
STATUS_CMD_FAILED = 0xC0
STATUS_CKSUM_ERROR = 0xC1
STATUS_CMD_UNKNOWN = 0xC9
#*****************[ STK parameter constants ]***************************
PARAM_BUILD_NUMBER_LOW = 0x80
PARAM_BUILD_NUMBER_HIGH = 0x81
PARAM_HW_VER = 0x90
PARAM_SW_MAJOR = 0x91
PARAM_SW_MINOR = 0x92
PARAM_VTARGET = 0x94
PARAM_VADJUST = 0x95
PARAM_OSC_PSCALE = 0x96
PARAM_OSC_CMATCH = 0x97
PARAM_SCK_DURATION = 0x98
PARAM_TOPCARD_DETECT = 0x9A
PARAM_STATUS = 0x9C
PARAM_DATA = 0x9D
PARAM_RESET_POLARITY = 0x9E
PARAM_CONTROLLER_INIT = 0x9F
#*****************[ STK answer constants ]******************************
ANSWER_CKSUM_ERROR = 0xB0



def WriteCmd(cmd):
	global ErrorStr
	global seqnum
	rplymsg = "NONE"
	
	ser = serial.Serial(port=SerPort,baudrate=115200,bytesize=8,parity="N",stopbits=1,timeout=3,xonxoff=0,rtscts=0)
	
	msgsiz = len(cmd)
	msgsiz1 = msgsiz & 0xff00
	msgsiz0 = msgsiz & 0x00ff
	cmdmsg = chr(MESSAGE_START) + chr(seqnum) + chr(msgsiz1) + chr(msgsiz0) + chr(TOKEN) + cmd
	chksum = MESSAGE_START ^ seqnum ^ msgsiz1 ^ msgsiz0 ^ TOKEN
	for cnt in range(0,len(cmd)):
		chksum = chksum ^ ord(cmd[cnt])
	cmdmsg = cmdmsg + chr(chksum)
	ser.write(cmdmsg)
	
	if ser.read(1) == chr(MESSAGE_START):				# check message start
		if ser.read(1) == chr(seqnum):					# check sequence number
			msgsiz1 = ord(ser.read(1))
			msgsiz0 = ord(ser.read(1))
			msgsiz = (msgsiz1 << 8) | msgsiz0
			if ser.read(1) == chr(TOKEN):				# check token
				ser.read(1)
				# answer_id Verarbeitung hier einfügen !!!
				status = ord(ser.read(1))
				if status == STATUS_CMD_UNKNOWN:		# check status
					ErrorStr = "STATUS_CMD_UNKNOWN"
				elif status == STATUS_CKSUM_ERROR:
					ErrorStr = "STATUS_CKSUM_ERROR"
				elif status == STATUS_CMD_FAILED:
					ErrorStr = "STATUS_CMD_FAILED"
				elif status == STATUS_SET_PARAM_MISSING:
					ErrorStr = "STATUS_SET_PARAM_MISSING"
				elif status == STATUS_RDY_BSY_TOUT:
					ErrorStr = "STATUS_RDY_BSY_TOUT"
				elif status == STATUS_CMD_TOUT:
					ErrorStr = "STATUS_CMD_TOUT"
				elif status == STATUS_CMD_OK:
					rplymsg = ser.read(msgsiz - 2)
					ErrorStr = ""
				else:
					ErrorStr = "UNKNOWN ERROR"
			chksum = ser.read(1)
			# chksum Verarbeitung hier einfügen !!!
	#print "Command: ", repr(cmdmsg)
	#print "Reply:   ", repr(rplymsg)
	#print "Error:   ", ErrorStr
	#print str(seqnum)
	
	seqnum = seqnum + 1
	if seqnum == 256:
		seqnum = 0
		
	ser.flushInput()
	ser.close()
	return rplymsg

def STK500_Init():
	print "Signature:  ", WriteCmd(chr(CMD_SIGN_ON))[1:], ErrorStr
	
	tc_id = ord(WriteCmd(chr(CMD_GET_PARAMETER) + chr(PARAM_TOPCARD_DETECT)))
	if tc_id == 0xFF:
		tc_str = "NONE"
	elif tc_id == 0xAA:
		tc_str = "STK501"
	elif tc_id == 0x55:
		tc_str = "STK502"
	elif tc_id == 0xFA:
		tc_str = "STK503"
	elif tc_id == 0xEE:
		tc_str = "STK504"
	elif tc_id == 0xE4:
		tc_str = "STK505"
	elif tc_id == 0xDD:
		tc_str = "STK520"
	else:
		tc_str = ErrorStr
	
	print "Topcard-ID: ", "0x%X"%(tc_id), "-->", tc_str
	print "HW-Version: ", ord(WriteCmd(chr(CMD_GET_PARAMETER) + chr(PARAM_HW_VER))), ErrorStr
	print "FW-Version: ", ord(WriteCmd(chr(CMD_GET_PARAMETER) + chr(PARAM_SW_MAJOR))), ".",\
						  ord(WriteCmd(chr(CMD_GET_PARAMETER) + chr(PARAM_SW_MINOR))), ".",\
						  ord(WriteCmd(chr(CMD_GET_PARAMETER) + chr(PARAM_BUILD_NUMBER_HIGH))),\
						  ord(WriteCmd(chr(CMD_GET_PARAMETER) + chr(PARAM_BUILD_NUMBER_LOW))), ErrorStr
	print
	STK500_GetVoltages()
	print
	STK500_GetOscillator()
	print

def STK500_GetVoltages():
	print "Supply voltage:    ", ord(WriteCmd(chr(CMD_GET_PARAMETER) + chr(PARAM_VTARGET))) / 10.0, "V", ErrorStr
	print "Reference voltage: ", ord(WriteCmd(chr(CMD_GET_PARAMETER) + chr(PARAM_VADJUST))) / 10.0, "V", ErrorStr

def STK500_SetVoltages():
	WriteCmd(chr(CMD_SET_PARAMETER) + chr(PARAM_VTARGET) + chr(int(float(raw_input("Supply voltage?    ")) * 10)))
	WriteCmd(chr(CMD_SET_PARAMETER) + chr(PARAM_VADJUST) + chr(int(float(raw_input("Reference voltage? ")) * 10)))

def STK500_GetOscillator():
	pscale = ord(WriteCmd(chr(CMD_GET_PARAMETER) + chr(PARAM_OSC_PSCALE)))
	cmatch = ord(WriteCmd(chr(CMD_GET_PARAMETER) + chr(PARAM_OSC_CMATCH)))
	print "PARAM_OSC_PSCALE:  ", pscale, ErrorStr
	print "PARAM_OSC_CMATCH:  ", cmatch, ErrorStr
	print "Frequency:         ", int(3685000 / (cmatch + 1)), "Hz"

def STK500_SetOscillator():
	WriteCmd(chr(CMD_SET_PARAMETER) + chr(PARAM_OSC_CMATCH) + chr(int(3685000 / float(raw_input("Frequency (Hz)?  ")))))



STK500_Init()
if raw_input("Change voltages y/n (n)?  ") == 'y':
	STK500_SetVoltages()
	STK500_GetVoltages()
print
if raw_input("Change frequency y/n (n)? ") == 'y':
	STK500_SetOscillator()
	STK500_GetOscillator()
print
