avrdude/src/updi_readwrite.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);
}