summaryrefslogtreecommitdiff
path: root/digital/ucoolib
diff options
context:
space:
mode:
Diffstat (limited to 'digital/ucoolib')
-rw-r--r--digital/ucoolib/ucoolib/dev/avrisp/Config6
-rw-r--r--digital/ucoolib/ucoolib/dev/avrisp/Module1
-rw-r--r--digital/ucoolib/ucoolib/dev/avrisp/avrisp.cc452
-rw-r--r--digital/ucoolib/ucoolib/dev/avrisp/avrisp.hh247
-rw-r--r--digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.cc173
-rw-r--r--digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.hh95
-rw-r--r--digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.cc269
-rw-r--r--digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.hh50
-rw-r--r--digital/ucoolib/ucoolib/dev/avrisp/test/Makefile9
-rw-r--r--digital/ucoolib/ucoolib/dev/avrisp/test/test_avrisp.cc90
10 files changed, 1392 insertions, 0 deletions
diff --git a/digital/ucoolib/ucoolib/dev/avrisp/Config b/digital/ucoolib/ucoolib/dev/avrisp/Config
new file mode 100644
index 00000000..cf3eb48a
--- /dev/null
+++ b/digital/ucoolib/ucoolib/dev/avrisp/Config
@@ -0,0 +1,6 @@
+[dev/avrisp]
+frame_buffer_size = 281
+proto_signature = "APBisp_2"
+proto_build_number = 0x0100
+proto_hw_version = 0x02
+proto_sw_version = 0x0204
diff --git a/digital/ucoolib/ucoolib/dev/avrisp/Module b/digital/ucoolib/ucoolib/dev/avrisp/Module
new file mode 100644
index 00000000..d66f06f3
--- /dev/null
+++ b/digital/ucoolib/ucoolib/dev/avrisp/Module
@@ -0,0 +1 @@
+dev_avrisp_SOURCES := avrisp.cc avrisp_proto.cc avrisp_frame.cc
diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp.cc b/digital/ucoolib/ucoolib/dev/avrisp/avrisp.cc
new file mode 100644
index 00000000..10550687
--- /dev/null
+++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp.cc
@@ -0,0 +1,452 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// 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.
+//
+// }}}
+#include "avrisp.hh"
+
+#include "ucoolib/utils/delay.hh"
+
+namespace ucoo {
+
+/// Command used to load extended address.
+static const uint8_t avrisp_cmd_load_extended_address = 0x4d;
+/// Bit to address high byte.
+static const uint8_t avrisp_cmd_high_byte = 1 << 3;
+/// Extra EEPROM programming delay.
+static const int avrisp_eeprom_delay_ms = 2;
+/// Miscellaneous read delay.
+static const int avrisp_misc_read_delay_ms = 5;
+
+AvrIsp::AvrIsp (AvrIspIntf &intf)
+ : intf_ (intf)
+{
+}
+
+AvrIspResult
+AvrIsp::enter_progmode (uint8_t sck_duration_us, uint8_t timeout_ms,
+ uint8_t stab_delay_ms, uint8_t cmd_exe_delay_ms,
+ uint8_t synch_loops, uint8_t byte_delay_ms,
+ uint8_t poll_value, uint8_t poll_index,
+ const uint8_t cmd[4])
+{
+ int i;
+ uint8_t tmp1, tmp2;
+ // Reset context.
+ ext_addr_ = 0;
+ last_ext_addr_ = 0xff;
+ larger_than_64k_ = 0;
+ bytes_left_ = 0;
+ // Enable SPI.
+ intf_.enable (sck_duration_us);
+ delay_ms (stab_delay_ms);
+ // Limit the number of loops.
+ if (synch_loops > 48)
+ synch_loops = 48;
+ // Minimum byte delay.
+ if (byte_delay_ms < 1)
+ byte_delay_ms = 1;
+ // Synchronisation loops.
+ for (i = 0; i < synch_loops; i++)
+ {
+ delay_ms (cmd_exe_delay_ms);
+ intf_.send_and_recv (cmd[0]);
+ delay_ms (byte_delay_ms);
+ intf_.send_and_recv (cmd[1]);
+ delay_ms (byte_delay_ms);
+ tmp1 = intf_.send_and_recv (cmd[2]);
+ delay_ms (byte_delay_ms);
+ tmp2 = intf_.send_and_recv (cmd[3]);
+ // Test success.
+ if (poll_index == 0
+ || (poll_index == 3 && tmp1 == poll_value)
+ || (poll_index != 3 && tmp2 == poll_value))
+ return AVRISP_OK;
+ // Else, new try.
+ intf_.sck_pulse ();
+ delay_ms (20);
+ }
+ return AVRISP_FAILED;
+}
+
+void
+AvrIsp::leave_progmode (uint8_t pre_delay_ms, uint8_t post_delay_ms)
+{
+ delay_ms (pre_delay_ms);
+ intf_.disable ();
+ delay_ms (post_delay_ms);
+}
+
+void
+AvrIsp::load_address (uint32_t addr)
+{
+ addr_ = addr & 0xffff;
+ ext_addr_ = (addr >> 16) & 0xff;
+ last_ext_addr_ = 0xff;
+ larger_than_64k_ = (addr & 0x80000000) ? 1 : 0;
+}
+
+AvrIspResult
+AvrIsp::chip_erase (uint8_t erase_delay_ms, uint8_t poll_method,
+ const uint8_t cmd[4])
+{
+ int tries;
+ intf_.send_and_recv (cmd[0]);
+ intf_.send_and_recv (cmd[1]);
+ intf_.send_and_recv (cmd[2]);
+ intf_.send_and_recv (cmd[3]);
+ if (poll_method == 0)
+ {
+ // Use delay.
+ delay_ms (erase_delay_ms);
+ }
+ else
+ {
+ // Use RDY/BSY command.
+ tries = 150;
+ while ((spi_tx_32 (0xf0000000) & 1) && tries)
+ tries--;
+ if (tries == 0)
+ return AVRISP_TIMEOUT;
+ }
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::program_begin (uint16_t num_bytes, uint8_t mode, uint8_t delay_ms,
+ uint8_t cmd_write_mem, uint8_t cmd_write_page,
+ uint8_t cmd_read_mem, const uint8_t poll[2],
+ uint8_t flash)
+{
+ // Set delay bounds.
+ if (delay_ms < 4)
+ delay_ms = 4;
+ if (delay_ms > 32)
+ delay_ms = 32;
+ // Check data size.
+ if (flash && (num_bytes & 1))
+ return AVRISP_FAILED;
+ // Store parameters.
+ start_addr_ = addr_;
+ bytes_left_ = num_bytes;
+ mode_ = mode;
+ delay_ms_ = delay_ms;
+ cmd_write_mem_ = cmd_write_mem;
+ cmd_write_page_ = cmd_write_page;
+ cmd_read_mem_ = cmd_read_mem;
+ poll_[0] = poll[0];
+ poll_[1] = poll[1];
+ pollable_ = 0;
+ flash_ = flash;
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::program_flash_begin (uint16_t num_bytes, uint8_t mode,
+ uint8_t delay_ms, uint8_t cmd_write_mem,
+ uint8_t cmd_write_page, uint8_t cmd_read_mem,
+ const uint8_t poll[2])
+{
+ return program_begin (num_bytes, mode, delay_ms, cmd_write_mem,
+ cmd_write_page, cmd_read_mem, poll, 1);
+}
+
+AvrIspResult
+AvrIsp::program_eeprom_begin (uint16_t num_bytes, uint8_t mode,
+ uint8_t delay_ms, uint8_t cmd_write_mem,
+ uint8_t cmd_write_page, uint8_t cmd_read_mem,
+ const uint8_t poll[2])
+{
+ return program_begin (num_bytes, mode, delay_ms, cmd_write_mem,
+ cmd_write_page, cmd_read_mem, poll, 0);
+}
+
+AvrIspResult
+AvrIsp::program_continue (const uint8_t *data, uint16_t size)
+{
+ uint16_t i;
+ uint8_t read;
+ int tries;
+ // Check size.
+ if (size > bytes_left_ || (flash_ && (size & 1)))
+ return AVRISP_FAILED;
+ bytes_left_ -= size;
+ // Loop on each input bytes.
+ for (i = 0; i < size; i++)
+ {
+ // Check for Load Extended Address.
+ if (larger_than_64k_ && last_ext_addr_ != ext_addr_)
+ {
+ intf_.send_and_recv (avrisp_cmd_load_extended_address);
+ intf_.send_and_recv (0x00);
+ intf_.send_and_recv (ext_addr_);
+ intf_.send_and_recv (0x00);
+ last_ext_addr_ = ext_addr_;
+ }
+ // Write memory/load page, using bit 3 as byte selector.
+ if (flash_ && (i & 1))
+ intf_.send_and_recv (cmd_write_mem_ | avrisp_cmd_high_byte);
+ else
+ intf_.send_and_recv (cmd_write_mem_);
+ spi_tx_16 (addr_);
+ intf_.send_and_recv (data[i]);
+ // EEPROM needs more delay.
+ if (!flash_)
+ delay_ms (avrisp_eeprom_delay_ms);
+ // Poll.
+ if (!(mode_ & AVRISP_MODE_PAGE))
+ {
+ // Poll right now.
+ tries = 150;
+ read = poll_[0];
+ if ((mode_ & AVRISP_MODE_WORD_VALUE) && data[i] != read)
+ {
+ // Poll by reading byte.
+ while (read != data[i] && tries)
+ {
+ if (flash_ && (i & 1))
+ intf_.send_and_recv (cmd_read_mem_
+ | avrisp_cmd_high_byte);
+ else
+ intf_.send_and_recv (cmd_read_mem_);
+ spi_tx_16 (addr_);
+ read = intf_.send_and_recv (0x00);
+ tries--;
+ }
+ }
+ else if (mode_ & AVRISP_MODE_WORD_RDY_BSY)
+ {
+ // RDY/BSY polling.
+ while ((spi_tx_32 (0xf0000000) & 1) && tries)
+ tries--;
+ }
+ else
+ // Simple delay.
+ delay_ms (delay_ms_);
+ if (tries == 0)
+ return AVRISP_TIMEOUT;
+ }
+ else
+ {
+ // Check for poll method.
+ if (!pollable_ && data[i] != poll_[0])
+ {
+ pollable_ = 0x02 | (i & 1);
+ poll_addr_ = addr_;
+ }
+ }
+ // Increment address.
+ if (!flash_ || (i & 1))
+ {
+ addr_++;
+ if (addr_ == 0)
+ ext_addr_++;
+ }
+ }
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::program_end ()
+{
+ uint8_t read;
+ int tries;
+ // Check size.
+ if (bytes_left_ != 0)
+ return AVRISP_FAILED;
+ // Write page if requested.
+ if ((mode_ & (AVRISP_MODE_PAGE | AVRISP_MODE_PAGE_WRITE))
+ == (AVRISP_MODE_PAGE | AVRISP_MODE_PAGE_WRITE))
+ {
+ // Write page.
+ intf_.send_and_recv (cmd_write_page_);
+ spi_tx_16 (start_addr_);
+ intf_.send_and_recv (0x00);
+ // EEPROM needs more delay.
+ if (!flash_)
+ delay_ms (avrisp_eeprom_delay_ms);
+ // Poll.
+ tries = 150;
+ read = poll_[0];
+ if ((mode_ & AVRISP_MODE_PAGE_VALUE) && pollable_)
+ {
+ // Poll by reading byte.
+ while (read == poll_[0] && tries)
+ {
+ if (flash_ && (pollable_ & 1))
+ intf_.send_and_recv (cmd_read_mem_ | avrisp_cmd_high_byte);
+ else
+ intf_.send_and_recv (cmd_read_mem_);
+ spi_tx_16 (poll_addr_);
+ read = intf_.send_and_recv (0x00);
+ tries--;
+ }
+ }
+ else if (mode_ & AVRISP_MODE_PAGE_RDY_BSY)
+ {
+ // RDY/BSY polling.
+ while ((spi_tx_32 (0xf0000000) & 1) && tries)
+ tries--;
+ }
+ else
+ // Simple delay.
+ delay_ms (delay_ms_);
+ if (tries == 0)
+ return AVRISP_TIMEOUT;
+ }
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::read_begin (uint16_t num_bytes, uint8_t cmd_read_mem, uint8_t flash)
+{
+ // Check data size.
+ if (flash && (num_bytes & 1))
+ return AVRISP_FAILED;
+ // Store parameters.
+ bytes_left_ = num_bytes;
+ cmd_read_mem_ = cmd_read_mem;
+ flash_ = flash;
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::read_flash_begin (uint16_t num_bytes, uint8_t cmd_read_mem)
+{
+ return read_begin (num_bytes, cmd_read_mem, 1);
+}
+
+AvrIspResult
+AvrIsp::read_eeprom_begin (uint16_t num_bytes, uint8_t cmd_read_mem)
+{
+ return read_begin (num_bytes, cmd_read_mem, 0);
+}
+
+AvrIspResult
+AvrIsp::read_continue (uint8_t *data, uint16_t size)
+{
+ uint16_t i;
+ // Check size.
+ if (size > bytes_left_ || (flash_ && (size & 1)))
+ return AVRISP_FAILED;
+ bytes_left_ -= size;
+ // Loop on each bytes.
+ for (i = 0; i < size; i++)
+ {
+ // Check for Load Extended Address.
+ if (larger_than_64k_ && last_ext_addr_ != ext_addr_)
+ {
+ intf_.send_and_recv (avrisp_cmd_load_extended_address);
+ intf_.send_and_recv (0x00);
+ intf_.send_and_recv (ext_addr_);
+ intf_.send_and_recv (0x00);
+ last_ext_addr_ = ext_addr_;
+ }
+ // Read memory, using bit 3 as byte selector.
+ if (flash_ && (i & 1))
+ intf_.send_and_recv (cmd_read_mem_ | avrisp_cmd_high_byte);
+ else
+ intf_.send_and_recv (cmd_read_mem_);
+ spi_tx_16 (addr_);
+ data[i] = intf_.send_and_recv (0x00);
+ // Increment address.
+ if (!flash_ || (i & 1))
+ {
+ addr_++;
+ if (addr_ == 0)
+ ext_addr_++;
+ }
+ }
+ return AVRISP_OK;
+}
+
+AvrIspResult
+AvrIsp::read_end ()
+{
+ // Check size.
+ if (bytes_left_ != 0)
+ return AVRISP_FAILED;
+ return AVRISP_OK;
+}
+
+void
+AvrIsp::program_misc (const uint8_t cmd[4])
+{
+ uint8_t i;
+ for (i = 0; i < 4; i++)
+ intf_.send_and_recv (cmd[i]);
+}
+
+uint8_t
+AvrIsp::read_misc (uint8_t ret_addr, const uint8_t cmd[4])
+{
+ uint8_t i, read = 0, tmp;
+ for (i = 0; i < 4; i++)
+ {
+ tmp = intf_.send_and_recv (cmd[i]);
+ if (i == ret_addr)
+ read = tmp;
+ delay_ms (avrisp_misc_read_delay_ms);
+ }
+ return read;
+}
+
+void
+AvrIsp::multi (uint8_t num_tx, uint8_t num_rx, uint8_t rx_start,
+ const uint8_t *dout, uint8_t *din)
+{
+ uint8_t in, out;
+ while (num_tx || num_rx)
+ {
+ out = 0;
+ if (num_tx)
+ {
+ out = *dout++;
+ num_tx--;
+ }
+ in = intf_.send_and_recv (out);
+ if (rx_start)
+ rx_start--;
+ else if (num_rx)
+ {
+ *din++ = in;
+ num_rx--;
+ }
+ }
+}
+
+void
+AvrIsp::spi_tx_16 (uint16_t data)
+{
+ intf_.send_and_recv ((data >> 8) & 0xff);
+ intf_.send_and_recv ((data >> 0) & 0xff);
+}
+
+uint8_t
+AvrIsp::spi_tx_32 (uint32_t data)
+{
+ intf_.send_and_recv ((data >> 24) & 0xff);
+ intf_.send_and_recv ((data >> 16) & 0xff);
+ intf_.send_and_recv ((data >> 8) & 0xff);
+ return intf_.send_and_recv ((data >> 0) & 0xff);
+}
+
+} // namespace ucoo
diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp.hh b/digital/ucoolib/ucoolib/dev/avrisp/avrisp.hh
new file mode 100644
index 00000000..5046459b
--- /dev/null
+++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp.hh
@@ -0,0 +1,247 @@
+#ifndef ucoolib_dev_avrisp_avrisp_hh
+#define ucoolib_dev_avrisp_avrisp_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// 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.
+//
+// }}}
+#include "ucoolib/common.hh"
+
+namespace ucoo {
+
+/// Results returned by ISP functions.
+enum AvrIspResult
+{
+ /// Operation success.
+ AVRISP_OK,
+ /// Operation failed.
+ AVRISP_FAILED,
+ /// Operation failed on a timeout.
+ AVRISP_TIMEOUT,
+};
+
+/// ISP Programming mode.
+enum AvrIspMode
+{
+ /// Use page programming.
+ AVRISP_MODE_PAGE = 1,
+ /// Use simple delay for word programming.
+ AVRISP_MODE_WORD_DELAY = 2,
+ /// Use value polling if possible for word programming, fall back to delay
+ /// if not possible.
+ AVRISP_MODE_WORD_VALUE = 4,
+ /// Use RDY/BSY polling for word programming.
+ AVRISP_MODE_WORD_RDY_BSY = 8,
+ /// Use simple delay for page programming.
+ AVRISP_MODE_PAGE_DELAY = 16,
+ /// Use value polling if possible for page programming, fall back to delay
+ /// if not possible.
+ AVRISP_MODE_PAGE_VALUE = 32,
+ /// Use RDY/BSY polling for page programming.
+ AVRISP_MODE_PAGE_RDY_BSY = 64,
+ /// Write page at end of transfer. Used for big pages which must be
+ /// transfered in several packets.
+ AVRISP_MODE_PAGE_WRITE = 128,
+};
+
+/// Interface to hardware connection.
+class AvrIspIntf
+{
+ public:
+ /// Send and receive one byte through SPI interface.
+ virtual uint8_t send_and_recv (uint8_t tx) = 0;
+ /// Enable programming:
+ /// - set RESET and SCK to low,
+ /// - power on, or if not possible, do a positive RESET pulse,
+ /// - enable SPI, mode 0.
+ virtual void enable (uint8_t sck_duration_us) = 0;
+ /// Disable programming:
+ /// - disable SPI,
+ /// - release RESET,
+ /// - power off if desired.
+ virtual void disable () = 0;
+ /// Do a pulse on SCK. This is used to try to resynchronise.
+ virtual void sck_pulse () = 0;
+};
+
+/// AVR serial programming.
+class AvrIsp
+{
+ public:
+ /// Constructor.
+ AvrIsp (AvrIspIntf &intf);
+ /// Enable SPI port and enter programing mode.
+ /// - sck_duration_us: SCK period.
+ /// - timeout_ms: command time-out, unused.
+ /// - stab_delay_ms: stabilisation delay once device is reseted and SPI
+ /// initialised.
+ /// - cmd_exe_delay_ms: delay for the command execution.
+ /// - synch_loops: number of synchronisation loops (there is no start of
+ /// frame in SPI).
+ /// - byte_delay_ms: delay between each byte.
+ /// - poll_value: value to read to consider the sequence is correct.
+ /// - poll_index: transfer index at which the poll_value must be read.
+ /// - cmd: command bytes to be transfered.
+ /// - returns: AVRISP_OK or AVRISP_FAILED if no synchronisation.
+ AvrIspResult enter_progmode (uint8_t sck_duration_us,
+ uint8_t timeout_ms, uint8_t stab_delay_ms,
+ uint8_t cmd_exe_delay_ms,
+ uint8_t synch_loops, uint8_t byte_delay_ms,
+ uint8_t poll_value, uint8_t poll_index,
+ const uint8_t cmd[4]);
+ /// Leave programming mode and disable SPI port.
+ /// - pre_delay_ms: delay before disabling.
+ /// - post_delay_ms: delay after disabling.
+ void leave_progmode (uint8_t pre_delay_ms, uint8_t post_delay_ms);
+ /// Load programing address.
+ /// - addr: address to load, bit 31 means the device has more than 64k
+ /// words and extended addressing should be used.
+ void load_address (uint32_t addr);
+ /// Chip full erase.
+ /// - erase_delay_ms: delay to ensure the erase is finished.
+ /// - poll_method: use delay (0) or RDY/BSY polling (1).
+ /// - cmd: chip erase command.
+ /// - returns: AVRISP_OK or AVRISP_TIMEOUT if using polling and it
+ /// timed-out.
+ AvrIspResult chip_erase (uint8_t erase_delay_ms, uint8_t poll_method,
+ const uint8_t cmd[4]);
+ /// Start a program command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult program_begin (uint16_t num_bytes, uint8_t mode,
+ uint8_t delay_ms, uint8_t cmd_write_mem,
+ uint8_t cmd_write_page, uint8_t cmd_read_mem,
+ const uint8_t poll[2], uint8_t flash);
+ /// Start a flash memory program command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult program_flash_begin (uint16_t num_bytes, uint8_t mode,
+ uint8_t delay_ms, uint8_t cmd_write_mem,
+ uint8_t cmd_write_page,
+ uint8_t cmd_read_mem,
+ const uint8_t poll[2]);
+ /// Start a EEPROM memory program command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult program_eeprom_begin (uint16_t num_bytes,
+ uint8_t mode,
+ uint8_t delay_ms,
+ uint8_t cmd_write_mem,
+ uint8_t cmd_write_page,
+ uint8_t cmd_read_mem,
+ const uint8_t poll[2]);
+ /// Provide data for memory programming. Data should be given by even
+ /// sized packs or loading of word addressed data will fail.
+ /// - returns: AVRISP_OK, AVRISP_FAILED for bad parameters or
+ /// AVRISP_TIMEOUT if using polling and it timed-out.
+ AvrIspResult program_continue (const uint8_t *data, uint16_t size);
+ /// End program command.
+ /// - returns: AVRISP_OK, AVRISP_FAILED if too early or AVRISP_TIMEOUT if
+ /// using polling and it timed-out.
+ AvrIspResult program_end ();
+ /// Start a read command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult read_begin (uint16_t num_bytes, uint8_t cmd_read_mem,
+ uint8_t flash);
+ /// Start a flash memory read command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult read_flash_begin (uint16_t num_bytes, uint8_t cmd_read_mem);
+ /// Start a EEPROM memory read command.
+ /// - num_bytes: total number of bytes to program.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ /// See class for other parameters meaning.
+ AvrIspResult read_eeprom_begin (uint16_t num_bytes, uint8_t cmd_read_mem);
+ /// Get data from read memory. Data should be read by even sized packs or
+ /// loading of word addressed data will fail.
+ /// - returns: AVRISP_OK or AVRISP_FAILED for bad parameters.
+ AvrIspResult read_continue (uint8_t *data, uint16_t size);
+ /// End read command.
+ /// - returns: AVRISP_OK or AVRISP_FAILED if too early.
+ AvrIspResult read_end ();
+ /// Program miscellaneous memory (fuse, lock).
+ /// - cmd: program command.
+ void program_misc (const uint8_t cmd[4]);
+ /// Read miscellaneous memory (fuse, lock, signature, osccal).
+ /// - ret_addr: transfer index at which the return value must be read.
+ /// - cmd: read command.
+ uint8_t read_misc (uint8_t ret_addr, const uint8_t cmd[4]);
+ /// Generic SPI access.
+ /// - num_tx: number of bytes to transmit.
+ /// - num_rx: number of bytes to receive.
+ /// - rx_start: start reception after this number of transmitted bytes.
+ /// - dout: buffer to read sent bytes.
+ /// - din: buffer to write received bytes.
+ /// Limitation: no support for doing this in several chunks as memory
+ /// programing and reading.
+ void multi (uint8_t num_tx, uint8_t num_rx, uint8_t rx_start,
+ const uint8_t *dout, uint8_t *din);
+ private:
+ /// Transmit a 16 bit data.
+ void spi_tx_16 (uint16_t data);
+ /// Transmit a 32 bit data and return last byte received. This is used for
+ /// RDY/BSY polling.
+ uint8_t spi_tx_32 (uint32_t data);
+ private:
+ /// Hardware interface.
+ AvrIspIntf &intf_;
+ /// Current address.
+ uint16_t addr_;
+ /// Current extended address.
+ uint8_t ext_addr_;
+ /// Extended address loaded in device.
+ uint8_t last_ext_addr_;
+ /// Whether the device needs extended addressing.
+ uint8_t larger_than_64k_;
+ /// Programming start address (used for page program command).
+ uint16_t start_addr_;
+ /// Number of bytes left to process.
+ uint16_t bytes_left_;
+ /// Programming mode.
+ uint8_t mode_;
+ /// Programming delay if no other poll method.
+ uint8_t delay_ms_;
+ /// Write Program Memory or Load Page.
+ uint8_t cmd_write_mem_;
+ /// Write Page.
+ uint8_t cmd_write_page_;
+ /// Read Program Memory.
+ uint8_t cmd_read_mem_;
+ /// Value read until memory is programmed for value polling.
+ uint8_t poll_[2];
+ /// Whether the page can be polled (if almost one byte is not poll[0]).
+ /// This is non zero if true, with LSB = 1 for high byte.
+ uint8_t pollable_;
+ /// Address to use for polling.
+ uint16_t poll_addr_;
+ /// Whether this is a flash memory.
+ uint8_t flash_;
+};
+
+} // namespace ucoo
+
+#endif // ucoolib_dev_avrisp_avrisp_hh
diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.cc b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.cc
new file mode 100644
index 00000000..04a1f1a5
--- /dev/null
+++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.cc
@@ -0,0 +1,173 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// 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.
+//
+// }}}
+#include "avrisp_frame.hh"
+
+namespace ucoo {
+
+static const uint8_t avrisp_frame_proto_start = 27;
+static const uint8_t avrisp_frame_proto_token = 14;
+static const uint8_t avrisp_frame_proto_answer_cksum_error = 0xb0;
+static const uint8_t avrisp_frame_proto_status_cksum_error = 0xc1;
+
+AvrIspFrame::AvrIspFrame (AvrIspProto &proto)
+ : proto_ (proto), state_ (AVRISP_FRAME_STATE_START), buffer_send_index_ (-1)
+{
+}
+
+void
+AvrIspFrame::read_and_write (Stream &stream)
+{
+ // Design is inherited from byte based C interface.
+ while (1)
+ {
+ if (buffer_send_index_ == -1)
+ {
+ // Read.
+ int c = stream.getc ();
+ if (c == -1)
+ return;
+ else
+ accept_char (c);
+ }
+ else
+ {
+ // Write.
+ int r = stream.write (reinterpret_cast<char *> (buffer_)
+ + buffer_send_index_,
+ buffer_len_ - buffer_send_index_);
+ if (r <= 0)
+ return;
+ else
+ buffer_send_index_ += r;
+ if (buffer_send_index_ == buffer_len_)
+ buffer_send_index_ = -1;
+ }
+ }
+}
+
+inline AvrIspFrameState
+operator++ (AvrIspFrameState& state, int)
+{
+ const int i = static_cast<int> (state);
+ state = static_cast<AvrIspFrameState> (i + 1);
+ return state;
+}
+
+void
+AvrIspFrame::accept_char (uint8_t c)
+{
+ switch (state_)
+ {
+ case AVRISP_FRAME_STATE_START:
+ if (c == avrisp_frame_proto_start)
+ {
+ cksum_ = avrisp_frame_proto_start;
+ state_++;
+ }
+ break;
+ case AVRISP_FRAME_STATE_WAIT_SEQ:
+ cksum_ ^= c;
+ seq_ = c;
+ state_++;
+ break;
+ case AVRISP_FRAME_STATE_WAIT_LEN_MSB:
+ cksum_ ^= c;
+ len_ = c << 8;
+ state_++;
+ break;
+ case AVRISP_FRAME_STATE_WAIT_LEN_LSB:
+ cksum_ ^= c;
+ len_ |= c;
+ buffer_len_ = 0;
+ if (len_ == 0
+ || len_ > (UCOO_CONFIG_DEV_AVRISP_FRAME_BUFFER_SIZE - proto_head_
+ - proto_tail_))
+ state_ = AVRISP_FRAME_STATE_START;
+ else
+ state_++;
+ break;
+ case AVRISP_FRAME_STATE_WAIT_TOKEN:
+ if (c == avrisp_frame_proto_token)
+ {
+ cksum_ ^= c;
+ state_++;
+ }
+ else
+ state_ = AVRISP_FRAME_STATE_START;
+ break;
+ case AVRISP_FRAME_STATE_DATA:
+ cksum_ ^= c;
+ buffer_[proto_head_ + buffer_len_++] = c;
+ if (buffer_len_ == len_)
+ state_++;
+ break;
+ case AVRISP_FRAME_STATE_WAIT_CKSUM:
+ cksum_ ^= c;
+ state_ = AVRISP_FRAME_STATE_START;
+ process ();
+ break;
+ }
+}
+
+void
+AvrIspFrame::send_frame (int len)
+{
+ int i = 0;
+ uint8_t cksum;
+ buffer_[i++] = avrisp_frame_proto_start;
+ cksum = avrisp_frame_proto_start;
+ buffer_[i++] = seq_;
+ cksum ^= seq_;
+ buffer_[i++] = len >> 8;
+ cksum ^= len >> 8;
+ buffer_[i++] = len & 0xff;
+ cksum ^= len & 0xff;
+ buffer_[i++] = avrisp_frame_proto_token;
+ cksum ^= avrisp_frame_proto_token;
+ for (; i < proto_head_ + len; i++)
+ cksum ^= buffer_[i];
+ buffer_[i] = cksum;
+ buffer_len_ = proto_head_ + len + proto_tail_;
+ buffer_send_index_ = 0;
+}
+
+void
+AvrIspFrame::process ()
+{
+ if (cksum_ != 0)
+ {
+ /* Bad checksum. */
+ buffer_[proto_head_] = avrisp_frame_proto_answer_cksum_error;
+ buffer_[proto_head_ + 1] = avrisp_frame_proto_status_cksum_error;
+ send_frame (2);
+ }
+ else
+ {
+ int r = proto_.accept (buffer_ + proto_head_, buffer_len_);
+ if (r)
+ send_frame (r);
+ }
+}
+
+} // namespace ucoo
diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.hh b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.hh
new file mode 100644
index 00000000..c51e42df
--- /dev/null
+++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_frame.hh
@@ -0,0 +1,95 @@
+#ifndef ucoolib_dev_avrisp_avrisp_frame_hh
+#define ucoolib_dev_avrisp_avrisp_frame_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// 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.
+//
+// }}}
+#include "avrisp_proto.hh"
+
+#include "ucoolib/intf/stream.hh"
+
+#include "config/dev/avrisp.hh"
+
+namespace ucoo {
+
+/// State of frame decoding.
+enum AvrIspFrameState
+{
+ /// Start state, nothing decoded.
+ AVRISP_FRAME_STATE_START,
+ /// After message started, waiting sequence number.
+ AVRISP_FRAME_STATE_WAIT_SEQ,
+ /// Waiting first length byte.
+ AVRISP_FRAME_STATE_WAIT_LEN_MSB,
+ /// Waiting second length byte.
+ AVRISP_FRAME_STATE_WAIT_LEN_LSB,
+ /// Waiting token.
+ AVRISP_FRAME_STATE_WAIT_TOKEN,
+ /// Reading data.
+ AVRISP_FRAME_STATE_DATA,
+ /// Waiting checksum.
+ AVRISP_FRAME_STATE_WAIT_CKSUM,
+};
+
+/// Transfer data between a Stream and AvrIspProto which works frame by frame.
+class AvrIspFrame
+{
+ public:
+ /// Constructor.
+ AvrIspFrame (AvrIspProto &proto);
+ /// Read & write from stream. If operation on stream blocks, this will
+ /// block too.
+ void read_and_write (Stream &stream);
+ private:
+ /// Handle received char.
+ void accept_char (uint8_t c);
+ /// Send frame in buffer (actually just setup, work is done in
+ /// read_and_write()).
+ void send_frame (int len);
+ /// Process found received frame.
+ void process ();
+ private:
+ /// Frame based ISP protocol handler.
+ AvrIspProto &proto_;
+ /// Current state.
+ AvrIspFrameState state_;
+ /// Message sequence number.
+ uint8_t seq_;
+ /// Message length.
+ int len_;
+ /// Checksum current value.
+ uint8_t cksum_;
+ /// Buffer to store frame until validated.
+ uint8_t buffer_[UCOO_CONFIG_DEV_AVRISP_FRAME_BUFFER_SIZE];
+ /// Used buffer length.
+ int buffer_len_;
+ /// Index to first byte to send from buffer, or -1 if not sending.
+ int buffer_send_index_;
+ /// Size of the frame header.
+ static const uint8_t proto_head_ = 5;
+ /// Size of the frame tail.
+ static const uint8_t proto_tail_ = 1;
+};
+
+} // namespace ucoo
+
+#endif // ucoolib_dev_avrisp_avrisp_frame_hh
diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.cc b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.cc
new file mode 100644
index 00000000..9c025d3c
--- /dev/null
+++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.cc
@@ -0,0 +1,269 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// 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.
+//
+// }}}
+#include "avrisp_proto.hh"
+
+#include "ucoolib/utils/bytes.hh"
+
+#include "config/dev/avrisp.hh"
+
+#include <cstring>
+#include <algorithm>
+
+namespace ucoo {
+
+/// Protocol commands.
+enum AvrIspProtoCmd
+{
+ AVRISP_PROTO_CMD_SIGN_ON = 0x01,
+ AVRISP_PROTO_CMD_SET_PARAMETER = 0x02,
+ AVRISP_PROTO_CMD_GET_PARAMETER = 0x03,
+ AVRISP_PROTO_CMD_SET_DEVICE_PARAMETERS = 0x04,
+ AVRISP_PROTO_CMD_OSCCAL = 0x05,
+ AVRISP_PROTO_CMD_LOAD_ADDRESS = 0x06,
+ AVRISP_PROTO_CMD_FIRMWARE_UPGRADE = 0x07,
+ AVRISP_PROTO_CMD_ENTER_PROGMODE_ISP = 0x10,
+ AVRISP_PROTO_CMD_LEAVE_PROGMODE_ISP = 0x11,
+ AVRISP_PROTO_CMD_CHIP_ERASE_ISP = 0x12,
+ AVRISP_PROTO_CMD_PROGRAM_FLASH_ISP = 0x13,
+ AVRISP_PROTO_CMD_READ_FLASH_ISP = 0x14,
+ AVRISP_PROTO_CMD_PROGRAM_EEPROM_ISP = 0x15,
+ AVRISP_PROTO_CMD_READ_EEPROM_ISP = 0x16,
+ AVRISP_PROTO_CMD_PROGRAM_FUSE_ISP = 0x17,
+ AVRISP_PROTO_CMD_READ_FUSE_ISP = 0x18,
+ AVRISP_PROTO_CMD_PROGRAM_LOCK_ISP = 0x19,
+ AVRISP_PROTO_CMD_READ_LOCK_ISP = 0x1a,
+ AVRISP_PROTO_CMD_READ_SIGNATURE_ISP = 0x1b,
+ AVRISP_PROTO_CMD_READ_OSCCAL_ISP = 0x1c,
+ AVRISP_PROTO_CMD_SPI_MULTI = 0x1d,
+};
+
+/// Protocol command status.
+enum AvrIspProtoStatus
+{
+ AVRISP_PROTO_STATUS_CMD_OK = 0x00,
+
+ AVRISP_PROTO_STATUS_CMD_TOUT = 0x80,
+ AVRISP_PROTO_STATUS_RDY_BSY_TOUT = 0x81,
+ AVRISP_PROTO_STATUS_SET_PARAM_MISSING = 0x82,
+
+ AVRISP_PROTO_STATUS_CMD_FAILED = 0xc0,
+ AVRISP_PROTO_STATUS_CKSUM_ERROR = 0xc1,
+ AVRISP_PROTO_STATUS_CMD_UNKNOWN = 0xc9,
+};
+
+/// Protocol parameters.
+enum AvrIspProtoParam
+{
+ AVRISP_PROTO_PARAM_BUILD_NUMBER_LOW = 0x80,
+ AVRISP_PROTO_PARAM_BUILD_NUMBER_HIGH = 0x81,
+ AVRISP_PROTO_PARAM_HW_VER = 0x90,
+ AVRISP_PROTO_PARAM_SW_MAJOR = 0x91,
+ AVRISP_PROTO_PARAM_SW_MINOR = 0x92,
+ AVRISP_PROTO_PARAM_VTARGET = 0x94,
+ AVRISP_PROTO_PARAM_VADJUST = 0x95,
+ AVRISP_PROTO_PARAM_OSC_PSCALE = 0x96,
+ AVRISP_PROTO_PARAM_OSC_CMATCH = 0x97,
+ AVRISP_PROTO_PARAM_SCK_DURATION = 0x98,
+ AVRISP_PROTO_PARAM_TOPCARD_DETECT = 0x9a,
+ AVRISP_PROTO_PARAM_STATUS = 0x9c,
+ AVRISP_PROTO_PARAM_DATA = 0x9d,
+ AVRISP_PROTO_PARAM_RESET_POLARITY = 0x9e,
+ AVRISP_PROTO_PARAM_CONTROLLER_INIT = 0x9f,
+};
+
+static inline AvrIspProtoStatus
+avrisp_proto_isp_status (AvrIspResult isp_status)
+{
+ if (isp_status == AVRISP_OK)
+ return AVRISP_PROTO_STATUS_CMD_OK;
+ else if (isp_status == AVRISP_TIMEOUT)
+ return AVRISP_PROTO_STATUS_CMD_TOUT;
+ else
+ return AVRISP_PROTO_STATUS_CMD_FAILED;
+}
+
+AvrIspProto::AvrIspProto (AvrIsp &isp)
+ : isp_ (isp), sck_duration_us_ (1)
+{
+}
+
+int
+AvrIspProto::accept (uint8_t *data, int len)
+{
+ uint8_t r;
+ AvrIspProtoStatus status;
+ AvrIspResult isp_status;
+ uint16_t size;
+ /* Decode command. */
+ switch (data[0])
+ {
+ case AVRISP_PROTO_CMD_SIGN_ON:
+ if (len != 1) break;
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ data[2] = sizeof (UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE);
+ memcpy (&data[3], UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE,
+ sizeof (UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE));
+ return 3 + sizeof (UCOO_CONFIG_DEV_AVRISP_PROTO_SIGNATURE);
+ case AVRISP_PROTO_CMD_SET_PARAMETER:
+ if (len != 3) break;
+ status = AVRISP_PROTO_STATUS_CMD_OK;
+ switch (data[1])
+ {
+ case AVRISP_PROTO_PARAM_SCK_DURATION:
+ sck_duration_us_ = std::max (data[2], static_cast<uint8_t> (1));
+ break;
+ case AVRISP_PROTO_PARAM_RESET_POLARITY:
+ if (data[2] != 1)
+ status = AVRISP_PROTO_STATUS_CMD_FAILED;
+ break;
+ default:
+ status = AVRISP_PROTO_STATUS_CMD_FAILED;
+ break;
+ }
+ data[1] = status;
+ return 2;
+ case AVRISP_PROTO_CMD_GET_PARAMETER:
+ if (len != 2) break;
+ status = AVRISP_PROTO_STATUS_CMD_OK;
+ switch (data[1])
+ {
+ case AVRISP_PROTO_PARAM_SCK_DURATION:
+ data[2] = sck_duration_us_;
+ break;
+ case AVRISP_PROTO_PARAM_RESET_POLARITY:
+ data[2] = 1;
+ break;
+ case AVRISP_PROTO_PARAM_BUILD_NUMBER_LOW:
+ data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_BUILD_NUMBER, 0);
+ break;
+ case AVRISP_PROTO_PARAM_BUILD_NUMBER_HIGH:
+ data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_BUILD_NUMBER, 1);
+ break;
+ case AVRISP_PROTO_PARAM_HW_VER:
+ data[2] = UCOO_CONFIG_DEV_AVRISP_PROTO_HW_VERSION;
+ break;
+ case AVRISP_PROTO_PARAM_SW_MAJOR:
+ data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_SW_VERSION, 1);
+ break;
+ case AVRISP_PROTO_PARAM_SW_MINOR:
+ data[2] = bytes_unpack (UCOO_CONFIG_DEV_AVRISP_PROTO_SW_VERSION, 0);
+ break;
+ default:
+ status = AVRISP_PROTO_STATUS_CMD_FAILED;
+ break;
+ }
+ data[1] = status;
+ return status == AVRISP_PROTO_STATUS_CMD_OK ? 3 : 2;
+ case AVRISP_PROTO_CMD_LOAD_ADDRESS:
+ if (len != 5) break;
+ isp_.load_address (bytes_pack (data[1], data[2], data[3], data[4]));
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 2;
+ case AVRISP_PROTO_CMD_ENTER_PROGMODE_ISP:
+ if (len != 12) break;
+ isp_status = isp_.enter_progmode (sck_duration_us_, data[1], data[2],
+ data[3], data[4], data[5], data[6],
+ data[7], &data[8]);
+ data[1] = avrisp_proto_isp_status (isp_status);
+ return 2;
+ case AVRISP_PROTO_CMD_LEAVE_PROGMODE_ISP:
+ if (len != 3) break;
+ isp_.leave_progmode (data[1], data[2]);
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 2;
+ case AVRISP_PROTO_CMD_CHIP_ERASE_ISP:
+ if (len != 7) break;
+ isp_status = isp_.chip_erase (data[1], data[2], &data[3]);
+ data[1] = avrisp_proto_isp_status (isp_status);
+ return 2;
+ case AVRISP_PROTO_CMD_PROGRAM_FLASH_ISP:
+ case AVRISP_PROTO_CMD_PROGRAM_EEPROM_ISP:
+ if (len < 10) break;
+ size = bytes_pack (data[1], data[2]);
+ if (len != 10 + size) break;
+ isp_status = isp_.program_begin (size, data[3], data[4], data[5], data[6],
+ data[7], &data[8], data[0]
+ == AVRISP_PROTO_CMD_PROGRAM_FLASH_ISP);
+ if (isp_status == AVRISP_OK)
+ isp_status = isp_.program_continue (&data[10], size);
+ if (isp_status == AVRISP_OK)
+ isp_status = isp_.program_end ();
+ data[1] = avrisp_proto_isp_status (isp_status);
+ return 2;
+ case AVRISP_PROTO_CMD_READ_FLASH_ISP:
+ case AVRISP_PROTO_CMD_READ_EEPROM_ISP:
+ if (len != 4) break;
+ size = bytes_pack (data[1], data[2]);
+ isp_status = isp_.read_begin (size, data[3], data[0]
+ == AVRISP_PROTO_CMD_READ_FLASH_ISP);
+ if (isp_status == AVRISP_OK)
+ isp_status = isp_.read_continue (&data[2], size);
+ if (isp_status == AVRISP_OK)
+ isp_status = isp_.read_end ();
+ if (isp_status == AVRISP_OK)
+ {
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ data[2 + size] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 2 + size + 1;
+ }
+ else
+ {
+ data[1] = AVRISP_PROTO_STATUS_CMD_FAILED;
+ return 2;
+ }
+ case AVRISP_PROTO_CMD_PROGRAM_FUSE_ISP:
+ case AVRISP_PROTO_CMD_PROGRAM_LOCK_ISP:
+ if (len != 5) break;
+ isp_.program_misc (&data[1]);
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ data[2] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 3;
+ case AVRISP_PROTO_CMD_READ_FUSE_ISP:
+ case AVRISP_PROTO_CMD_READ_LOCK_ISP:
+ case AVRISP_PROTO_CMD_READ_SIGNATURE_ISP:
+ case AVRISP_PROTO_CMD_READ_OSCCAL_ISP:
+ if (len != 6) break;
+ r = isp_.read_misc (data[1], &data[2]);
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ data[2] = r;
+ data[3] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 4;
+ case AVRISP_PROTO_CMD_SPI_MULTI:
+ if (len < 4) break;
+ size = data[2];
+ if (len != 4 + size) break;
+ isp_.multi (data[1], data[2], data[3], &data[4], &data[2]);
+ data[1] = AVRISP_PROTO_STATUS_CMD_OK;
+ data[2 + size] = AVRISP_PROTO_STATUS_CMD_OK;
+ return 2 + size + 1;
+ default:
+ /* Unknown. */
+ data[1] = AVRISP_PROTO_STATUS_CMD_UNKNOWN;
+ return 2;
+ }
+ data[1] = AVRISP_PROTO_STATUS_CMD_FAILED;
+ return 2;
+}
+
+} // namespace ucoo
diff --git a/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.hh b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.hh
new file mode 100644
index 00000000..2c09c092
--- /dev/null
+++ b/digital/ucoolib/ucoolib/dev/avrisp/avrisp_proto.hh
@@ -0,0 +1,50 @@
+#ifndef ucoolib_dev_avrisp_avrisp_proto_hh
+#define ucoolib_dev_avrisp_avrisp_proto_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// 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.
+//
+// }}}
+#include "avrisp.hh"
+
+namespace ucoo {
+
+/// Interpret commands in the AVR068 and AVR069 format. Framing is needed for
+/// AVR068 and provided by AvrIspFrame.
+class AvrIspProto
+{
+ public:
+ /// Constructor.
+ AvrIspProto (AvrIsp &isp);
+ /// Accept a frame to interpret. Return the response length provided in
+ /// the same buffer. The buffer should be large enough to store the
+ /// largest frame used by AVR06[89] protocol.
+ int accept (uint8_t *data, int len);
+ private:
+ /// Ref to ISP class.
+ AvrIsp &isp_;
+ /// SCK period.
+ uint8_t sck_duration_us_;
+};
+
+} // namespace ucoo
+
+#endif // ucoolib_dev_avrisp_avrisp_proto_hh
diff --git a/digital/ucoolib/ucoolib/dev/avrisp/test/Makefile b/digital/ucoolib/ucoolib/dev/avrisp/test/Makefile
new file mode 100644
index 00000000..80a83341
--- /dev/null
+++ b/digital/ucoolib/ucoolib/dev/avrisp/test/Makefile
@@ -0,0 +1,9 @@
+BASE = ../../../..
+
+TARGETS = stm32f4
+PROGS = test_avrisp
+test_avrisp_SOURCES = test_avrisp.cc
+
+MODULES = dev/avrisp hal/spi hal/gpio base/test hal/usb utils
+
+include $(BASE)/build/top.mk
diff --git a/digital/ucoolib/ucoolib/dev/avrisp/test/test_avrisp.cc b/digital/ucoolib/ucoolib/dev/avrisp/test/test_avrisp.cc
new file mode 100644
index 00000000..66ecf14f
--- /dev/null
+++ b/digital/ucoolib/ucoolib/dev/avrisp/test/test_avrisp.cc
@@ -0,0 +1,90 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// 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.
+//
+// }}}
+#include "ucoolib/dev/avrisp/avrisp_frame.hh"
+
+#include "ucoolib/arch/arch.hh"
+#include "ucoolib/base/test/test.hh"
+#include "ucoolib/hal/gpio/gpio.hh"
+#include "ucoolib/hal/spi/spi_soft.hh"
+#include "ucoolib/utils/delay.hh"
+
+#include <libopencm3/stm32/f4/rcc.h>
+#include <libopencm3/stm32/f4/gpio.h>
+
+class TestAvrIspIntf : public ucoo::AvrIspIntf
+{
+ public:
+ TestAvrIspIntf (ucoo::Io &reset, ucoo::Io &sck, ucoo::Io &mosi,
+ ucoo::Io &miso)
+ : reset_ (reset), sck_ (sck), spi_ (sck, mosi, miso) { }
+ uint8_t send_and_recv (uint8_t tx)
+ {
+ return spi_.send_and_recv (tx);
+ }
+ void enable (uint8_t sck_duration_us)
+ {
+ reset_.output ();
+ reset_.reset ();
+ sck_.output ();
+ sck_.reset ();
+ ucoo::delay_us (1000);
+ reset_.set ();
+ ucoo::delay_us (100);
+ reset_.reset ();
+ int freq = 1000000 / sck_duration_us;
+ spi_.setup (freq, ucoo::SPI_MODE_0);
+ }
+ void disable ()
+ {
+ spi_.setup (0);
+ reset_.input ();
+ }
+ void sck_pulse ()
+ {
+ sck_.toggle ();
+ ucoo::delay_us (100);
+ sck_.toggle ();
+ }
+ private:
+ ucoo::Io &reset_;
+ ucoo::Io &sck_;
+ ucoo::SpiSoftMaster spi_;
+};
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::Stream &ts = ucoo::test_stream ();
+ rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN
+ | RCC_AHB1ENR_IOPEEN);
+ ucoo::Gpio reset (GPIOD, 10), sck (GPIOE, 7), mosi (GPIOD, 8),
+ miso (GPIOD, 9);
+ TestAvrIspIntf intf (reset, sck, mosi, miso);
+ ucoo::AvrIsp isp (intf);
+ ucoo::AvrIspProto proto (isp);
+ ucoo::AvrIspFrame frame (proto);
+ while (1)
+ frame.read_and_write (ts);
+}