Added support for writing USERROW memory

This commit is contained in:
Dawid Buchwald 2021-12-18 16:47:37 +01:00
parent c3100763cb
commit d1dddad896
13 changed files with 4032 additions and 0 deletions

39
.gitignore vendored Normal file
View File

@ -0,0 +1,39 @@
avrdude
libavrdude.a
libavrdude.la
Makefile
Makefile.in
*.o
*.lo
libtool
ltmain.sh
.deps/
.libs/
INSTALL
ac_cfg.h
ac_cfg.h.in
aclocal.m4
autom4te.cache/
avrdude.conf
avrdude.conf.tmp
avrdude.spec
compile
config.guess
config.log
config.status
config.sub
config_gram.c
config_gram.h
configure
configure~
depcomp
doc/mdate-sh
doc/texinfo.tex
install-sh
lexer.c
missing
stamp-h1
windows/.deps/
ylwrap
m4/
*.bin

View File

@ -16562,6 +16562,13 @@ part
readsize = 0x4; readsize = 0x4;
; ;
memory "userrow"
size = 0x20;
offset = 0x1080;
page_size = 0x20;
readsize = 0x20;
;
memory "data" memory "data"
# SRAM, only used to supply the offset # SRAM, only used to supply the offset
offset = 0x1000000; offset = 0x1000000;

965
serialupdi.c Normal file
View File

@ -0,0 +1,965 @@
/*
* 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$ */
/*
* Interface to the SerialUPDI programmer.
*
* 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 "serialupdi.h"
#include "updi_link.h"
#include "updi_state.h"
#include "updi_readwrite.h"
#include "updi_nvm.h"
#include "updi_constants.h"
static int serialupdi_enter_progmode(PROGRAMMER * pgm);
static int serialupdi_leave_progmode(PROGRAMMER * pgm);
static void serialupdi_setup(PROGRAMMER * pgm)
{
if ((pgm->cookie = malloc(sizeof(updi_state))) == 0) {
avrdude_message(MSG_INFO,
"%s: serialupdi_setup(): Out of memory allocating private data\n",
progname);
exit(1);
}
memset(pgm->cookie, 0, sizeof(updi_state));
updi_set_datalink_mode(pgm, UPDI_LINK_MODE_16BIT);
}
static void serialupdi_teardown(PROGRAMMER * pgm)
{
free(pgm->cookie);
}
static int serialupdi_open(PROGRAMMER * pgm, char * port)
{
strcpy(pgm->port, port);
return updi_link_open(pgm);
}
typedef enum {
APPLY_RESET,
RELEASE_RESET
} reset_mode;
static int serialupdi_reset(PROGRAMMER * pgm, reset_mode mode)
{
/*
def reset(self, apply_reset):
"""
Applies or releases an UPDI reset condition
:param apply_reset: True to apply, False to release
"""
if apply_reset:
self.logger.info("Apply reset")
self.readwrite.write_cs(constants.UPDI_ASI_RESET_REQ, constants.UPDI_RESET_REQ_VALUE)
else:
self.logger.info("Release reset")
self.readwrite.write_cs(constants.UPDI_ASI_RESET_REQ, 0x00)
*/
switch (mode) {
case APPLY_RESET:
avrdude_message(MSG_DEBUG, "%s: Sending reset request\n", progname);
return updi_write_cs(pgm, UPDI_ASI_RESET_REQ, UPDI_RESET_REQ_VALUE);
case RELEASE_RESET:
avrdude_message(MSG_DEBUG, "%s: Sending release reset request\n", progname);
return updi_write_cs(pgm, UPDI_ASI_RESET_REQ, 0x00);
}
return -1;
}
static int serialupdi_reset_connection(PROGRAMMER * pgm)
{
if (serialupdi_reset(pgm, APPLY_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Apply reset operation failed\n", progname);
return -1;
}
if (serialupdi_reset(pgm, RELEASE_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Release reset operation failed\n", progname);
return -1;
}
return updi_link_init(pgm);
}
static int serialupdi_decode_sib(PROGRAMMER * pgm, updi_sib_info * sib_info)
{
char * str_ptr;
sib_info->sib_string[SIB_INFO_STRING_LENGTH]=0;
avrdude_message(MSG_DEBUG, "%s: Received SIB: [%s]\n", progname, sib_info->sib_string);
memset(sib_info->family_string, 0, SIB_INFO_FAMILY_LENGTH+1);
memset(sib_info->nvm_string, 0, SIB_INFO_NVM_LENGTH+1);
memset(sib_info->debug_string, 0, SIB_INFO_DEBUG_LENGTH+1);
memset(sib_info->pdi_string, 0, SIB_INFO_PDI_LENGTH+1);
memset(sib_info->pdi_string, 0, SIB_INFO_PDI_LENGTH+1);
memset(sib_info->extra_string, 0, SIB_INFO_EXTRA_LENGTH+1);
memcpy(sib_info->family_string, sib_info->sib_string, SIB_INFO_FAMILY_LENGTH);
memcpy(sib_info->nvm_string, sib_info->sib_string + 8, SIB_INFO_NVM_LENGTH);
memcpy(sib_info->debug_string, sib_info->sib_string + 11, SIB_INFO_DEBUG_LENGTH);
memcpy(sib_info->pdi_string, sib_info->sib_string + 15, SIB_INFO_PDI_LENGTH);
strcpy(sib_info->extra_string, (char *)sib_info->sib_string + 19);
str_ptr = strstr(sib_info->nvm_string, ":");
if (!str_ptr) {
avrdude_message(MSG_INFO, "%s: Incorrect format of NVM string\n", progname);
return -1;
}
sib_info->nvm_version = *(str_ptr+1);
str_ptr = strstr(sib_info->debug_string, ":");
if (!str_ptr) {
avrdude_message(MSG_INFO, "%s: Incorrect format of DEBUG string\n", progname);
return -1;
}
sib_info->debug_version = *(str_ptr+1);
avrdude_message(MSG_DEBUG, "%s: Device family ID: %s\n", progname, sib_info->family_string);
avrdude_message(MSG_DEBUG, "%s: NVM interface: %s\n", progname, sib_info->nvm_string);
avrdude_message(MSG_DEBUG, "%s: Debug interface: %s\n", progname, sib_info->debug_string);
avrdude_message(MSG_DEBUG, "%s: PDI oscillator: %s\n", progname, sib_info->pdi_string);
avrdude_message(MSG_DEBUG, "%s: Extra information: %s\n", progname, sib_info->extra_string);
switch (sib_info->nvm_version) {
case '0':
avrdude_message(MSG_INFO, "%s: NVM type 0: 16-bit, page oriented write\n", progname);
updi_set_nvm_mode(pgm, UPDI_NVM_MODE_V0);
updi_set_datalink_mode(pgm, UPDI_LINK_MODE_16BIT);
break;
case '2':
avrdude_message(MSG_INFO, "%s: NVM type 2: 24-bit, word oriented write\n", progname);
updi_set_nvm_mode(pgm, UPDI_NVM_MODE_V2);
updi_set_datalink_mode(pgm, UPDI_LINK_MODE_24BIT);
break;
case '3':
avrdude_message(MSG_INFO, "%s: NVM type 3: 16-bit, page oriented\n", progname);
updi_set_nvm_mode(pgm, UPDI_NVM_MODE_V3);
updi_set_datalink_mode(pgm, UPDI_LINK_MODE_16BIT);
break;
default:
avrdude_message(MSG_INFO, "%s: Unsupported NVM type: %c, please update software\n", progname, sib_info->nvm_version);
return -1;
}
return 0;
}
static void serialupdi_close(PROGRAMMER * pgm)
{
avrdude_message(MSG_INFO, "%s: Leaving NVM programming mode\n", progname);
if (serialupdi_leave_progmode(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: Unable to leave NVM programming mode\n", progname);
}
updi_link_close(pgm);
}
static int serialupdi_wait_for_unlock(PROGRAMMER * pgm, unsigned int ms) {
/*
def wait_unlocked(self, timeout_ms):
"""
Waits for the device to be unlocked.
All devices boot up as locked until proven otherwise
:param timeout_ms: number of milliseconds to wait
"""
timeout = Timeout(timeout_ms)
while not timeout.expired():
if not self.readwrite.read_cs(constants.UPDI_ASI_SYS_STATUS) & (
1 << constants.UPDI_ASI_SYS_STATUS_LOCKSTATUS):
return True
self.logger.error("Timeout waiting for device to unlock")
return False
*/
unsigned long start_time;
unsigned long current_time;
struct timeval tv;
uint8_t status;
gettimeofday (&tv, NULL);
start_time = (tv.tv_sec * 1000000) + tv.tv_usec;
do {
if (updi_read_cs(pgm, UPDI_ASI_SYS_STATUS, &status) >= 0) {
if (!(status & (1 << UPDI_ASI_SYS_STATUS_LOCKSTATUS))) {
return 0;
}
}
gettimeofday (&tv, NULL);
current_time = (tv.tv_sec * 1000000) + tv.tv_usec;
} while ((current_time - start_time) < (ms * 1000));
avrdude_message(MSG_INFO, "%s: Timeout waiting for device to unlock\n", progname);
return -1;
}
typedef enum {
WAIT_FOR_UROW_LOW,
WAIT_FOR_UROW_HIGH
} urow_wait_mode;
static int serialupdi_wait_for_urow(PROGRAMMER * pgm, unsigned int ms, urow_wait_mode mode) {
/*
def wait_urow_prog(self, timeout_ms, wait_for_high):
"""
Waits for the device to be in user row write mode
User row is writeable on a locked device using this mechanism
:param timeout_ms: number of milliseconds to wait
:param wait_for_high: set True to wait for bit to go high; False to wait for low
"""
timeout = Timeout(timeout_ms)
while not timeout.expired():
status = self.readwrite.read_cs(constants.UPDI_ASI_SYS_STATUS)
if wait_for_high:
if status & (1 << constants.UPDI_ASI_SYS_STATUS_UROWPROG):
return True
else:
if not status & (1 << constants.UPDI_ASI_SYS_STATUS_UROWPROG):
return True
self.logger.error("Timeout waiting for device to enter UROW WRITE mode")
return False
*/
unsigned long start_time;
unsigned long current_time;
struct timeval tv;
uint8_t status;
gettimeofday (&tv, NULL);
start_time = (tv.tv_sec * 1000000) + tv.tv_usec;
do {
if (updi_read_cs(pgm, UPDI_ASI_SYS_STATUS, &status) >= 0) {
if (mode == WAIT_FOR_UROW_HIGH) {
if (status & (1 << UPDI_ASI_SYS_STATUS_UROWPROG)) {
return 0;
}
} else {
if (!(status & (1 << UPDI_ASI_SYS_STATUS_UROWPROG))) {
return 0;
}
}
}
gettimeofday (&tv, NULL);
current_time = (tv.tv_sec * 1000000) + tv.tv_usec;
} while ((current_time - start_time) < (ms * 1000));
avrdude_message(MSG_INFO, "%s: Timeout waiting for device to complete UROW WRITE\n", progname);
return -1;
}
static int serialupdi_in_prog_mode(PROGRAMMER * pgm, uint8_t * in_prog_mode)
{
/*
def in_prog_mode(self):
"""
Checks whether the NVM PROG flag is up
"""
if self.readwrite.read_cs(constants.UPDI_ASI_SYS_STATUS) & (1 << constants.UPDI_ASI_SYS_STATUS_NVMPROG):
return True
return False
*/
uint8_t value;
int rc;
rc = updi_read_cs(pgm, UPDI_ASI_SYS_STATUS, &value);
if (rc < 0) {
avrdude_message(MSG_INFO, "%s: Read CS operation failed\n", progname);
return rc;
}
if (value & (1 << UPDI_ASI_SYS_STATUS_NVMPROG)) {
*in_prog_mode = 1;
} else {
*in_prog_mode = 0;
}
return 0;
}
static int serialupdi_enter_progmode(PROGRAMMER * pgm)
{
/*
def enter_progmode(self):
"""
Enters into NVM programming mode
"""
# First check if NVM is already enabled
if self.in_prog_mode():
self.logger.info("Already in NVM programming mode")
return True
self.logger.info("Entering NVM programming mode")
# Put in the key
self.readwrite.write_key(constants.UPDI_KEY_64, constants.UPDI_KEY_NVM)
# Check key status
key_status = self.readwrite.read_cs(constants.UPDI_ASI_KEY_STATUS)
self.logger.debug("Key status = 0x%02X", key_status)
if not key_status & (1 << constants.UPDI_ASI_KEY_STATUS_NVMPROG):
self.logger.error("Key status = 0x%02X", key_status)
raise IOError("Key not accepted")
# Toggle reset
self.reset(apply_reset=True)
self.reset(apply_reset=False)
# And wait for unlock
if not self.wait_unlocked(100):
raise IOError("Failed to enter NVM programming mode: device is locked")
# Check for NVMPROG flag
if not self.in_prog_mode():
raise IOError("Failed to enter NVM programming mode")
self.logger.debug("Now in NVM programming mode")
return True
*/
uint8_t in_prog_mode;
unsigned char buffer[8];
uint8_t key_status;
if (serialupdi_in_prog_mode(pgm, &in_prog_mode) < 0) {
avrdude_message(MSG_INFO, "%s: Checking UPDI NVM prog mode failed\n", progname);
return -1;
}
if (in_prog_mode) {
avrdude_message(MSG_DEBUG, "%s: Already in prog mode\n", progname);
return 0;
}
memcpy(buffer, UPDI_KEY_NVM, sizeof(buffer));
if (updi_write_key(pgm, buffer, UPDI_KEY_64, sizeof(buffer)) < 0) {
avrdude_message(MSG_INFO, "%s: Writing NVM KEY failed\n", progname);
return -1;
}
if (updi_read_cs(pgm, UPDI_ASI_KEY_STATUS, &key_status) < 0) {
avrdude_message(MSG_INFO, "%s: Checking KEY status failed\n", progname);
return -1;
}
avrdude_message(MSG_DEBUG, "%s: Key status: 0x%02X\n", progname, key_status);
if (!(key_status & (1 << UPDI_ASI_KEY_STATUS_NVMPROG))) {
avrdude_message(MSG_INFO, "%s: Key was not accepted\n", progname);
return -1;
}
if (serialupdi_reset(pgm, APPLY_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Apply reset operation failed\n", progname);
return -1;
}
if (serialupdi_reset(pgm, RELEASE_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Release reset operation failed\n", progname);
return -1;
}
if (serialupdi_wait_for_unlock(pgm, 100) < 0) {
avrdude_message(MSG_INFO, "%s: Failed to enter NVM programming mode: device is locked\n", progname);
return -1;
}
if (serialupdi_in_prog_mode(pgm, &in_prog_mode) < 0) {
avrdude_message(MSG_INFO, "%s: Checking UPDI NVM prog mode failed\n", progname);
return -1;
}
if (!in_prog_mode) {
avrdude_message(MSG_INFO, "%s: Failed to enter NVM programming mode\n", progname);
return -1;
}
avrdude_message(MSG_DEBUG, "%s: Entered NVM programming mode\n", progname);
return 0;
}
static int serialupdi_leave_progmode(PROGRAMMER * pgm)
{
/*
def leave_progmode(self):
"""
Disables UPDI which releases any keys enabled
"""
self.logger.info("Leaving NVM programming mode")
self.reset(apply_reset=True)
self.reset(apply_reset=False)
self.readwrite.write_cs(constants.UPDI_CS_CTRLB,
(1 << constants.UPDI_CTRLB_UPDIDIS_BIT) | (1 << constants.UPDI_CTRLB_CCDETDIS_BIT))
*/
if (serialupdi_reset(pgm, APPLY_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Apply reset operation failed\n", progname);
return -1;
}
if (serialupdi_reset(pgm, RELEASE_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Release reset operation failed\n", progname);
return -1;
}
return updi_write_cs(pgm, UPDI_CS_CTRLB, (1 << UPDI_CTRLB_UPDIDIS_BIT) | (1 << UPDI_CTRLB_CCDETDIS_BIT));
}
static int serialupdi_write_userrow(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes)
{
/*
def write_user_row_locked_device(self, address, data):
"""
Writes data to the user row when the device is locked, using a key.
"""
# Put in the key
self.readwrite.write_key(constants.UPDI_KEY_64, constants.UPDI_KEY_UROW)
# Check key status
key_status = self.readwrite.read_cs(constants.UPDI_ASI_KEY_STATUS)
self.logger.debug("Key status = 0x%02X", key_status)
if not key_status & (1 << constants.UPDI_ASI_KEY_STATUS_UROWWRITE):
raise PymcuprogError("Key not accepted")
# Toggle reset
self.reset(apply_reset=True)
self.reset(apply_reset=False)
# Wait for mode to be entered
if not self.wait_urow_prog(500, wait_for_high=True):
raise PymcuprogError("Failed to enter urow write mode using key")
# At this point we can write one 'page' to the device, and have it transfered into the user row
# Transfer data
self.readwrite.write_data(address, data)
# Finalize
self.readwrite.write_cs(constants.UPDI_ASI_SYS_CTRLA,
(1 << constants.UPDI_ASI_SYS_CTRLA_UROW_FINAL) |
(1 << constants.UPDI_CTRLB_CCDETDIS_BIT))
# Wait for mode to be exited
if not self.wait_urow_prog(500, wait_for_high=False):
# Toggle reset
self.reset(apply_reset=True)
self.reset(apply_reset=False)
raise PymcuprogError("Failed to exit urow write mode")
# Clear status
self.readwrite.write_cs(constants.UPDI_ASI_KEY_STATUS,
(1 << constants.UPDI_ASI_KEY_STATUS_UROWWRITE) |
(1 << constants.UPDI_CTRLB_CCDETDIS_BIT))
# Toggle reset
self.reset(apply_reset=True)
self.reset(apply_reset=False)
*/
unsigned char buffer[8];
uint8_t key_status;
memcpy(buffer, UPDI_KEY_UROW, sizeof(buffer));
if (updi_write_key(pgm, buffer, UPDI_KEY_64, sizeof(buffer)) < 0) {
avrdude_message(MSG_INFO, "%s: Writing USERROW KEY failed\n", progname);
return -1;
}
if (updi_read_cs(pgm, UPDI_ASI_KEY_STATUS, &key_status) < 0) {
avrdude_message(MSG_INFO, "%s: Checking KEY status failed\n", progname);
return -1;
}
avrdude_message(MSG_DEBUG, "%s: Key status: 0x%02X\n", progname, key_status);
if (!(key_status & (1 << UPDI_ASI_KEY_STATUS_UROWWRITE))) {
avrdude_message(MSG_INFO, "%s: Key was not accepted\n", progname);
return -1;
}
if (serialupdi_reset(pgm, APPLY_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Apply reset operation failed\n", progname);
return -1;
}
if (serialupdi_reset(pgm, RELEASE_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Release reset operation failed\n", progname);
return -1;
}
if (serialupdi_wait_for_urow(pgm, 500, WAIT_FOR_UROW_HIGH) < 0) {
avrdude_message(MSG_INFO, "%s: Failed to enter USERROW programming mode\n", progname);
return -1;
}
if (updi_write_data(pgm, m->offset+addr, m->buf + addr, n_bytes) < 0) {
avrdude_message(MSG_INFO, "%s: Writing USER ROW failed\n", progname);
return -1;
}
if (updi_write_cs(pgm, UPDI_ASI_SYS_CTRLA, (1 << UPDI_ASI_SYS_CTRLA_UROW_FINAL) |
(1 << UPDI_CTRLB_CCDETDIS_BIT)) < 0) {
avrdude_message(MSG_INFO, "%s: Failed trying to commit user row write\n", progname);
return -1;
}
if (serialupdi_wait_for_urow(pgm, 500, WAIT_FOR_UROW_LOW) < 0) {
avrdude_message(MSG_DEBUG, "%s: Failed to exit USERROW programming mode\n", progname);
if (serialupdi_reset(pgm, APPLY_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Apply reset operation failed\n", progname);
return -1;
}
if (serialupdi_reset(pgm, RELEASE_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Release reset operation failed\n", progname);
return -1;
}
}
if (updi_write_cs(pgm, UPDI_ASI_KEY_STATUS, (1 << UPDI_ASI_KEY_STATUS_UROWWRITE) |
(1 << UPDI_CTRLB_CCDETDIS_BIT)) < 0) {
avrdude_message(MSG_INFO, "%s: Failed trying to complete user row write\n", progname);
return -1;
}
if (serialupdi_reset(pgm, APPLY_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Apply reset operation failed\n", progname);
return -1;
}
if (serialupdi_reset(pgm, RELEASE_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Release reset operation failed\n", progname);
return -1;
}
serialupdi_reset_connection(pgm);
serialupdi_enter_progmode(pgm);
return 0;
}
static int serialupdi_initialize(PROGRAMMER * pgm, AVRPART * p)
{
uint8_t value;
uint8_t reset_link_required=0;
if (updi_link_init(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: UPDI link initialization failed\n", progname);
return -1;
}
avrdude_message(MSG_INFO, "%s: UPDI link initialization OK\n", progname);
if (updi_read_cs(pgm, UPDI_ASI_SYS_STATUS, &value)<0) {
/* let's try reset the connection */
if (!serialupdi_reset_connection(pgm)) {
return -1;
}
if (updi_read_cs(pgm, UPDI_ASI_SYS_STATUS, &value)<0) {
avrdude_message(MSG_INFO, "%s: Read CS operation during initialization failed\n", progname);
return -1;
}
}
if (value & (1 << UPDI_ASI_SYS_STATUS_LOCKSTATUS)) {
avrdude_message(MSG_INFO, "%s: Device is locked\n", progname);
}
if (value & (1 << UPDI_ASI_SYS_STATUS_UROWPROG)) {
avrdude_message(MSG_INFO, "%s: Device in USER ROW programming state, leaving programming mode\n", progname);
reset_link_required = 1;
}
if (value & (1 << UPDI_ASI_SYS_STATUS_NVMPROG)) {
avrdude_message(MSG_INFO, "%s: Device in NVM programming state, leaving programming mode\n", progname);
reset_link_required = 1;
}
if (value & (1 << UPDI_ASI_SYS_STATUS_INSLEEP)) {
avrdude_message(MSG_INFO, "%s: Device is in SLEEP mode\n", progname);
}
if (value & (1 << UPDI_ASI_SYS_STATUS_RSTSYS)) {
avrdude_message(MSG_INFO, "%s: Device in reset status, trying to release it\n", progname);
if (serialupdi_reset(pgm, RELEASE_RESET)<0) {
return -1;
}
}
if (reset_link_required) {
if (serialupdi_reset_connection(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: UPDI link reset failed\n", progname);
return -1;
}
}
updi_sib_info * sib_info = updi_get_sib_info(pgm);
if (updi_read_sib(pgm, sib_info->sib_string, 32) < 0) {
/* this should never happen, let's try to reset connection and try again */
if (serialupdi_reset_connection(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: SerialUPDI reset connection failed\n", progname);
return -1;
}
if (updi_read_sib(pgm, sib_info->sib_string, 32) < 0) {
avrdude_message(MSG_INFO, "%s: Read SIB operation failed\n", progname);
return -1;
}
}
if (serialupdi_decode_sib(pgm, sib_info) < 0) {
avrdude_message(MSG_INFO, "%s: Decode SIB_INFO failed\n", progname);
return -1;
}
if (updi_link_init(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: UPDI link initialization failed\n", progname);
return -1;
}
avrdude_message(MSG_INFO, "%s: Entering NVM programming mode\n", progname);
/* try, but ignore failure */
serialupdi_enter_progmode(pgm);
return 0;
}
static void serialupdi_disable(PROGRAMMER * pgm)
{
/* Do nothing. */
return;
}
static void serialupdi_enable(PROGRAMMER * pgm)
{
/* Do nothing. */
return;
}
static void serialupdi_display(PROGRAMMER * pgm, const char * p)
{
return;
}
static int serialupdi_cmd(PROGRAMMER * pgm, const unsigned char * cmd,
unsigned char * res)
{
avrdude_message(MSG_INFO, "%s: error: cmd %s[%s] not implemented yet\n",
progname, cmd, res);
return -1;
}
static int serialupdi_program_enable(PROGRAMMER * pgm, AVRPART * p)
{
avrdude_message(MSG_INFO, "%s: error: program enable not implemented yet\n",
progname);
return -1;
}
static int serialupdi_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char * value)
{
return updi_read_byte(pgm, mem->offset + addr, value);
}
static int serialupdi_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char value)
{
if (strstr(mem->desc, "fuse") != 0) {
return updi_nvm_write_fuse(pgm, p, mem->offset + addr, value);
}
if (strcmp(mem->desc, "lock") == 0) {
return updi_nvm_write_fuse(pgm, p, mem->offset + addr, value);
}
if (strcmp(mem->desc, "eeprom") == 0) {
unsigned char buffer[1];
buffer[0]=value;
return updi_nvm_write_eeprom(pgm, p, mem->offset + addr, buffer, 1);
}
if (strcmp(mem->desc, "flash") == 0) {
unsigned char buffer[1];
buffer[0]=value;
return updi_nvm_write_flash(pgm, p, mem->offset + addr, buffer, 1);
}
return updi_write_byte(pgm, mem->offset + addr, value);
}
static int serialupdi_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes)
{
if (n_bytes > m->readsize) {
unsigned int read_offset = addr;
unsigned int remaining_bytes = n_bytes;
int read_bytes = 0;
int rc;
while (remaining_bytes > 0) {
rc = updi_read_data(pgm, m->offset + read_offset, m->buf + read_offset,
remaining_bytes > m->readsize ? m->readsize : remaining_bytes);
if (rc < 0) {
avrdude_message(MSG_INFO, "%s: Paged load operation failed\n", progname);
return rc;
} else {
read_bytes+=rc;
read_offset+=m->readsize;
remaining_bytes-=m->readsize;
}
}
return read_bytes;
} else {
return updi_read_data(pgm, m->offset + addr, m->buf + addr, n_bytes);
}
}
static int serialupdi_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes)
{
int rc;
if (n_bytes > m->page_size) {
unsigned int write_offset = addr;
unsigned int remaining_bytes = n_bytes;
int write_bytes = 0;
while (remaining_bytes > 0) {
if (strcmp(m->desc, "eeprom")==0) {
rc = updi_nvm_write_eeprom(pgm, p, m->offset + write_offset, m->buf + write_offset,
remaining_bytes > m->page_size ? m->page_size : remaining_bytes);
} else if (strcmp(m->desc, "flash")==0) {
rc = updi_nvm_write_flash(pgm, p, m->offset + write_offset, m->buf + write_offset,
remaining_bytes > m->page_size ? m->page_size : remaining_bytes);
} else if (strcmp(m->desc, "userrow")==0) {
rc = serialupdi_write_userrow(pgm, p, m, page_size, write_offset,
remaining_bytes > m->page_size ? m->page_size : remaining_bytes);
} else if (strcmp(m->desc, "fuses")==0) {
avrdude_message(MSG_DEBUG, "%s: Page write operation requested for fuses, falling back to byte-level write\n", progname);
return -1;
} else {
avrdude_message(MSG_INFO, "%s: Invalid memory type: <%s:%d>, 0x%06X, %d (0x%04X)\n", progname, m->desc, page_size, addr, n_bytes, n_bytes);
rc = -1;
}
if (rc < 0) {
avrdude_message(MSG_INFO, "%s: Paged write operation failed\n", progname);
return rc;
} else {
write_bytes+=rc;
write_offset+=m->page_size;
remaining_bytes-=m->page_size;
}
}
return write_bytes;
} else {
if (strcmp(m->desc, "eeprom")==0) {
rc = updi_nvm_write_eeprom(pgm, p, m->offset+addr, m->buf+addr, n_bytes);
} else if (strcmp(m->desc, "flash")==0) {
rc = updi_nvm_write_flash(pgm, p, m->offset+addr, m->buf+addr, n_bytes);
} else if (strcmp(m->desc, "userrow")==0) {
rc = serialupdi_write_userrow(pgm, p, m, page_size, addr, n_bytes);
} else if (strcmp(m->desc, "fuses")==0) {
avrdude_message(MSG_DEBUG, "%s: Page write operation requested for fuses, falling back to byte-level write\n", progname);
rc = -1;
} else {
avrdude_message(MSG_INFO, "%s: Invalid memory type: <%s:%d>, 0x%06X, %d (0x%04X)\n", progname, m->desc, page_size, addr, n_bytes, n_bytes);
rc = -1;
}
return rc;
}
}
static int serialupdi_unlock(PROGRAMMER * pgm, AVRPART * p)
{
/*
def unlock(self):
"""
Unlock by chip erase
"""
# Put in the key
self.readwrite.write_key(constants.UPDI_KEY_64, constants.UPDI_KEY_CHIPERASE)
# Check key status
key_status = self.readwrite.read_cs(constants.UPDI_ASI_KEY_STATUS)
self.logger.debug("Key status = 0x%02X", key_status)
if not key_status & (1 << constants.UPDI_ASI_KEY_STATUS_CHIPERASE):
raise PymcuprogError("Key not accepted")
# Toggle reset
self.reset(apply_reset=True)
self.reset(apply_reset=False)
# And wait for unlock
if not self.wait_unlocked(500):
raise PymcuprogError("Failed to chip erase using key")
*/
unsigned char buffer[8];
uint8_t key_status;
memcpy(buffer, UPDI_KEY_CHIPERASE, sizeof(buffer));
if (updi_write_key(pgm, buffer, UPDI_KEY_64, sizeof(buffer)) < 0) {
avrdude_message(MSG_INFO, "%s: Writing NVM KEY failed\n", progname);
return -1;
}
if (updi_read_cs(pgm, UPDI_ASI_KEY_STATUS, &key_status) < 0) {
avrdude_message(MSG_INFO, "%s: Checking KEY status failed\n", progname);
return -1;
}
avrdude_message(MSG_DEBUG, "%s: Key status: 0x%02X\n", progname, key_status);
if (!(key_status & (1 << UPDI_ASI_KEY_STATUS_CHIPERASE))) {
avrdude_message(MSG_INFO, "%s: Key not accepted\n", progname);
return -1;
}
if (serialupdi_reset(pgm, APPLY_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Apply reset operation failed\n", progname);
return -1;
}
if (serialupdi_reset(pgm, RELEASE_RESET) < 0) {
avrdude_message(MSG_INFO, "%s: Release reset operation failed\n", progname);
return -1;
}
if (serialupdi_wait_for_unlock(pgm, 500) < 0) {
avrdude_message(MSG_INFO, "%s: Waiting for unlock failed\n", progname);
return -1;
}
if (updi_link_init(pgm) < 0) {
avrdude_message(MSG_INFO, "%s: UPDI link reinitialization failed\n", progname);
return -1;
}
return serialupdi_enter_progmode(pgm);
}
static int serialupdi_chip_erase(PROGRAMMER * pgm, AVRPART * p)
{
uint8_t value;
if (updi_read_cs(pgm, UPDI_ASI_SYS_STATUS, &value)<0) {
avrdude_message(MSG_INFO, "%s: Read CS operation during chip erase failed\n", progname);
return -1;
}
if (value & (1 << UPDI_ASI_SYS_STATUS_LOCKSTATUS)) {
avrdude_message(MSG_INFO, "%s: Device is locked\n", progname);
if (ovsigck) {
avrdude_message(MSG_INFO, "%s: Attempting device erase\n", progname);
return serialupdi_unlock(pgm, p);
}
} else {
return updi_nvm_chip_erase(pgm, p);
}
return -1;
}
static int serialupdi_page_erase(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
unsigned int baseaddr)
{
avrdude_message(MSG_INFO, "%s: error: page erase not implemented yet\n",
progname);
return -1;
}
static int serialupdi_read_signature(PROGRAMMER * pgm, AVRPART *p, AVRMEM *m) {
uint8_t value;
if (updi_read_cs(pgm, UPDI_ASI_SYS_STATUS, &value)<0) {
avrdude_message(MSG_INFO, "%s: Read CS operation during signature read failed\n", progname);
return -1;
}
if (value & (1 << UPDI_ASI_SYS_STATUS_LOCKSTATUS)) {
m->buf[0]=0x00;
m->buf[1]=0x00;
m->buf[2]=0x00;
} else {
updi_read_byte(pgm, m->offset + 0, m->buf);
updi_read_byte(pgm, m->offset + 1, m->buf+1);
updi_read_byte(pgm, m->offset + 2, m->buf+2);
}
return 3;
}
static int serialupdi_read_sib(PROGRAMMER * pgm, AVRPART *p, char *sib) {
updi_sib_info * sib_info = updi_get_sib_info(pgm);
memcpy(sib, sib_info->sib_string, 32);
return 0;
}
void serialupdi_initpgm(PROGRAMMER * pgm)
{
strcpy(pgm->type, "serialupdi");
/*
* mandatory functions
*/
pgm->initialize = serialupdi_initialize;
pgm->display = serialupdi_display;
pgm->enable = serialupdi_enable;
pgm->disable = serialupdi_disable;
pgm->program_enable = serialupdi_program_enable;
pgm->chip_erase = serialupdi_chip_erase;
pgm->cmd = serialupdi_cmd;
pgm->open = serialupdi_open;
pgm->close = serialupdi_close;
pgm->read_byte = serialupdi_read_byte;
pgm->write_byte = serialupdi_write_byte;
/*
* optional functions
*/
pgm->unlock = serialupdi_unlock;
pgm->paged_write = serialupdi_paged_write;
pgm->read_sig_bytes = serialupdi_read_signature;
pgm->read_sib = serialupdi_read_sib;
pgm->paged_load = serialupdi_paged_load;
pgm->page_erase = serialupdi_page_erase;
pgm->setup = serialupdi_setup;
pgm->teardown = serialupdi_teardown;
}
const char serialupdi_desc[] = "Driver for SerialUPDI programmers";

43
serialupdi.h Normal file
View File

@ -0,0 +1,43 @@
/*
* 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
*/
#ifndef serialupdi_h
#define serialupdi_h
#include "libavrdude.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const char serialupdi_desc[];
void serialupdi_initpgm (PROGRAMMER * pgm);
#ifdef __cplusplus
}
#endif
#endif /* serialupdi_h */

156
updi_constants.h Normal file
View File

@ -0,0 +1,156 @@
/*
* 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
*/
#ifndef updi_constants_h
#define updi_constants_h
#define UPDI_BREAK 0x00
#define UPDI_LDS 0x00
#define UPDI_STS 0x40
#define UPDI_LD 0x20
#define UPDI_ST 0x60
#define UPDI_LDCS 0x80
#define UPDI_STCS 0xC0
#define UPDI_REPEAT 0xA0
#define UPDI_KEY 0xE0
#define UPDI_PTR 0x00
#define UPDI_PTR_INC 0x04
#define UPDI_PTR_ADDRESS 0x08
#define UPDI_ADDRESS_8 0x00
#define UPDI_ADDRESS_16 0x04
#define UPDI_ADDRESS_24 0x08
#define UPDI_DATA_8 0x00
#define UPDI_DATA_16 0x01
#define UPDI_DATA_24 0x02
#define UPDI_KEY_SIB 0x04
#define UPDI_KEY_KEY 0x00
#define UPDI_KEY_64 0x00
#define UPDI_KEY_128 0x01
#define UPDI_KEY_256 0x02
#define UPDI_SIB_8BYTES UPDI_KEY_64
#define UPDI_SIB_16BYTES UPDI_KEY_128
#define UPDI_SIB_32BYTES UPDI_KEY_256
#define UPDI_REPEAT_BYTE 0x00
#define UPDI_REPEAT_WORD 0x01
#define UPDI_PHY_SYNC 0x55
#define UPDI_PHY_ACK 0x40
#define UPDI_MAX_REPEAT_SIZE (0xFF+1) // Repeat counter of 1-byte, with off-by-one counting
//# CS and ASI Register Address map
#define UPDI_CS_STATUSA 0x00
#define UPDI_CS_STATUSB 0x01
#define UPDI_CS_CTRLA 0x02
#define UPDI_CS_CTRLB 0x03
#define UPDI_ASI_KEY_STATUS 0x07
#define UPDI_ASI_RESET_REQ 0x08
#define UPDI_ASI_CTRLA 0x09
#define UPDI_ASI_SYS_CTRLA 0x0A
#define UPDI_ASI_SYS_STATUS 0x0B
#define UPDI_ASI_CRC_STATUS 0x0C
#define UPDI_CTRLA_IBDLY_BIT 7
#define UPDI_CTRLB_CCDETDIS_BIT 3
#define UPDI_CTRLB_UPDIDIS_BIT 2
#define UPDI_KEY_NVM "NVMProg "
#define UPDI_KEY_CHIPERASE "NVMErase"
#define UPDI_KEY_UROW "NVMUs&te"
#define UPDI_ASI_STATUSA_REVID 4
#define UPDI_ASI_STATUSB_PESIG 0
#define UPDI_ASI_KEY_STATUS_CHIPERASE 3
#define UPDI_ASI_KEY_STATUS_NVMPROG 4
#define UPDI_ASI_KEY_STATUS_UROWWRITE 5
#define UPDI_ASI_SYS_STATUS_RSTSYS 5
#define UPDI_ASI_SYS_STATUS_INSLEEP 4
#define UPDI_ASI_SYS_STATUS_NVMPROG 3
#define UPDI_ASI_SYS_STATUS_UROWPROG 2
#define UPDI_ASI_SYS_STATUS_LOCKSTATUS 0
#define UPDI_ASI_SYS_CTRLA_UROW_FINAL 1
#define UPDI_RESET_REQ_VALUE 0x59
// FLASH CONTROLLER
#define UPDI_NVMCTRL_CTRLA 0x00
#define UPDI_NVMCTRL_CTRLB 0x01
#define UPDI_NVMCTRL_STATUS 0x02
#define UPDI_NVMCTRL_INTCTRL 0x03
#define UPDI_NVMCTRL_INTFLAGS 0x04
#define UPDI_NVMCTRL_DATAL 0x06
#define UPDI_NVMCTRL_DATAH 0x07
#define UPDI_NVMCTRL_ADDRL 0x08
#define UPDI_NVMCTRL_ADDRH 0x09
// NVMCTRL v0 CTRLA
#define UPDI_V0_NVMCTRL_CTRLA_NOP 0x00
#define UPDI_V0_NVMCTRL_CTRLA_WRITE_PAGE 0x01
#define UPDI_V0_NVMCTRL_CTRLA_ERASE_PAGE 0x02
#define UPDI_V0_NVMCTRL_CTRLA_ERASE_WRITE_PAGE 0x03
#define UPDI_V0_NVMCTRL_CTRLA_PAGE_BUFFER_CLR 0x04
#define UPDI_V0_NVMCTRL_CTRLA_CHIP_ERASE 0x05
#define UPDI_V0_NVMCTRL_CTRLA_ERASE_EEPROM 0x06
#define UPDI_V0_NVMCTRL_CTRLA_WRITE_FUSE 0x07
// NVMCTRL v2 CTRLA
#define UPDI_V2_NVMCTRL_CTRLA_NOCMD 0x00
#define UPDI_V2_NVMCTRL_CTRLA_FLASH_WRITE 0x02
#define UPDI_V2_NVMCTRL_CTRLA_FLASH_PAGE_ERASE 0x08
#define UPDI_V2_NVMCTRL_CTRLA_EEPROM_ERASE_WRITE 0x13
#define UPDI_V2_NVMCTRL_CTRLA_CHIP_ERASE 0x20
#define UPDI_V2_NVMCTRL_CTRLA_EEPROM_ERASE 0x30
// NVMCTRL v3 CTRLA
#define UPDI_V3_NVMCTRL_CTRLA_NOCMD 0x00
#define UPDI_V3_NVMCTRL_CTRLA_NOP 0x01
#define UPDI_V3_NVMCTRL_CTRLA_FLASH_PAGE_WRITE 0x04
#define UPDI_V3_NVMCTRL_CTRLA_FLASH_PAGE_ERASE_WRITE 0x05
#define UPDI_V3_NVMCTRL_CTRLA_FLASH_PAGE_ERASE 0x08
#define UPDI_V3_NVMCTRL_CTRLA_FLASH_PAGE_BUFFER_CLEAR 0x0F
#define UPDI_V3_NVMCTRL_CTRLA_EEPROM_PAGE_WRITE 0x14
#define UPDI_V3_NVMCTRL_CTRLA_EEPROM_PAGE_ERASE_WRITE 0x15
#define UPDI_V3_NVMCTRL_CTRLA_EEPROM_PAGE_ERASE 0x17
#define UPDI_V3_NVMCTRL_CTRLA_EEPROM_PAGE_BUFFER_CLEAR 0x1F
#define UPDI_V3_NVMCTRL_CTRLA_CHIP_ERASE 0x20
#define UPDI_V3_NVMCTRL_CTRLA_EEPROM_ERASE 0x30
#define UPDI_NVM_STATUS_WRITE_ERROR 2
#define UPDI_NVM_STATUS_EEPROM_BUSY 1
#define UPDI_NVM_STATUS_FLASH_BUSY 0
#endif /* updi_constants_h */

930
updi_link.c Normal file
View File

@ -0,0 +1,930 @@
/*
* 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_link.h"
#include "updi_constants.h"
#include "updi_state.h"
#include <sys/time.h>
void msleep(int tms)
{
struct timeval tv;
tv.tv_sec = tms / 1000;
tv.tv_usec = (tms % 1000) * 1000;
select (0, NULL, NULL, NULL, &tv);
}
static int updi_physical_open(PROGRAMMER* pgm, int baudrate, unsigned long cflags)
{
serial_recv_timeout = 100;
union pinfo pinfo;
pinfo.serialinfo.baud = baudrate;
pinfo.serialinfo.cflags = cflags;
avrdude_message(MSG_DEBUG, "%s: Opening serial port...\n", progname);
if (serial_open(pgm->port, pinfo, &pgm->fd)==-1) {
avrdude_message(MSG_DEBUG, "%s: Serial port open failed!\n", progname);
return -1;
}
/*
* drain any extraneous input
*/
serial_drain(&pgm->fd, 0);
return 0;
}
static void updi_physical_close(PROGRAMMER* pgm)
{
serial_close(&pgm->fd);
pgm->fd.ifd = -1;
}
static int updi_physical_send(PROGRAMMER * pgm, unsigned char * buf, size_t len)
{
size_t i;
int rv;
avrdude_message(MSG_DEBUG, "%s: Sending %lu bytes [", progname, len);
for (i=0; i<len; i++) {
avrdude_message(MSG_DEBUG, "0x%02x", buf[i]);
if (i<len-1) {
avrdude_message(MSG_DEBUG, ", ");
}
}
avrdude_message(MSG_DEBUG, "]\n");
rv = serial_send(&pgm->fd, buf, len);
serial_recv(&pgm->fd, buf, len);
return rv;
}
static int updi_physical_recv(PROGRAMMER * pgm, unsigned char * buf, size_t len)
{
size_t i;
int rv;
rv = serial_recv(&pgm->fd, buf, len);
if (rv < 0) {
avrdude_message(MSG_DEBUG,
"%s: serialupdi_recv(): programmer is not responding\n",
progname);
return -1;
}
avrdude_message(MSG_DEBUG, "%s: Received %lu bytes [", progname, len);
for (i=0; i<len; i++) {
avrdude_message(MSG_DEBUG, "0x%02x", buf[i]);
if (i<len-1) {
avrdude_message(MSG_DEBUG, ", ");
}
}
avrdude_message(MSG_DEBUG, "]\n");
return len;
}
static int updi_physical_send_double_break(PROGRAMMER * pgm)
{
unsigned char buffer[1];
avrdude_message(MSG_DEBUG, "%s: Sending double break\n", progname);
updi_physical_close(pgm);
if (updi_physical_open(pgm, 300, SERIAL_8E1)==-1) {
return -1;
}
buffer[0] = UPDI_BREAK;
serial_send(&pgm->fd, buffer, 1);
serial_recv(&pgm->fd, buffer, 1);
msleep(100);
buffer[0] = UPDI_BREAK;
serial_send(&pgm->fd, buffer, 1);
serial_recv(&pgm->fd, buffer, 1);
updi_physical_close(pgm);
return updi_physical_open(pgm, pgm->baudrate? pgm->baudrate: 115200, SERIAL_8E2);
}
int updi_physical_sib(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size)
{
/*
def sib(self):
"""
System information block is just a string coming back from a SIB command
"""
self.send([
constants.UPDI_PHY_SYNC,
constants.UPDI_KEY | constants.UPDI_KEY_SIB | constants.UPDI_SIB_32BYTES])
return self.ser.readline()
*/
unsigned char send_buffer[2];
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_KEY | UPDI_KEY_SIB | UPDI_SIB_32BYTES;
if (updi_physical_send(pgm, send_buffer, 2) < 0) {
avrdude_message(MSG_DEBUG, "%s: SIB request send failed\n", progname);
return -1;
}
return updi_physical_recv(pgm, buffer, size);
}
int updi_link_open(PROGRAMMER * pgm)
{
if (updi_physical_open(pgm, pgm->baudrate? pgm->baudrate: 115200, SERIAL_8E2) < 0) {
return -1;
}
return updi_physical_send_double_break(pgm);
}
void updi_link_close(PROGRAMMER * pgm)
{
updi_physical_close(pgm);
}
static int updi_link_init_session_parameters(PROGRAMMER * pgm)
{
/*
def _init_session_parameters(self):
"""
Set the inter-byte delay bit and disable collision detection
"""
self.stcs(constants.UPDI_CS_CTRLB, 1 << constants.UPDI_CTRLB_CCDETDIS_BIT)
self.stcs(constants.UPDI_CS_CTRLA, 1 << constants.UPDI_CTRLA_IBDLY_BIT)
*/
if (updi_link_stcs(pgm, UPDI_CS_CTRLB, 1 << UPDI_CTRLB_CCDETDIS_BIT) < 0) {
return -1;
}
if (updi_link_stcs(pgm, UPDI_CS_CTRLA, 1 << UPDI_CTRLA_IBDLY_BIT) < 0) {
return -1;
}
return 0;
}
static int updi_link_check(PROGRAMMER * pgm)
{
/*
def _check_datalink(self):
"""
Check UPDI by loading CS STATUSA
"""
try:
if self.ldcs(constants.UPDI_CS_STATUSA) != 0:
self.logger.info("UPDI init OK")
return True
except PymcuprogError:
self.logger.warning("Check failed")
return False
self.logger.info("UPDI not OK - reinitialisation required")
return False
*/
int result;
uint8_t value;
result = updi_link_ldcs(pgm, UPDI_CS_STATUSA, &value);
if (result < 0) {
avrdude_message(MSG_DEBUG, "%s: Check failed\n", progname);
return -1;
} else {
if (value > 0) {
avrdude_message(MSG_DEBUG, "%s: UDPI init OK\n", progname);
return 0;
} else {
avrdude_message(MSG_DEBUG, "%s: UDPI not OK - reinitialisation required\n", progname);
return -1;
}
}
}
int updi_link_init(PROGRAMMER * pgm)
{
/*
def init_datalink(self):
"""
Init DL layer
"""
self._init_session_parameters()
# Check
if not self._check_datalink():
# Send double break if all is not well, and re-check
self.updi_phy.send_double_break()
self._init_session_parameters()
if not self._check_datalink():
raise PymcuprogError("UPDI initialisation failed")
*/
if (updi_link_init_session_parameters(pgm) < 0) {
avrdude_message(MSG_DEBUG, "%s: Session initialisation failed\n", progname);
return -1;
}
if (updi_link_check(pgm) < 0) {
avrdude_message(MSG_DEBUG, "%s: Datalink not active, resetting...\n", progname);
if (updi_physical_send_double_break(pgm) < 0) {
avrdude_message(MSG_DEBUG, "%s: Datalink initialisation failed\n", progname);
return -1;
}
if (updi_link_init_session_parameters(pgm) < 0) {
avrdude_message(MSG_DEBUG, "%s: Session initialisation failed\n", progname);
return -1;
}
if (updi_link_check(pgm) < 0) {
avrdude_message(MSG_DEBUG, "%s: Restoring datalink failed\n", progname);
return -1;
}
}
return 0;
}
int updi_link_ldcs(PROGRAMMER * pgm, uint8_t address, uint8_t * value)
{
/*
def ldcs(self, address):
"""
Load data from Control/Status space
:param address: address to load
"""
self.logger.debug("LDCS from 0x%02X", address)
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_LDCS | (address & 0x0F)])
response = self.updi_phy.receive(self.LDCS_RESPONSE_BYTES)
numbytes_received = len(response)
if numbytes_received != self.LDCS_RESPONSE_BYTES:
raise PymcuprogError("Unexpected number of bytes in response: "
"{} byte(s) expected {} byte(s)".format(numbytes_received, self.LDCS_RESPONSE_BYTES))
return response[0]
*/
unsigned char buffer[2];
int result;
avrdude_message(MSG_DEBUG, "%s: LDCS from 0x%02X\n", progname, address);
buffer[0]=UPDI_PHY_SYNC;
buffer[1]=UPDI_LDCS | (address & 0x0F);
if (updi_physical_send(pgm, buffer, 2) < 0) {
avrdude_message(MSG_DEBUG, "%s: LDCS send operation failed\n", progname);
return -1;
}
result = updi_physical_recv(pgm, buffer, 1);
if (result != 1) {
if (result >= 0) {
avrdude_message(MSG_DEBUG, "%s: Incorrect response size, received %d instead of %d bytes\n", progname, result, 1);
}
return -1;
}
* value = buffer[0];
return 0;
}
int updi_link_stcs(PROGRAMMER * pgm, uint8_t address, uint8_t value)
{
/*
def stcs(self, address, value):
"""
Store a value to Control/Status space
:param address: address to store to
:param value: value to write
"""
self.logger.debug("STCS to 0x%02X", address)
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_STCS | (address & 0x0F), value])
*/
unsigned char buffer[3];
avrdude_message(MSG_DEBUG, "%s: STCS 0x%02X to address 0x%02X\n", progname, value, address);
buffer[0] = UPDI_PHY_SYNC;
buffer[1] = UPDI_STCS | (address & 0x0F);
buffer[2] = value;
return updi_physical_send(pgm, buffer, 3);
}
int updi_link_ld_ptr_inc(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size)
{
/*
def ld_ptr_inc(self, size):
"""
Loads a number of bytes from the pointer location with pointer post-increment
:param size: number of bytes to load
:return: values read
"""
self.logger.debug("LD8 from ptr++")
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_LD | constants.UPDI_PTR_INC |
constants.UPDI_DATA_8])
return self.updi_phy.receive(size)
*/
unsigned char send_buffer[2];
avrdude_message(MSG_DEBUG, "%s: LD8 from ptr++\n", progname);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_LD | UPDI_PTR_INC | UPDI_DATA_8;
if (updi_physical_send(pgm, send_buffer, 2) < 0) {
avrdude_message(MSG_DEBUG, "%s: LD_PTR_INC send operation failed\n", progname);
return -1;
}
return updi_physical_recv(pgm, buffer, size);
}
int updi_link_ld_ptr_inc16(PROGRAMMER * pgm, unsigned char * buffer, uint16_t words)
{
/*
def ld_ptr_inc16(self, words):
"""
Load a 16-bit word value from the pointer location with pointer post-increment
:param words: number of words to load
:return: values read
"""
self.logger.debug("LD16 from ptr++")
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_LD | constants.UPDI_PTR_INC |
constants.UPDI_DATA_16])
return self.updi_phy.receive(words << 1)
*/
unsigned char send_buffer[2];
avrdude_message(MSG_DEBUG, "%s: LD16 from ptr++\n", progname);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_LD | UPDI_PTR_INC | UPDI_DATA_16;
if (updi_physical_send(pgm, send_buffer, 2) < 0) {
avrdude_message(MSG_DEBUG, "%s: LD_PTR_INC send operation failed\n", progname);
return -1;
}
return updi_physical_recv(pgm, buffer, words << 2);
}
int updi_link_st_ptr_inc(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size)
{
/*
def st_ptr_inc(self, data):
"""
Store data to the pointer location with pointer post-increment
:param data: data to store
"""
self.logger.debug("ST8 to *ptr++")
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_ST | constants.UPDI_PTR_INC | constants.UPDI_DATA_8,
data[0]])
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("ACK error with st_ptr_inc")
num = 1
while num < len(data):
self.updi_phy.send([data[num]])
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("Error with st_ptr_inc")
num += 1
*/
unsigned char send_buffer[3];
unsigned char recv_buffer[1];
int response;
int num = 1;
avrdude_message(MSG_DEBUG, "%s: ST8 to *ptr++\n", progname);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_ST | UPDI_PTR_INC | UPDI_DATA_8;
send_buffer[2] = buffer[0];
if (updi_physical_send(pgm, send_buffer, 3) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST_PTR_INC send operation failed\n", progname);
return -1;
}
response = updi_physical_recv(pgm, recv_buffer, 1);
if (response != 1 || recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_DEBUG, "%s: ACK was expected but not received\n", progname);
return -1;
}
while (num < size) {
send_buffer[0]=buffer[num];
if (updi_physical_send(pgm, send_buffer, 1) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST_PTR_INC data send operation failed\n", progname);
return -1;
}
response = updi_physical_recv(pgm, recv_buffer, 1);
if (response != 1 || recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_DEBUG, "%s: Data ACK was expected but not received\n", progname);
return -1;
}
num++;
}
return 0;
}
int updi_link_st_ptr_inc16(PROGRAMMER * pgm, unsigned char * buffer, uint16_t words)
{
/*
def st_ptr_inc16(self, data):
"""
Store a 16-bit word value to the pointer location with pointer post-increment
:param data: data to store
"""
self.logger.debug("ST16 to *ptr++")
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_ST | constants.UPDI_PTR_INC |
constants.UPDI_DATA_16, data[0], data[1]])
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("ACK error with st_ptr_inc16")
num = 2
while num < len(data):
self.updi_phy.send([data[num], data[num + 1]])
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("Error with st_ptr_inc16")
num += 2
*/
unsigned char send_buffer[4];
unsigned char recv_buffer[1];
int response;
int num = 2;
avrdude_message(MSG_DEBUG, "%s: ST16 to *ptr++\n", progname);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_ST | UPDI_PTR_INC | UPDI_DATA_16;
send_buffer[2] = buffer[0];
send_buffer[3] = buffer[1];
if (updi_physical_send(pgm, send_buffer, 4) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST_PTR_INC16 send operation failed\n", progname);
return -1;
}
response = updi_physical_recv(pgm, recv_buffer, 1);
if (response != 1 || recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_DEBUG, "%s: ACK was expected but not received\n", progname);
return -1;
}
while (num < words) {
send_buffer[0]=buffer[num];
send_buffer[1]=buffer[num+1];
if (updi_physical_send(pgm, send_buffer, 2) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST_PTR_INC data send operation failed\n", progname);
return -1;
}
response = updi_physical_recv(pgm, recv_buffer, 1);
if (response != 1 || recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_DEBUG, "%s: Data ACK was expected but not received\n", progname);
return -1;
}
num+=2;
}
return 0;
}
int updi_link_st_ptr_inc16_RSD(PROGRAMMER * pgm, unsigned char * buffer, uint16_t words, int blocksize) {
/*
def st_ptr_inc16_RSD(self, data, blocksize):
"""
Store a 16-bit word value to the pointer location with pointer post-increment
:param data: data to store
:blocksize: max number of bytes being sent -1 for all.
Warning: This does not strictly honor blocksize for values < 6
We always glob together the STCS(RSD) and REP commands.
But this should pose no problems for compatibility, because your serial adapter can't deal with 6b chunks,
none of pymcuprog would work!
"""
self.logger.debug("ST16 to *ptr++ with RSD, data length: 0x%03X in blocks of: %d", len(data), blocksize)
#for performance we glob everything together into one USB transfer....
repnumber= ((len(data) >> 1) -1)
data = [*data, *[constants.UPDI_PHY_SYNC, constants.UPDI_STCS | constants.UPDI_CS_CTRLA, 0x06]]
if blocksize == -1 :
# Send whole thing at once stcs + repeat + st + (data + stcs)
blocksize = 3 + 3 + 2 + len(data)
num = 0
firstpacket = []
if blocksize < 10 :
# very small block size - we send pair of 2-byte commands first.
firstpacket = [*[constants.UPDI_PHY_SYNC, constants.UPDI_STCS | constants.UPDI_CS_CTRLA, 0x0E],
*[constants.UPDI_PHY_SYNC, constants.UPDI_REPEAT | constants.UPDI_REPEAT_BYTE, (repnumber & 0xFF)]]
data = [*[constants.UPDI_PHY_SYNC, constants.UPDI_ST | constants.UPDI_PTR_INC |constants.UPDI_DATA_16], *data]
num = 0
else:
firstpacket = [*[constants.UPDI_PHY_SYNC, constants.UPDI_STCS | constants.UPDI_CS_CTRLA , 0x0E],
*[constants.UPDI_PHY_SYNC, constants.UPDI_REPEAT | constants.UPDI_REPEAT_BYTE, (repnumber & 0xFF)],
*[constants.UPDI_PHY_SYNC, constants.UPDI_ST | constants.UPDI_PTR_INC | constants.UPDI_DATA_16],
*data[:blocksize - 8]]
num = blocksize - 8
self.updi_phy.send( firstpacket )
# if finite block size, this is used.
while num < len(data):
data_slice = data[num:num+blocksize]
self.updi_phy.send(data_slice)
num += len(data_slice)
*/
avrdude_message(MSG_DEBUG, "%s: ST16 to *ptr++ with RSD, data length: 0x%03X in blocks of: %d\n", progname, words * 2, blocksize);
unsigned int temp_buffer_size = 3 + 3 + 2 + (words * 2) + 3;
unsigned int num=0;
unsigned char* temp_buffer = malloc(temp_buffer_size);
if (temp_buffer == 0) {
avrdude_message(MSG_DEBUG, "%s: Allocating temporary buffer failed\n", progname);
return -1;
}
if (blocksize == -1) {
blocksize = temp_buffer_size;
}
temp_buffer[0] = UPDI_PHY_SYNC;
temp_buffer[1] = UPDI_STCS | UPDI_CS_CTRLA;
temp_buffer[2] = 0x0E;
temp_buffer[3] = UPDI_PHY_SYNC;
temp_buffer[4] = UPDI_REPEAT | UPDI_REPEAT_BYTE;
temp_buffer[5] = (words - 1) & 0xFF;
temp_buffer[6] = UPDI_PHY_SYNC;
temp_buffer[7] = UPDI_ST | UPDI_PTR_INC | UPDI_DATA_16;
memcpy(temp_buffer + 8, buffer, words * 2);
temp_buffer[temp_buffer_size-3] = UPDI_PHY_SYNC;
temp_buffer[temp_buffer_size-2] = UPDI_STCS | UPDI_CS_CTRLA;
temp_buffer[temp_buffer_size-1] = 0x06;
if (blocksize < 10) {
if (updi_physical_send(pgm, temp_buffer, 6) < 0) {
avrdude_message(MSG_DEBUG, "%s: Failed to send first package\n", progname);
free(temp_buffer);
return -1;
}
num = 6;
}
while (num < temp_buffer_size) {
int next_package_size;
if (num + blocksize > temp_buffer_size) {
next_package_size = temp_buffer_size - num;
} else {
next_package_size = blocksize;
}
if (updi_physical_send(pgm, temp_buffer + num, next_package_size) < 0) {
avrdude_message(MSG_DEBUG, "%s: Failed to send package\n", progname);
free(temp_buffer);
return -1;
}
num+=next_package_size;
}
free(temp_buffer);
return 0;
}
int updi_link_repeat(PROGRAMMER * pgm, uint16_t repeats)
{
/*
def repeat(self, repeats):
"""
Store a value to the repeat counter
:param repeats: number of repeats requested
"""
self.logger.debug("Repeat %d", repeats)
if (repeats - 1) > constants.UPDI_MAX_REPEAT_SIZE:
self.logger.error("Invalid repeat count of %d", repeats)
raise Exception("Invalid repeat count!")
repeats -= 1
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_REPEAT | constants.UPDI_REPEAT_BYTE,
repeats & 0xFF])
*/
unsigned char buffer[3];
avrdude_message(MSG_DEBUG, "%s: Repeat %d\n", progname, repeats);
if ((repeats - 1) > UPDI_MAX_REPEAT_SIZE) {
avrdude_message(MSG_DEBUG, "%s: Invalid repeat count of %d\n", progname, repeats);
return -1;
}
repeats-=1;
buffer[0] = UPDI_PHY_SYNC;
buffer[1] = UPDI_REPEAT | UPDI_REPEAT_BYTE;
buffer[2] = repeats & 0xFF;
return updi_physical_send(pgm, buffer, 3);
}
int updi_link_read_sib(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size)
{
/*
def read_sib(self):
"""
Read the SIB
"""
return self.updi_phy.sib()
*/
return updi_physical_sib(pgm, buffer, size);
}
int updi_link_key(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size_type, uint16_t size)
{
/*
def key(self, size, key):
"""
Write a key
:param size: size of key (0=64B, 1=128B, 2=256B)
:param key: key value
"""
self.logger.debug("Writing key")
if len(key) != 8 << size:
raise PymcuprogError("Invalid KEY length!")
self.updi_phy.send([constants.UPDI_PHY_SYNC, constants.UPDI_KEY | constants.UPDI_KEY_KEY | size])
self.updi_phy.send(list(reversed(list(key))))
*/
unsigned char send_buffer[2];
unsigned char reversed_key[256];
int index;
avrdude_message(MSG_DEBUG, "%s: UPDI writing key\n", progname);
if (size != (8 << size_type)) {
avrdude_message(MSG_DEBUG, "%s: Invalid key length\n", progname);
return -1;
}
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_KEY | UPDI_KEY_KEY | size_type;
if (updi_physical_send(pgm, send_buffer, 2) < 0) {
avrdude_message(MSG_DEBUG, "%s: UPDI key send message failed\n", progname);
return -1;
}
/* reverse key contents */
for (index=0; index<size; index++) {
reversed_key[index] = buffer[size-index-1];
}
return updi_physical_send(pgm, reversed_key, size);
}
int updi_link_ld(PROGRAMMER * pgm, uint32_t address, uint8_t * value)
{
/*
def ld(self, address):
"""
Load a single byte direct from a 24-bit address
:param address: address to load from
:return: value read
"""
self.logger.info("LD from 0x{0:06X}".format(address))
self.updi_phy.send(
[constants.UPDI_PHY_SYNC, constants.UPDI_LDS | constants.UPDI_ADDRESS_24 | constants.UPDI_DATA_8,
address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF])
return self.updi_phy.receive(1)[0]
*/
unsigned char send_buffer[5];
unsigned char recv_buffer[1];
avrdude_message(MSG_DEBUG, "%s: LD from 0x%06X\n", progname, address);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_LDS | UPDI_DATA_8 | (updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? UPDI_ADDRESS_24 : UPDI_ADDRESS_16);
send_buffer[2] = address & 0xFF;
send_buffer[3] = (address >> 8) & 0xFF;
send_buffer[4] = (address >> 16) & 0xFF;
if (updi_physical_send(pgm, send_buffer, updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? 5 : 4) < 0) {
avrdude_message(MSG_DEBUG, "%s: LD operation send failed\n", progname);
return -1;
}
if (updi_physical_recv(pgm, recv_buffer, 1) < 0) {
avrdude_message(MSG_DEBUG, "%s: LD operation recv failed\n", progname);
return -1;
}
* value = recv_buffer[0];
return 0;
}
int updi_link_ld16(PROGRAMMER * pgm, uint32_t address, uint16_t * value)
{
/*
def ld16(self, address):
"""
Load a 16-bit word directly from a 24-bit address
:param address: address to load from
:return: values read
"""
self.logger.info("LD from 0x{0:06X}".format(address))
self.updi_phy.send(
[constants.UPDI_PHY_SYNC, constants.UPDI_LDS | constants.UPDI_ADDRESS_24 | constants.UPDI_DATA_16,
address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF])
return self.updi_phy.receive(2)
*/
unsigned char send_buffer[5];
unsigned char recv_buffer[2];
avrdude_message(MSG_DEBUG, "%s: LD16 from 0x%06X\n", progname, address);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_LDS | UPDI_DATA_16 | (updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? UPDI_ADDRESS_24 : UPDI_ADDRESS_16);
send_buffer[2] = address & 0xFF;
send_buffer[3] = (address >> 8) & 0xFF;
send_buffer[4] = (address >> 16) & 0xFF;
if (updi_physical_send(pgm, send_buffer, updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? 5 : 4) < 0) {
avrdude_message(MSG_DEBUG, "%s: LD16 operation send failed\n", progname);
return -1;
}
if (updi_physical_recv(pgm, recv_buffer, 2) < 0) {
avrdude_message(MSG_DEBUG, "%s: LD16 operation recv failed\n", progname);
return -1;
}
* value = (recv_buffer[0] << 8 | recv_buffer[1]);
return 0;
}
static int updi_link_st_data_phase(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size)
{
/*
def _st_data_phase(self, values):
"""
Performs data phase of transaction:
* receive ACK
* send data
:param values: bytearray of value(s) to send
"""
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("Error with st")
self.updi_phy.send(values)
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("Error with st")
*/
unsigned char recv_buffer[1];
if (updi_physical_recv(pgm, recv_buffer, 1) < 0) {
avrdude_message(MSG_DEBUG, "%s: UPDI data phase recv failed on first ACK\n", progname);
return -1;
}
if (recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_DEBUG, "%s: UPDI data phase expected first ACK\n", progname);
return -1;
}
if (updi_physical_send(pgm, buffer, size) < 0) {
avrdude_message(MSG_DEBUG, "%s: UPDI data phase send failed\n", progname);
return -1;
}
if (updi_physical_recv(pgm, recv_buffer, 1) < 0) {
avrdude_message(MSG_DEBUG, "%s: UPDI data phase recv failed on second ACK\n", progname);
return -1;
}
if (recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_DEBUG, "%s: UPDI data phase expected second ACK\n", progname);
return -1;
}
return 0;
}
int updi_link_st(PROGRAMMER * pgm, uint32_t address, uint8_t value)
{
/*
def st(self, address, value):
"""
Store a single byte value directly to a 24-bit address
:param address: address to write to
:param value: value to write
"""
self.logger.info("ST to 0x{0:06X}".format(address))
self.updi_phy.send(
[constants.UPDI_PHY_SYNC, constants.UPDI_STS | constants.UPDI_ADDRESS_24 | constants.UPDI_DATA_8,
address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF])
return self._st_data_phase([value & 0xFF])
*/
unsigned char send_buffer[5];
avrdude_message(MSG_DEBUG, "%s: ST to 0x%06X\n", progname, address);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_STS | UPDI_DATA_8 | (updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? UPDI_ADDRESS_24 : UPDI_ADDRESS_16);
send_buffer[2] = address & 0xFF;
send_buffer[3] = (address >> 8) & 0xFF;
send_buffer[4] = (address >> 16) & 0xFF;
if (updi_physical_send(pgm, send_buffer, updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? 5 : 4) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST operation send failed\n", progname);
return -1;
}
send_buffer[0] = value;
return updi_link_st_data_phase(pgm, send_buffer, 1);
}
int updi_link_st16(PROGRAMMER * pgm, uint32_t address, uint16_t value)
{
/*
def st16(self, address, value):
"""
Store a 16-bit word value directly to a 24-bit address
:param address: address to write to
:param value: value to write
"""
self.logger.info("ST to 0x{0:06X}".format(address))
self.updi_phy.send(
[constants.UPDI_PHY_SYNC, constants.UPDI_STS | constants.UPDI_ADDRESS_24 | constants.UPDI_DATA_16,
address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF])
return self._st_data_phase([value & 0xFF, (value >> 8) & 0xFF])
*/
unsigned char send_buffer[5];
avrdude_message(MSG_DEBUG, "%s: ST16 to 0x%06X\n", progname, address);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_STS | UPDI_DATA_16 | (updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? UPDI_ADDRESS_24 : UPDI_ADDRESS_16);
send_buffer[2] = address & 0xFF;
send_buffer[3] = (address >> 8) & 0xFF;
send_buffer[4] = (address >> 16) & 0xFF;
if (updi_physical_send(pgm, send_buffer, updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? 5 : 4) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST16 operation send failed\n", progname);
return -1;
}
send_buffer[0] = value & 0xFF;
send_buffer[1] = (value >> 8) & 0xFF;
return updi_link_st_data_phase(pgm, send_buffer, 2);
}
int updi_link_st_ptr(PROGRAMMER * pgm, uint32_t address)
{
/*
def st_ptr(self, address):
"""
Set the pointer location
:param address: address to write
"""
self.logger.info("ST to ptr")
self.updi_phy.send(
[constants.UPDI_PHY_SYNC, constants.UPDI_ST | constants.UPDI_PTR_ADDRESS | constants.UPDI_DATA_24,
address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF])
response = self.updi_phy.receive(1)
if len(response) != 1 or response[0] != constants.UPDI_PHY_ACK:
raise PymcuprogError("Error with st_ptr")
*/
unsigned char send_buffer[5];
unsigned char recv_buffer[1];
avrdude_message(MSG_DEBUG, "%s: ST_PTR to 0x%06X\n", progname, address);
send_buffer[0] = UPDI_PHY_SYNC;
send_buffer[1] = UPDI_STS | UPDI_ST | UPDI_PTR_ADDRESS | (updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? UPDI_DATA_24 : UPDI_DATA_16);
send_buffer[2] = address & 0xFF;
send_buffer[3] = (address >> 8) & 0xFF;
send_buffer[4] = (address >> 16) & 0xFF;
if (updi_physical_send(pgm, send_buffer, updi_get_datalink_mode(pgm) == UPDI_LINK_MODE_24BIT ? 5 : 4) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST_PTR operation send failed\n", progname);
return -1;
}
if (updi_physical_recv(pgm, recv_buffer, 1) < 0) {
avrdude_message(MSG_DEBUG, "%s: UPDI ST_PTR recv failed on ACK\n", progname);
return -1;
}
if (recv_buffer[0] != UPDI_PHY_ACK) {
avrdude_message(MSG_DEBUG, "%s: UPDI ST_PTR expected ACK\n", progname);
return -1;
}
return 0;
}

59
updi_link.h Normal file
View File

@ -0,0 +1,59 @@
/*
* 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
*/
#ifndef updi_link_h
#define updi_link_h
#include "libavrdude.h"
#ifdef __cplusplus
extern "C" {
#endif
int updi_link_open(PROGRAMMER * pgm);
void updi_link_close(PROGRAMMER * pgm);
int updi_link_init(PROGRAMMER * pgm);
int updi_link_ldcs(PROGRAMMER * pgm, uint8_t address, uint8_t * value);
int updi_link_stcs(PROGRAMMER * pgm, uint8_t address, uint8_t value);
int updi_link_ld_ptr_inc(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size);
int updi_link_ld_ptr_inc16(PROGRAMMER * pgm, unsigned char * buffer, uint16_t words);
int updi_link_st_ptr_inc(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size);
int updi_link_st_ptr_inc16(PROGRAMMER * pgm, unsigned char * buffer, uint16_t words);
int updi_link_st_ptr_inc16_RSD(PROGRAMMER * pgm, unsigned char * buffer, uint16_t words, int blocksize);
int updi_link_repeat(PROGRAMMER * pgm, uint16_t repeats);
int updi_link_read_sib(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size);
int updi_link_key(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size_type, uint16_t size);
int updi_link_ld(PROGRAMMER * pgm, uint32_t address, uint8_t * value);
int updi_link_ld16(PROGRAMMER * pgm, uint32_t address, uint16_t * value);
int updi_link_st(PROGRAMMER * pgm, uint32_t address, uint8_t value);
int updi_link_st16(PROGRAMMER * pgm, uint32_t address, uint16_t value);
int updi_link_st_ptr(PROGRAMMER * pgm, uint32_t address);
#ifdef __cplusplus
}
#endif
#endif /* updi_link_h */

1275
updi_nvm.c Normal file

File diff suppressed because it is too large Load Diff

51
updi_nvm.h Normal file
View File

@ -0,0 +1,51 @@
/*
* 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
*/
#ifndef updi_nvm_h
#define updi_nvm_h
#include "libavrdude.h"
#ifdef __cplusplus
extern "C" {
#endif
int updi_nvm_chip_erase(PROGRAMMER * pgm, AVRPART * p);
int updi_nvm_erase_flash_page(PROGRAMMER * pgm, AVRPART *p, uint32_t address);
int updi_nvm_erase_eeprom(PROGRAMMER * pgm, AVRPART *p);
int updi_nvm_erase_user_row(PROGRAMMER * pgm, AVRPART *p, uint32_t address, uint16_t size);
int updi_nvm_write_flash(PROGRAMMER * pgm, AVRPART *p, uint32_t address, unsigned char * buffer, uint16_t size);
int updi_nvm_write_user_row(PROGRAMMER * pgm, AVRPART *p, uint32_t address, unsigned char * buffer, uint16_t size);
int updi_nvm_write_eeprom(PROGRAMMER * pgm, AVRPART *p, uint32_t address, unsigned char * buffer, uint16_t size);
int updi_nvm_write_fuse(PROGRAMMER * pgm, AVRPART *p, uint32_t address, uint8_t value);
int updi_nvm_wait_ready(PROGRAMMER * pgm, AVRPART *p);
int updi_nvm_command(PROGRAMMER * pgm, AVRPART *p, uint8_t command);
#ifdef __cplusplus
}
#endif
#endif /* updi_nvm_h */

316
updi_readwrite.c Normal file
View File

@ -0,0 +1,316 @@
/*
* 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(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(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(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(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(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(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(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("Cant 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)
*/
avrdude_message(MSG_DEBUG, "%s: Reading %d bytes from 0x%06X\n", progname, size, address);
if (size > UPDI_MAX_REPEAT_SIZE) {
avrdude_message(MSG_DEBUG, "%s: Can't read that many bytes in one go\n", progname);
return -1;
}
if (updi_link_st_ptr(pgm, address) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST_PTR operation failed\n", progname);
return -1;
}
if (size > 1) {
if (updi_link_repeat(pgm, size) < 0) {
avrdude_message(MSG_DEBUG, "%s: Repeat operation failed\n", progname);
return -1;
}
}
return updi_link_ld_ptr_inc(pgm, buffer, size);
}
int updi_write_data(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) {
avrdude_message(MSG_DEBUG, "%s: ST operation failed\n", progname);
return -1;
}
return updi_link_st(pgm, address+1, buffer[1]);
}
if (size > UPDI_MAX_REPEAT_SIZE) {
avrdude_message(MSG_DEBUG, "%s: Invalid length\n", progname);
return -1;
}
if (updi_link_st_ptr(pgm, address) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST_PTR operation failed\n", progname);
return -1;
}
if (updi_link_repeat(pgm, size) < 0) {
avrdude_message(MSG_DEBUG, "%s: Repeat operation failed\n", progname);
return -1;
}
return updi_link_st_ptr_inc(pgm, buffer, size);
}
int updi_read_data_words(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("Cant 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)
*/
avrdude_message(MSG_DEBUG, "%s: Reading %d words from 0x%06X", progname, size, address);
if (size > (UPDI_MAX_REPEAT_SIZE >> 1)) {
avrdude_message(MSG_DEBUG, "%s: Can't read that many words in one go\n", progname);
return -1;
}
if (updi_link_st_ptr(pgm, address) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST_PTR operation failed\n", progname);
return -1;
}
if (size > 1) {
if (updi_link_repeat(pgm, size) < 0) {
avrdude_message(MSG_DEBUG, "%s: Repeat operation failed\n", progname);
return -1;
}
}
return updi_link_ld_ptr_inc16(pgm, buffer, size);
}
int updi_write_data_words(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) {
avrdude_message(MSG_DEBUG, "%s: Invalid length\n", progname);
return -1;
}
if (updi_link_st_ptr(pgm, address) < 0) {
avrdude_message(MSG_DEBUG, "%s: ST_PTR operation failed\n", progname);
return -1;
}
return updi_link_st_ptr_inc16_RSD(pgm, buffer, size >> 1, -1);
}

51
updi_readwrite.h Normal file
View File

@ -0,0 +1,51 @@
/*
* 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
*/
#ifndef updi_readwrite_h
#define updi_readwrite_h
#include "libavrdude.h"
#ifdef __cplusplus
extern "C" {
#endif
int updi_read_cs(PROGRAMMER * pgm, uint8_t address, uint8_t * value);
int updi_write_cs(PROGRAMMER * pgm, uint8_t address, uint8_t value);
int updi_write_key(PROGRAMMER * pgm, unsigned char * buffer, uint8_t size_type, uint16_t size);
int updi_read_sib(PROGRAMMER * pgm, unsigned char * buffer, uint16_t size);
int updi_read_byte(PROGRAMMER * pgm, uint32_t address, uint8_t * value);
int updi_write_byte(PROGRAMMER * pgm, uint32_t address, uint8_t value);
int updi_read_data(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size);
int updi_write_data(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size);
int updi_read_data_words(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size);
int updi_write_data_words(PROGRAMMER * pgm, uint32_t address, uint8_t * buffer, uint16_t size);
#ifdef __cplusplus
}
#endif
#endif /* updi_readwrite_h */

55
updi_state.c Normal file
View File

@ -0,0 +1,55 @@
/*
* 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 "libavrdude.h"
#include "updi_state.h"
updi_sib_info* updi_get_sib_info(PROGRAMMER * pgm)
{
return &((updi_state *)(pgm->cookie))->sib_info;
}
updi_datalink_mode updi_get_datalink_mode(PROGRAMMER * pgm)
{
return ((updi_state *)(pgm->cookie))->datalink_mode;
}
void updi_set_datalink_mode(PROGRAMMER * pgm, updi_datalink_mode mode)
{
((updi_state *)(pgm->cookie))->datalink_mode = mode;
}
updi_nvm_mode updi_get_nvm_mode(PROGRAMMER * pgm)
{
return ((updi_state *)(pgm->cookie))->nvm_mode;
}
void updi_set_nvm_mode(PROGRAMMER * pgm, updi_nvm_mode mode)
{
((updi_state *)(pgm->cookie))->nvm_mode = mode;
}

85
updi_state.h Normal file
View File

@ -0,0 +1,85 @@
/*
* 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
*/
#ifndef updi_state_h
#define updi_state_h
#include "libavrdude.h"
typedef enum
{
UPDI_LINK_MODE_16BIT,
UPDI_LINK_MODE_24BIT
} updi_datalink_mode;
typedef enum
{
UPDI_NVM_MODE_V0,
UPDI_NVM_MODE_V2,
UPDI_NVM_MODE_V3
} updi_nvm_mode;
#define SIB_INFO_STRING_LENGTH 32
#define SIB_INFO_FAMILY_LENGTH 8
#define SIB_INFO_NVM_LENGTH 3
#define SIB_INFO_DEBUG_LENGTH 3
#define SIB_INFO_PDI_LENGTH 4
#define SIB_INFO_EXTRA_LENGTH 20
typedef struct
{
unsigned char sib_string[SIB_INFO_STRING_LENGTH+1];
char family_string[SIB_INFO_FAMILY_LENGTH+1];
char nvm_string[SIB_INFO_NVM_LENGTH+1];
char debug_string[SIB_INFO_DEBUG_LENGTH+1];
char pdi_string[SIB_INFO_PDI_LENGTH+1];
char extra_string[SIB_INFO_EXTRA_LENGTH+1];
char nvm_version;
char debug_version;
} updi_sib_info;
typedef struct
{
updi_sib_info sib_info;
updi_datalink_mode datalink_mode;
updi_nvm_mode nvm_mode;
} updi_state;
#ifdef __cplusplus
extern "C" {
#endif
updi_sib_info* updi_get_sib_info(PROGRAMMER * pgm);
updi_datalink_mode updi_get_datalink_mode(PROGRAMMER * pgm);
void updi_set_datalink_mode(PROGRAMMER * pgm, updi_datalink_mode mode);
updi_nvm_mode updi_get_nvm_mode(PROGRAMMER * pgm);
void updi_set_nvm_mode(PROGRAMMER * pgm, updi_nvm_mode mode);
#ifdef __cplusplus
}
#endif
#endif /* updi_state_h */