307 lines
8.2 KiB
C
307 lines
8.2 KiB
C
/*
|
|
* avrdude - A Downloader/Uploader for AVR device programmers
|
|
* Copyright (C) 2021 Dawid Buchwald
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/* $Id$ */
|
|
|
|
/*
|
|
* Based on pymcuprog
|
|
* See https://github.com/microchip-pic-avr-tools/pymcuprog
|
|
*/
|
|
|
|
#include "ac_cfg.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "avrdude.h"
|
|
#include "libavrdude.h"
|
|
#include "updi_constants.h"
|
|
#include "updi_link.h"
|
|
#include "updi_readwrite.h"
|
|
|
|
int updi_read_cs(const PROGRAMMER *pgm, uint8_t address, uint8_t *value) {
|
|
/*
|
|
def read_cs(self, address):
|
|
"""
|
|
Read from Control/Status space
|
|
|
|
:param address: address (index) to read
|
|
:return: value read
|
|
"""
|
|
return self.datalink.ldcs(address)
|
|
*/
|
|
return updi_link_ldcs(pgm, address, value);
|
|
}
|
|
|
|
int updi_write_cs(const PROGRAMMER *pgm, uint8_t address, uint8_t value) {
|
|
/*
|
|
def write_cs(self, address, value):
|
|
"""
|
|
Write to Control/Status space
|
|
|
|
:param address: address (index) to write
|
|
:param value: 8-bit value to write
|
|
"""
|
|
return self.datalink.stcs(address, value)
|
|
*/
|
|
return updi_link_stcs(pgm, address, value);
|
|
}
|
|
|
|
int updi_write_key(const PROGRAMMER *pgm, unsigned char *buffer, uint8_t size_type, uint16_t size) {
|
|
/*
|
|
def write_key(self, size, key):
|
|
"""
|
|
Write a KEY into UPDI
|
|
|
|
:param size: size of key to send
|
|
:param key: key value
|
|
"""
|
|
return self.datalink.key(size, key)
|
|
*/
|
|
return updi_link_key(pgm, buffer, size_type, size);
|
|
}
|
|
|
|
int updi_read_sib(const PROGRAMMER *pgm, unsigned char *buffer, uint16_t size) {
|
|
/*
|
|
def read_sib(self):
|
|
"""
|
|
Read the SIB from UPDI
|
|
|
|
:return: SIB string (bytearray) read
|
|
"""
|
|
return self.datalink.read_sib()
|
|
*/
|
|
return updi_link_read_sib(pgm, buffer, size);
|
|
}
|
|
|
|
int updi_read_byte(const PROGRAMMER *pgm, uint32_t address, uint8_t *value) {
|
|
/*
|
|
def read_byte(self, address):
|
|
"""
|
|
Read a single byte from UPDI
|
|
|
|
:param address: address to read from
|
|
:return: value read
|
|
"""
|
|
return self.datalink.ld(address)
|
|
*/
|
|
return updi_link_ld(pgm, address, value);
|
|
}
|
|
|
|
int updi_write_byte(const PROGRAMMER *pgm, uint32_t address, uint8_t value) {
|
|
/*
|
|
def write_byte(self, address, value):
|
|
"""
|
|
Writes a single byte to UPDI
|
|
|
|
:param address: address to write to
|
|
:param value: value to write
|
|
"""
|
|
return self.datalink.st(address, value)
|
|
*/
|
|
return updi_link_st(pgm, address, value);
|
|
}
|
|
|
|
int updi_read_data(const PROGRAMMER *pgm, uint32_t address, uint8_t *buffer, uint16_t size) {
|
|
/*
|
|
def read_data(self, address, size):
|
|
"""
|
|
Reads a number of bytes of data from UPDI
|
|
|
|
:param address: address to write to
|
|
:param size: number of bytes to read
|
|
"""
|
|
self.logger.debug("Reading %d bytes from 0x%04X", size, address)
|
|
# Range check
|
|
if size > constants.UPDI_MAX_REPEAT_SIZE:
|
|
raise PymcuprogError("Can't read that many bytes in one go")
|
|
|
|
# Store the address
|
|
self.datalink.st_ptr(address)
|
|
|
|
# Fire up the repeat
|
|
if size > 1:
|
|
self.datalink.repeat(size)
|
|
|
|
# Do the read(s)
|
|
return self.datalink.ld_ptr_inc(size)
|
|
*/
|
|
pmsg_debug("reading %d bytes from 0x%06X\n", size, address);
|
|
|
|
if (size > UPDI_MAX_REPEAT_SIZE) {
|
|
pmsg_debug("cannot read that many bytes in one go\n");
|
|
return -1;
|
|
}
|
|
|
|
if (updi_link_st_ptr(pgm, address) < 0) {
|
|
pmsg_debug("ST_PTR operation failed\n");
|
|
return -1;
|
|
}
|
|
|
|
if (size > 1) {
|
|
if (updi_link_repeat(pgm, size) < 0) {
|
|
pmsg_debug("repeat operation failed\n");
|
|
return -1;
|
|
}
|
|
}
|
|
return updi_link_ld_ptr_inc(pgm, buffer, size);
|
|
}
|
|
|
|
int updi_write_data(const PROGRAMMER *pgm, uint32_t address, uint8_t *buffer, uint16_t size) {
|
|
/*
|
|
def write_data(self, address, data):
|
|
"""
|
|
Writes a number of bytes to memory
|
|
|
|
:param address: address to write to
|
|
:param data: data to write
|
|
"""
|
|
# Special case of 1 byte
|
|
if len(data) == 1:
|
|
return self.datalink.st(address, data[0])
|
|
# Special case of 2 byte
|
|
if len(data) == 2:
|
|
self.datalink.st(address, data[0])
|
|
return self.datalink.st(address + 1, data[1])
|
|
|
|
# Range check
|
|
if len(data) > constants.UPDI_MAX_REPEAT_SIZE:
|
|
raise PymcuprogError("Invalid length")
|
|
|
|
# Store the address
|
|
self.datalink.st_ptr(address)
|
|
|
|
# Fire up the repeat
|
|
self.datalink.repeat(len(data))
|
|
return self.datalink.st_ptr_inc(data)
|
|
*/
|
|
if (size == 1) {
|
|
return updi_link_st(pgm, address, buffer[0]);
|
|
}
|
|
if (size == 2) {
|
|
if (updi_link_st(pgm, address, buffer[0]) < 0) {
|
|
pmsg_debug("ST operation failed\n");
|
|
return -1;
|
|
}
|
|
return updi_link_st(pgm, address+1, buffer[1]);
|
|
}
|
|
if (size > UPDI_MAX_REPEAT_SIZE) {
|
|
pmsg_debug("invalid length\n");
|
|
return -1;
|
|
}
|
|
if (updi_link_st_ptr(pgm, address) < 0) {
|
|
pmsg_debug("ST_PTR operation failed\n");
|
|
return -1;
|
|
}
|
|
if (updi_link_repeat(pgm, size) < 0) {
|
|
pmsg_debug("repeat operation failed\n");
|
|
return -1;
|
|
}
|
|
return updi_link_st_ptr_inc(pgm, buffer, size);
|
|
}
|
|
|
|
int updi_read_data_words(const PROGRAMMER *pgm, uint32_t address, uint8_t *buffer, uint16_t size) {
|
|
/*
|
|
def read_data_words(self, address, words):
|
|
"""
|
|
Reads a number of words of data from UPDI
|
|
|
|
:param address: address to write to
|
|
:param words: number of words to read
|
|
"""
|
|
self.logger.debug("Reading %d words from 0x%04X", words, address)
|
|
|
|
# Range check
|
|
if words > constants.UPDI_MAX_REPEAT_SIZE >> 1:
|
|
raise PymcuprogError("Can't read that many words in one go")
|
|
|
|
# Store the address
|
|
self.datalink.st_ptr(address)
|
|
|
|
# Fire up the repeat
|
|
if words > 1:
|
|
self.datalink.repeat(words)
|
|
|
|
# Do the read
|
|
return self.datalink.ld_ptr_inc16(words)
|
|
*/
|
|
pmsg_debug("reading %d words from 0x%06X", size, address);
|
|
|
|
if (size > (UPDI_MAX_REPEAT_SIZE >> 1)) {
|
|
pmsg_debug("cannot read that many words in one go\n");
|
|
return -1;
|
|
}
|
|
|
|
if (updi_link_st_ptr(pgm, address) < 0) {
|
|
pmsg_debug("ST_PTR operation failed\n");
|
|
return -1;
|
|
}
|
|
|
|
if (size > 1) {
|
|
if (updi_link_repeat(pgm, size) < 0) {
|
|
pmsg_debug("repeat operation failed\n");
|
|
return -1;
|
|
}
|
|
}
|
|
return updi_link_ld_ptr_inc16(pgm, buffer, size);
|
|
}
|
|
|
|
int updi_write_data_words(const PROGRAMMER *pgm, uint32_t address, uint8_t *buffer, uint16_t size) {
|
|
/*
|
|
def write_data_words(self, address, data):
|
|
"""
|
|
Writes a number of words to memory
|
|
|
|
:param address: address to write to
|
|
:param data: data to write
|
|
"""
|
|
# Special-case of 1 word
|
|
if len(data) == 2:
|
|
value = data[0] + (data[1] << 8)
|
|
return self.datalink.st16(address, value)
|
|
|
|
# Range check
|
|
if len(data) > constants.UPDI_MAX_REPEAT_SIZE << 1:
|
|
raise PymcuprogError("Invalid length")
|
|
|
|
# Store the address
|
|
self.datalink.st_ptr(address)
|
|
|
|
# Fire up the repeat
|
|
self.datalink.repeat(len(data) >> 1)
|
|
return self.datalink.st_ptr_inc16(data)
|
|
*/
|
|
if (size == 2) {
|
|
return updi_link_st16(pgm, address, buffer[0] + (buffer[1] << 8));
|
|
}
|
|
if (size > UPDI_MAX_REPEAT_SIZE << 1) {
|
|
pmsg_debug("invalid length\n");
|
|
return -1;
|
|
}
|
|
if (updi_link_st_ptr(pgm, address) < 0) {
|
|
pmsg_debug("ST_PTR operation failed\n");
|
|
return -1;
|
|
}
|
|
return updi_link_st_ptr_inc16_RSD(pgm, buffer, size >> 1, -1);
|
|
}
|