Trammell Hudson avatar Trammell Hudson committed 203b3bf Draft

Analog gauge driver and box

Comments (0)

Files changed (12)

 
 
 # Target file name (without extension).
-TARGET = prom
+TARGET = gauge
 
 
 # List C source files here. (C dependencies are automatically generated.)
 SRC =	$(TARGET).c \
 	bits.c \
-	xmodem.c \
 	usb_serial.c \
 
-
 # MCU name, you MUST set this to match the board you are using
 # type "make clean" after changing this, so all files will be rebuilt
 #
 #MCU = at90usb162       # Teensy 1.0
-#MCU = atmega32u4        # Teensy 2.0
+MCU = atmega32u4        # Teensy 2.0
 #MCU = at90usb646       # Teensy++ 1.0
-MCU = at90usb1286      # Teensy++ 2.0
+#MCU = at90usb1286      # Teensy++ 2.0
 
 
 # Processor frequency.
 
 	switch (port)
 	{
+#if 0
 	case 0xA:
 		set_bit(DDRA, pin, value);
 		return;
+#endif
 	case 0xB:
 		set_bit(DDRB, pin, value);
 		return;
 
 	switch (port)
 	{
+#if 0
 	case 0xA:
 		set_bit(PORTA, pin, value);
 		return;
+#endif
 	case 0xB:
 		set_bit(PORTB, pin, value);
 		return;
 
 	switch (port)
 	{
+#if 0
 	case 0xA:
 		return get_bit(PINA, pin);
+#endif
 	case 0xB:
 		return get_bit(PINB, pin);
 	case 0xC:
Added
New image
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with boxer (http://trmm.net/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg4501"
+   version="1.1"
+   inkscape:version="0.48.2 r9819"
+   width="100%"
+   height="100%"
+   sodipodi:docname="box.svg">
+  <metadata
+     id="metadata4533">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs4531" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1440"
+     inkscape:window-height="852"
+     id="namedview4529"
+     showgrid="false"
+     inkscape:zoom="0.60245418"
+     inkscape:cx="372.04724"
+     inkscape:cy="526.18109"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="g4503" />
+  <g
+     transform="scale(3.543307)"
+     id="g4503">
+    <!-- scale to mm -->
+    <g
+       transform="translate(2.4765489,15.958959)"
+       id="g4505">
+      <path
+         d="m 5,5 7.9,0 0,-5 10.2,0 0,5 9.8,0 0,-5 10.2,0 0,5 9.8,0 0,-5 10.2,0 0,5 9.8,0 0,-5 10.2,0 0,5 7.9,0 0,7.9 5,0 0,10.2 -5,0 0,9.8 5,0 0,10.2 -5,0 0,9.8 5,0 0,10.2 -5,0 0,9.8 5,0 0,10.2 -5,0 0,7.9 -7.9,0 0,5 -10.2,0 0,-5 -9.8,0 0,5 -10.2,0 0,-5 -9.8,0 0,5 -10.2,0 0,-5 -9.8,0 0,5 -10.2,0 0,-5 -7.9,0 0,-7.9 -5,0 0,-10.2 5,0 0,-9.8 -5,0 0,-10.2 5,0 0,-9.8 -5,0 0,-10.2 5,0 0,-9.8 -5,0 0,-10.2 5,0 L 5,5"
+         id="path4507"
+         inkscape:connector-curvature="0"
+         style="fill:none;stroke:#ff0000;stroke-width:0.1px" />
+    </g>
+    <g
+       transform="translate(2.0973189,120.16444)"
+       id="g4513">
+      <path
+         id="path4541"
+         style="fill:none;stroke:#ff0000;stroke-width:0.1px"
+         d="m 95.997856,0 -12.9,0 -0.2,5 -9.8,0 -0.2,-5 -9.8,0 -0.2,5 -9.8,0 -0.2,-5 -4.9,0 M 0,0 l 12.9,0 0.2,5 9.8,0 0.2,-5 9.8,0 0.2,5 9.8,0 0.2,-5 4.9,0 m -48,0 0,14.9 5,0.2 0,9.8 -5,0.2 0,9.8 5,0.2 0,9.8 -5,0.2 0,9.8 5,0.2 0,9.8 -5,0.2 0,14.9 95.997856,0 0,-14.9 -5,-0.2 0,-9.8 5,-0.2 0,-9.8 -5,-0.2 0,-9.8 5,-0.2 0,-9.8 -5,-0.2 0,-9.8 5,-0.2 0,-14.9"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccc" />
+    </g>
+    <g
+       transform="translate(104.98606,83.096802)"
+       id="g4517">
+      <path
+         d="m 0,0 12.9,0 0.2,5 9.8,0 0.2,-5 9.8,0 0.2,5 9.8,0 0.2,-5 9.8,0 0.2,5 9.8,0 0.2,-5 9.8,0 0.2,5 9.8,0 0.2,-5 7.9,0 0,14.9 5,0 0,10.2 -5,0 0,9.8 5,0 0,10.2 -5,0 0,9.8 5,0 0,10.2 -5,0 L 91,80 0,34.9 0,25.1 5,24.9 5,15.1 0,14.9 0,0"
+         id="path4519"
+         inkscape:connector-curvature="0"
+         style="fill:none;stroke:#ff0000;stroke-width:0.1px"
+         sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccc" />
+    </g>
+    <path
+       sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
+       inkscape:connector-curvature="0"
+       d="m 151.04178,164.08062 4.9,0 0.2,5 9.8,0 0.2,-5 9.8,0 0.2,5 9.8,0 0.2,-5 7.9,0 0,14.9 5,0 0,10.2 -5,0 0,9.8 -86.09998,0 0,-9.8 -5,0 0,-10.2 5,0 0,-14.9 7.9,0 0.2,5 9.8,0 0.2,-5 9.8,0 0.2,5 9.8,0 0.2,-5 4.9,0"
+       style="fill:none;stroke:#ff0000;stroke-width:0.1px"
+       id="path4547" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4640"
+       y="69.638885"
+       x="29.192924"
+       style="font-size:6.77333355px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:georgia;-inkscape-font-specification:georgia"
+       xml:space="preserve"><tspan
+         y="69.638885"
+         x="29.192924"
+         id="tspan4642"
+         sodipodi:role="line">Badass Gauge</tspan></text>
+    <g
+       id="g4535"
+       transform="matrix(1,0,0,-1,104.64276,81.659952)">
+      <path
+         sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccc"
+         style="fill:none;stroke:#ff0000;stroke-width:0.1px"
+         inkscape:connector-curvature="0"
+         id="path4537"
+         d="m 0,0 12.9,0 0.2,5 9.8,0 0.2,-5 9.8,0 0.2,5 9.8,0 0.2,-5 9.8,0 0.2,5 9.8,0 0.2,-5 9.8,0 0.2,5 9.8,0 0.2,-5 7.9,0 0,14.9 5,0 0,10.2 -5,0 0,9.8 5,0 0,10.2 -5,0 0,9.8 5,0 0,10.2 -5,0 L 91,80 0,34.9 0,25.1 5,24.9 5,15.1 0,14.9 0,0" />
+    </g>
+    <g
+       id="g4724"
+       transform="translate(50.235778,67.599191)"
+       style="stroke-width:0.28222224;stroke-miterlimit:4;stroke-dasharray:none">
+      <circle
+         id="circle4726"
+         r="38"
+         cy="0"
+         cx="0"
+         sodipodi:cx="0"
+         sodipodi:cy="0"
+         sodipodi:rx="38"
+         sodipodi:ry="38"
+         style="fill:none;stroke:#ff0000;stroke-width:0.28222224;stroke-miterlimit:4;stroke-dasharray:none"
+         d="M 38,0 C 38,20.98682 20.98682,38 0,38 -20.98682,38 -38,20.98682 -38,0 c 0,-20.98682 17.01318,-38 38,-38 20.98682,0 38,17.01318 38,38 z" />
+      <g
+         id="g4728"
+         transform="matrix(0.5,0.8660254,-0.8660254,0.5,0,0)"
+         style="stroke-width:0.28222224;stroke-miterlimit:4;stroke-dasharray:none">
+        <circle
+           id="circle4730"
+           r="3"
+           cx="0"
+           cy="43"
+           sodipodi:cx="0"
+           sodipodi:cy="43"
+           sodipodi:rx="3"
+           sodipodi:ry="3"
+           style="fill:none;stroke:#ff0000;stroke-width:0.28222224;stroke-miterlimit:4;stroke-dasharray:none"
+           d="m 3,43 c 0,1.656854 -1.3431458,3 -3,3 -1.6568542,0 -3,-1.343146 -3,-3 0,-1.656854 1.3431458,-3 3,-3 1.6568542,0 3,1.343146 3,3 z" />
+      </g>
+      <g
+         id="g4732"
+         transform="scale(-1,-1)"
+         style="stroke-width:0.28222224;stroke-miterlimit:4;stroke-dasharray:none">
+        <circle
+           id="circle4734"
+           r="3"
+           cx="0"
+           cy="43"
+           sodipodi:cx="0"
+           sodipodi:cy="43"
+           sodipodi:rx="3"
+           sodipodi:ry="3"
+           style="fill:none;stroke:#ff0000;stroke-width:0.28222224;stroke-miterlimit:4;stroke-dasharray:none"
+           d="m 3,43 c 0,1.656854 -1.3431458,3 -3,3 -1.6568542,0 -3,-1.343146 -3,-3 0,-1.656854 1.3431458,-3 3,-3 1.6568542,0 3,1.343146 3,3 z" />
+      </g>
+      <g
+         id="g4736"
+         transform="matrix(0.5,-0.8660254,0.8660254,0.5,0,0)"
+         style="stroke-width:0.28222224;stroke-miterlimit:4;stroke-dasharray:none">
+        <circle
+           id="circle4738"
+           r="3"
+           cx="0"
+           cy="43"
+           sodipodi:cx="0"
+           sodipodi:cy="43"
+           sodipodi:rx="3"
+           sodipodi:ry="3"
+           style="fill:none;stroke:#ff0000;stroke-width:0.28222224;stroke-miterlimit:4;stroke-dasharray:none"
+           d="m 3,43 c 0,1.656854 -1.3431458,3 -3,3 -1.6568542,0 -3,-1.343146 -3,-3 0,-1.656854 1.3431458,-3 3,-3 1.6568542,0 3,1.343146 3,3 z" />
+      </g>
+    </g>
+  </g>
+</svg>
+/**
+ * \file Badass gauge driver
+ *
+ * Drives mA gauges via PWM.
+ */
+
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <avr/interrupt.h>
+#include <stdint.h>
+#include <string.h>
+#include <util/delay.h>
+#include "usb_serial.h"
+#include "bits.h"
+
+void send_str(const char *s);
+uint8_t recv_str(char *buf, uint8_t size);
+void parse_and_execute_command(const char *buf, uint8_t num);
+
+static uint8_t
+hexdigit(
+	uint8_t x
+)
+{
+	x &= 0xF;
+	if (x < 0xA)
+		return x + '0' - 0x0;
+	else
+		return x + 'A' - 0xA;
+}
+
+
+int main(void)
+{
+	// set for 16 MHz clock
+#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
+	CPU_PRESCALE(0);
+
+	// Disable the ADC
+	ADMUX = 0;
+
+	// initialize the USB, and then wait for the host
+	// to set configuration.  If the Teensy is powered
+	// without a PC connected to the USB port, this 
+	// will wait forever.
+	usb_init();
+	while (!usb_configured()) /* wait */ ;
+	_delay_ms(1000);
+
+	// wait for the user to run their terminal emulator program
+	// which sets DTR to indicate it is ready to receive.
+	while (!(usb_serial_get_control() & USB_SERIAL_DTR))
+		continue;
+
+	// discard anything that was received prior.  Sometimes the
+	// operating system or other software will send a modem
+	// "AT command", which can still be buffered.
+	usb_serial_flush_input();
+
+#define GAUGE1 0xC6
+
+	ddr(GAUGE1, 1);
+	out(GAUGE1, 0);
+
+	// Configure OC3A in fast-PWM mode, 10-bit
+	sbi(TCCR3B, WGM32);
+	sbi(TCCR3A, WGM31);
+	sbi(TCCR3A, WGM30);
+
+	// Configure output mode to clear on match, set at top
+	sbi(TCCR3A, COM3A1);
+	cbi(TCCR3A, COM3A0);
+
+	// Configure clock 3 at clk/1
+	cbi(TCCR3B, CS32);
+	cbi(TCCR3B, CS31);
+	sbi(TCCR3B, CS30);
+
+/*
+	// or configure output mode to clear on match, set at top
+	cbi(TCCR3A, COM3A1);
+	sbi(TCCR3A, COM3A0);
+*/
+
+	OCR3A = 255;
+	uint16_t val = 0;
+
+	send_str(PSTR("badass gauge\r\n"));
+	while (1)
+	{
+		int c = usb_serial_getchar();
+		if (c == -1)
+			continue;
+
+		if (c == '!')
+		{
+			OCR3A = 0;
+			val = 0;
+			continue;
+		}
+		if (c == '@')
+		{
+			OCR3A = 1023;
+			val = 0;
+			continue;
+		}
+
+		if ('0' <= c && c <= '9')
+		{
+			val = (val << 4) | (c - '0' + 0x0);
+			continue;
+		}
+
+		if ('a' <= c && c <= 'f')
+		{
+			val = (val << 4) | (c - 'a' + 0xA);
+			continue;
+		}
+
+		if ('A' <= c && c <= 'F')
+		{
+			val = (val << 4) | (c - 'A' + 0xA);
+			continue;
+		}
+
+		if (c == '\n')
+			continue;
+
+		if (c == '\r')
+		{
+			send_str(PSTR("!\r\n"));
+			OCR3A = val;
+			val = 0;
+			continue;
+		}
+
+		send_str(PSTR("?\r\n"));
+		val = 0;
+	}
+}
+
+
+// Send a string to the USB serial port.  The string must be in
+// flash memory, using PSTR
+//
+void send_str(const char *s)
+{
+	char c;
+	while (1) {
+		c = pgm_read_byte(s++);
+		if (!c) break;
+		usb_serial_putchar(c);
+	}
+}
Added
New image
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg>
+  <!-- scale to mm -->
+  <g transform="scale(3.543307)">
+	<circle cx="0" cy="0" r="39" stroke="#ff0000" fill="none"/>
+	<g transform="rotate(60)">
+		<circle cy="43" cx="0" r="3" stroke="#ff0000" fill="none"/>
+	</g>
+	<g transform="rotate(180)">
+		<circle cy="43" cx="0" r="3" stroke="#ff0000" fill="none"/>
+	</g>
+	<g transform="rotate(300)">
+		<circle cy="43" cx="0" r="3" stroke="#ff0000" fill="none"/>
+	</g>
+  </g>
+</svg>

hex-merge

-#!/usr/bin/perl
-# Merge a low and high roms into a single image file
-use warnings;
-use strict;
-
-my $f1 = shift;
-my $f2 = shift;
-
-undef $/;
-open BIN1, "<$f1" or die;
-my $bin1 = <BIN1>;
-open BIN2, "<$f2" or die;
-my $bin2 = <BIN2>;
-
-my @b1 = split //, $bin1;
-my @b2 = split //, $bin2;
-
-my $b1_len = length $bin1;
-my $b2_len = length $bin2;
-die "File lengths $b1_len != $b2_len\n"
-	unless $b1_len == $b2_len;
-
-for my $i (0..$b1_len-1)
-{
-	print $b2[$i], $b1[$i];
-}
-
-__END__

hex2png

-#!/usr/bin/perl
-# Convert a ROM dump into a monochrome PBM
-use warnings;
-use strict;
-use Getopt::Long;
-
-my $usage = <<__END_OF_USAGE__;
-Usage:
-    $0 [options] < file.bin | convert - file.png
-
-Options:
-    -w | --width 16          Column width (in bits) to stride
-    -b | --offset N          Offset (in bits) into the stride
-    -y | --height N          Height of the image (in scan lines)
-    -m | --msb               Use most significant bit first (default LSB)
-    -s | --size N            Limit size to the first N bytes
-    -n | --negative          Invert the colors
-
-__END_OF_USAGE__
-
-my $max_size;
-my $use_msb;
-my $cols = 8;
-my $bit_offset = 0;
-my $px_height = 512;
-my $use_negative;
-my $offset = 0;
-
-GetOptions(
-	"w|width=i"		=> \$cols,
-	"b|bit-offset=i"	=> \$bit_offset,
-	"o|offset=i"		=> \$offset,
-	"m|msb+"		=> \$use_msb,
-	"s|size=i"		=> \$max_size,
-	"n|negative+"		=> \$use_negative,
-	"y|height=i"		=> \$px_height,
-) or die $usage;
-
-
-undef $/;
-my $buf = <>;
-
-# Skip offset bytes into the image
-$buf = substr $buf, $offset;
-
-$max_size ||= length $buf;
-$max_size *= 8;
-my @bits = split //, unpack($use_msb ? "b*" : "B*", $buf), $max_size;
-
-# The width of the image will be a function of the number of columns
-# and the maximum height.  This must be rounded to be an even multiple
-# of the column size
-my $px_width = int(($max_size + $px_height - 1) / $px_height);
-$px_width = int(($px_width + $cols - 1) / $cols) * $cols;
-
-warn "$max_size bits = $px_width x $px_height\n";
-
-# Now generate a PBM file with those dimensions
-print <<"";
-P1
-$px_width $px_height
-
-for (my $y = 0 ; $y < $px_height ; $y++)
-{
-	my @row;
-
-	for (my $x = 0 ; $x < $px_width ; $x++)
-	{
-		my $col = $x % $cols;
-		my $group = int($x / $cols);
-		my $offset = $col + $y * $cols + $group * $cols * $px_height + $bit_offset;
-		my $bit = $offset < $max_size ? $bits[$offset] : '0';
-		$bit = !$bit if $use_negative;
-
-		push @row, $bit;
-	}
-
-	print join(' ', @row), "\n";
-}
-
-
-__END__
-
-buf = sys.stdin.read()
-
-# rearrange buf into parallel columns
-bw=8*6
-cols=128
-w=bw*cols
-h=256*256/cols
-img = Image.new("1",(w,h))
-
-for c in range(cols):
-    colimg = Image.fromstring("1",(bw,h),buf[c*h:(c+int(bw/8))*h])
-    img.paste(colimg,(bw*c,0))
-
-img.save(sys.argv[1])

make-images

-#!/bin/sh
-
-file=$1
-for width in 008 016 032 064 128 256 384 512 1024; do
-	for order in '' '-m'; do
-		../hex2png \
-			-w $width \
-			-y 1024 \
-			$order \
-			$file \
-		| convert - \
-			$file.$width.$order.png
-	done
-done

prom.c

-/**
- * \file PROM dancer
- *
- * Read up to 40 pin DIP PROMs using a Teensy++ 2.0
- */
-
-#include <avr/io.h>
-#include <avr/pgmspace.h>
-#include <avr/interrupt.h>
-#include <stdint.h>
-#include <string.h>
-#include <util/delay.h>
-#include "usb_serial.h"
-#include "xmodem.h"
-#include "bits.h"
-
-void send_str(const char *s);
-uint8_t recv_str(char *buf, uint8_t size);
-void parse_and_execute_command(const char *buf, uint8_t num);
-
-static uint8_t
-hexdigit(
-	uint8_t x
-)
-{
-	x &= 0xF;
-	if (x < 0xA)
-		return x + '0' - 0x0;
-	else
-		return x + 'A' - 0xA;
-}
-
-
-static uint8_t
-printable(
-	uint8_t x
-)
-{
-	if ('A' <= x && x <= 'Z')
-		return 1;
-	if ('a' <= x && x <= 'z')
-		return 1;
-	if ('0' <= x && x <= '9')
-		return 1;
-	if (x == ' ')
-		return 1;
-
-	return 0;
-}
-	
-
-/** Total number of mapped pins.
- * This is unlikely to change without a significant hardware redesign.
- */
-#define ZIF_PINS 40
-
-/** Mapping of AVR IO ports to the ZIF socket pins */
-static const uint8_t ports[ZIF_PINS+1] = {
-	[ 1]	= 0xB6,
-	[ 2]	= 0xB5,
-	[ 3]	= 0xB4,
-	[ 4]	= 0xB3,
-	[ 5]	= 0xB2,
-	[ 6]	= 0xB1,
-	[ 7]	= 0xB0,
-	[ 8]	= 0xE7,
-	[ 9]	= 0xE6,
-	[10]	= 0xA2,
-	[11]	= 0xA1,
-	[12]	= 0xF0,
-	[13]	= 0xF1,
-	[14]	= 0xF2,
-	[15]	= 0xF3,
-	[16]	= 0xF4,
-	[17]	= 0xF5,
-	[18]	= 0xF6,
-	[19]	= 0xF7,
-	[20]	= 0xA3,
-
-	[21]	= 0xA7,
-	[22]	= 0xC7,
-	[23]	= 0xC6,
-	[24]	= 0xC5,
-	[25]	= 0xC4,
-	[26]	= 0xC3,
-	[27]	= 0xC2,
-	[28]	= 0xC1,
-	[29]	= 0xC0,
-	[30]	= 0xE1,
-	[31]	= 0xE0,
-	[32]	= 0xD7,
-	[33]	= 0xD6,
-	[34]	= 0xD5,
-	[35]	= 0xD4,
-	[36]	= 0xD3,
-	[37]	= 0xD2,
-	[38]	= 0xD1,
-	[39]	= 0xD0,
-	[40]	= 0xB7,
-};
-
-
-typedef struct
-{
-	/** Name of the chip type */
-	char name[16];
-
-	/** Total number of pins on the chip */
-	uint8_t pins;
-
-	/** Total number of address pins.
-	 * The download will retrieve 2^addr_width bytes.
- 	 */
-	uint8_t addr_width;
-
-	/** Total number of data pins.
-	 * If data_pins == 0, the chip is assumed to be in AVR ISP mode.
-	 */
-	uint8_t data_width;
-
-	/** Address pins.
-	 * An array of up to 24 pins in package numbering.
-	 * Any that are 0 will be ignored.  Other than ISP mode chips,
-	 * there should be addr_width pins defined here.
-	 * These will be configured as outputs from the reader
-	 * and initially driven low.
-	 */
-	uint8_t addr_pins[24];
-
-	/** Data pins.
-	 * An array of up to 24 pins in package numbering.
-	 * Any that are 0 will be ignored.  Other than ISP mode chips,
-	 * there should be data_width pins defined here.
-	 * These will be configured as inputs from the reader,
-	 * with no pull ups.
-	 */
-	uint8_t data_pins[24];
-
-	/** Pins to be driven high at all times.
-	 * These will be configured as outputs and drive hi.
-	 * Typical power limits are sourcing 50 mA per pin.
-	 */
-	uint8_t hi_pins[8];
-
-	/** Pins to be driven low at all times.
-	 * These will be configured as outputs and driven low.
-	 * Typical power limits are sinking 50 mA per pin.
-	 */
-	uint8_t lo_pins[8];
-} prom_t;
-
-
-static const prom_t proms[] = {
-{
-	// Default is to leave everything in tristate mode
-	.name		= "NONE",
-	.pins		= 28,
-
-	.addr_width	= 0,
-	.addr_pins	= {
-	},
-
-	.data_width	= 0,
-	.data_pins	= {
-	},
-
-	.hi_pins	= { },
-	.lo_pins	= { },
-},
-{
-	.name		= "M27C512",
-	.pins		= 28,
-
-	.addr_width	= 16,
-	.addr_pins	= {
-		10, 9, 8, 7, 6, 5, 4, 3, 25, 24, 21, 23, 2, 26, 27, 1,
-	},
-
-	.data_width	= 8,
-	.data_pins	= {
-		11, 12, 13, 15, 16, 17, 18, 19,
-	},
-
-	.hi_pins	= { 28, },
-	.lo_pins	= { 22, 20, 14, },
-},
-{
-	.name		= "M27C256",
-	.pins		= 28,
-	.addr_width	= 15,
-	.addr_pins	= {
-		10, 9, 8, 7, 6, 5, 4, 3, 25, 24, 21, 23, 2, 26, 27,
-	},
-
-	.data_width	= 8,
-	.data_pins	= {
-		11, 12, 13, 15, 16, 17, 18, 19,
-	},
-	.hi_pins	= { 28, 1 },
-	.lo_pins	= { 22, 20, 14, },
-},
-{
-	.name		= "M27C64",
-	.pins		= 28,
-	.addr_width	= 13,
-	.addr_pins	= {
-		10, 9, 8, 7, 6, 5, 4, 3, 25, 24, 21, 23, 2,
-	},
-
-	.data_width	= 8,
-	.data_pins	= {
-		11, 12, 13, 15, 16, 17, 18, 19,
-	},
-	.hi_pins	= { 28, 1, 27 },
-	.lo_pins	= { 22, 20, 14, },
-},
-{
-	.name		= "C64-2732",
-	.pins		= 24,
-	.addr_width	= 12,
-	.addr_pins	= {
-		8, 7, 6, 5, 4, 3, 2, 1, 23, 22, 19, 18,
-	},
-
-	.data_width	= 8,
-	.data_pins	= {
-		9, 10, 11, 13, 14, 15, 16, 17,
-	},
-	.hi_pins	= { 24, 21 },
-	.lo_pins	= { 12, 20, },
-},
-{
-	/** 8192x8 UV EEPROM, found in DX synth */
-	.name		= "MBM2764-30",
-	.pins		= 28,
-	.addr_width	= 13,
-	.addr_pins	= {
-		10, 9, 8, 7, 6, 5, 4, 3, 25, 24, 21, 23, 2,
-	},
-
-	.data_width	= 8,
-	.data_pins	= {
-		11, 12, 13, 15, 16, 17, 18, 19,
-	},
-	.hi_pins	= {
-		//28, // vdd, disabled since external power must be used
-		27, // pgm
-		1,  // vpp
-	},
-	.lo_pins	= { 22, 20, 14, }, // !oe, !cs, gnd
-},
-{
-	/** Apple Mac SE PROM chips
-	 * Similar to a M27C512, but with the 17th address line
-	 * on 22 instead of Vpp, allowing 128 KB of data.
-	 */
-	.name		= "APPLE PROM",
-	.pins		= 28,
-	.addr_width	= 17,
-	.addr_pins	= {
-		10, 9, 8, 7, 6, 5, 4, 3, 25, 24, 21, 23, 2, 26, 27, 1, 22
-	},
-
-	.data_width	= 8,
-	.data_pins	= {
-		11, 12, 13, 15, 16, 17, 18, 19,
-	},
-	.hi_pins	= { 28, },
-	.lo_pins	= { 20, 14, },
-},
-{
-	/** 2716 mask ROM used in video games.
-	 * \note: Not tested yet.
-	 */
-	.name		= "2716 (untested)",
-	.pins		= 24,
-	.addr_width	= 11,
-	.addr_pins	= {
-		8, 7, 6, 5, 4, 3, 2, 1, 23, 22, 19,
-	},
-
-	.data_width	= 8,
-	.data_pins	= {
-		9, 10, 11, 13, 14, 15, 16, 17
-	},
-
-	.hi_pins	= { 24, 21, },
-	.lo_pins	= { 12, 20, 18 },
-},
-{
-	/** 9316 mask ROM used in video games.
-	 * \note: Not tested yet.
-	 */
-	.name		= "9316 (untested)",
-	.pins		= 24,
-	.addr_width	= 11,
-	.addr_pins	= {
-		8, 7, 6, 5, 4, 3, 2, 1, 23, 22, 19,
-	},
-
-	.data_width	= 8,
-	.data_pins	= {
-		9, 10, 11, 13, 14, 15, 16, 17
-	},
-
-	.hi_pins	= { 24, 18, },
-	.lo_pins	= { 12, 21, 20 },
-},
-{
-	.name		= "28F512 (untstd)",
-	.pins		= 32,
-	.addr_width	= 16,
-	.addr_pins	= {
-		12, 11, 10, 9, 8, 7, 6, 5, 27, 26, 23, 25, 4, 28, 29, 15
-	},
-	.data_width	= 8,
-	.data_pins	= {
-		13, 14, 15, 17, 18, 19, 20, 21,
-	},
-	.hi_pins	= {
-		32, // vcc
-		31, // !we
-		1, // Vpp
-	},
-	.lo_pins	= {
-		16, // gnd
-		24, // !oe
-		22, // !ce
-	},
-},
-{
-	// C64 kernel and basic ROMs
-	.name		= "2364A",
-	.pins		= 24,
-	.addr_width	= 13,
-	.addr_pins	= {
-		8, 7, 6, 5, 4, 3, 2, 1, 23, 22, 19, 18, 21,
-	},
-	.data_width	= 8,
-	.data_pins	= {
-		9, 10, 11, 13, 14, 15, 16, 17,
-	},
-	.hi_pins	= {
-		24,
-	},
-	.lo_pins	= {
-		12, // gnd
-		20, // !cs
-	},
-},
-{
-	.name		= "HN462732",
-	.pins		= 24,
-	.addr_width	= 12,
-	.addr_pins	= {
-		8, 7, 6, 5, 4, 3, 2, 1, 23, 22, 19, 21,
-	},
-	.data_width	= 8,
-	.data_pins	= {
-		9, 10, 11, 13, 14, 15, 16, 17,
-	},
-	.hi_pins	= {
-		24, // vcc
-	},
-	.lo_pins	= {
-		12, // gnd
-		20, // !oe
-		18, // !ce
-	},
-},
-{
-	/** atmega8.
-	 * Not an EEPROM, but a chip to read via ISP.
-	 * data_width / addr_width == 0 to indicate that this is not eeprom
-	 */
-#define ISP_MOSI 0
-#define ISP_MISO 0
-#define ISP_SCK 1
-#define ISP_RESET 2
-#define ISP_XTAL 3
-	.name		= "ATMega8",
-	.pins		= 28,
-	.addr_width	= 13,
-	.addr_pins	= {
-		[ISP_MOSI] = 17, // from the reader to the chip
-		[ISP_SCK] = 19, // SCK,
-		[ISP_RESET] = 1, // reset
-		[ISP_XTAL] = 9, // xtal
-	},
-	.data_pins	= {
-		[ISP_MISO] = 18, // from the chip back to the reader
-	},
-	.lo_pins	= {
-		8, // gnd
-		22, // gnd
-	},
-	.hi_pins	= {
-		7, // vcc
-		20, // avcc
-	},
-},
-};
-
-/** Select one of the chips */
-static const prom_t * prom = &proms[0];
-
-
-/** Translate PROM pin numbers into ZIF pin numbers */
-static inline uint8_t
-prom_pin(
-	const uint8_t pin
-)
-{
-	if (pin <= prom->pins / 2)
-		return ports[pin];
-	else
-		return ports[pin + ZIF_PINS - prom->pins];
-}
-
-
-/** Generate a 0.5 MHz clock on the XTAL pin to drive the chip
- * if it does not have a built in oscillator enabled.
- */
-static void
-isp_clock(
-	uint8_t cycles
-)
-{
-	const uint8_t xtal = prom_pin(prom->addr_pins[ISP_XTAL]);
-	for (uint8_t i = 0 ; i < cycles ; i++)
-	{
-		out(xtal, 1);
-		_delay_us(1);
-		out(xtal, 0);
-		_delay_us(1);
-	}
-}
-
-
-/** Send a byte to an AVR ISP enabled chip and read a result.
- * Since the AVR ISP is bidirectional, every byte out is also a byte in.
- */
-static uint8_t
-isp_write(
-	uint8_t byte
-)
-{
-	const uint8_t mosi = prom_pin(prom->addr_pins[ISP_MOSI]);
-	const uint8_t sck = prom_pin(prom->addr_pins[ISP_SCK]);
-	const uint8_t miso = prom_pin(prom->data_pins[ISP_MISO]);
-	uint8_t rc = 0;
-
-	for (uint8_t i = 0 ; i < 8 ; i++, byte <<= 1)
-	{
-		out(mosi, (byte & 0x80) ? 1 : 0);
-		isp_clock(4);
-
-		out(sck, 1);
-		isp_clock(4);
-
-		rc = (rc << 1) | (in(miso) ? 1 : 0);
-		out(sck, 0);
-	}
-
-	return rc;
-}
-
-
-/** Enter programming mode for an ISP chip.
- * \return 1 on success, 0 on failure.
- */
-static int
-isp_setup(void)
-{
-	// Pulse the RESET pin, while holding SCK low.
-	const uint8_t sck = prom_pin(prom->addr_pins[ISP_SCK]);
-	const uint8_t reset = prom_pin(prom->addr_pins[ISP_RESET]);
-	const uint8_t miso = prom_pin(prom->data_pins[ISP_MISO]);
-	out(sck, 0);
-	out(reset, 1);
-	isp_clock(4);
-	out(reset, 0);
-	isp_clock(255);
-
-	// Now delay at least 20 ms
-	_delay_ms(20);
-
-	uint8_t rc1, rc2, rc3, rc4;
-
-	// Enter programming mode; enable pull up on the MISO pin
-	out(miso, 1);
-
-	rc1 = isp_write(0xAC);
-	rc2 = isp_write(0x53);
-	rc3 = isp_write(0x12);
-	rc4 = isp_write(0x34);
-
-	// Disable pull up
-	out(miso, 0);
-
-	if (rc3 == 0x53)
-		return 1;
-
-	// Now show what we read
-	uint8_t buf[10];
-	buf[0] = hexdigit(rc1 >> 4);
-	buf[1] = hexdigit(rc1 >> 0);
-	buf[2] = hexdigit(rc2 >> 4);
-	buf[3] = hexdigit(rc2 >> 0);
-	buf[4] = hexdigit(rc3 >> 4);
-	buf[5] = hexdigit(rc3 >> 0);
-	buf[6] = hexdigit(rc4 >> 4);
-	buf[7] = hexdigit(rc4 >> 0);
-
-	buf[8] = '\r';
-	buf[9] = '\n';
-
-	usb_serial_write(buf, sizeof(buf));
-	return 0;
-}
-
-
-/** Read a byte using the AVRISP, instead of the normal PROM format.
- */
-static uint8_t
-isp_read(
-	uint32_t addr
-)
-{
-	uint8_t h = (addr >> 12) & 0x01;
-	uint8_t a = (addr >>  8) & 0x0F;
-	uint8_t b = (addr >>  0) & 0xFF;
-	isp_write(0x20 | (h ? 0x8 : 0));
-	isp_write(a);
-	isp_write(b);
-	return isp_write(0);
-}
-
-
-
-/** Configure all of the IO pins for the new PROM type */
-static void
-prom_setup(void)
-{
-	// Configure all of the address pins as outputs,
-	// pulled low for now
-	for (uint8_t i = 0 ; i < array_count(prom->addr_pins) ; i++)
-	{
-		uint8_t pin = prom_pin(prom->addr_pins[i]);
-		if (pin == 0)
-			continue;
-		out(pin, 0);
-		ddr(pin, 1);
-	}
-
-	// Configure all of the data pins as inputs,
-	// no pull ups enabled.
-	for (uint8_t i = 0 ; i < array_count(prom->data_pins) ; i++)
-	{
-		uint8_t pin = prom_pin(prom->data_pins[i]);
-		if (pin == 0)
-			continue;
-		out(pin, 0);
-		ddr(pin, 0);
-	}
-
-	// Configure all of the hi and low pins as outputs.
-	// Do the low pins first to bring them to ground potential,
-	// then the high pins.
-	for (uint8_t i = 0 ; i < array_count(prom->lo_pins) ; i++)
-	{
-		uint8_t pin = prom_pin(prom->lo_pins[i]);
-		if (pin == 0)
-			continue;
-		out(pin, 0);
-		ddr(pin, 1);
-	}
-
-	for (uint8_t i = 0 ; i < array_count(prom->hi_pins) ; i++)
-	{
-		uint8_t pin = prom_pin(prom->hi_pins[i]);
-		if (pin == 0)
-			continue;
-		out(pin, 1);
-		ddr(pin, 1);
-	}
-
-
-	// Let things stabilize for a little while
-	_delay_ms(250);
-
-	// If this is an AVR ISP chip, try to go into programming mode
-	if (prom->data_width == 0)
-		isp_setup();
-}
-
-
-/** Switch all of the ZIF pins back to tri-state to make it safe.
- * Doesn't matter what PROM is inserted.
- */
-static void
-prom_tristate(void)
-{
-	for (uint8_t i = 1 ; i <= ZIF_PINS ; i++)
-	{
-		ddr(ports[i], 0);
-		out(ports[i], 0);
-	}
-}
-
-
-/** Select a 32-bit address for the current PROM */
-static void
-prom_set_address(
-	uint32_t addr
-)
-{
-	for (uint8_t i = 0 ; i < prom->addr_width ; i++)
-	{
-		out(prom_pin(prom->addr_pins[i]), addr & 1);
-		addr >>= 1;
-	}
-}
-
-
-static uint8_t
-_prom_read(void)
-{
-	uint8_t b = 0;
-	for (uint8_t i = 0 ; i < prom->data_width  ; i++)
-	{
-		uint8_t bit = in(prom_pin(prom->data_pins[i])) ? 0x80 : 0;
-		b = (b >> 1) | bit;
-	}
-
-	return b;
-}
-
-
-/** Read a byte from the PROM at the specified address..
- * \todo Update this to handle wider than 8-bit PROM chips.
- */
-static uint8_t
-prom_read(
-	uint32_t addr
-)
-{
-	if (prom->data_width == 0)
-		return isp_read(addr);
-
-	prom_set_address(addr);
-	for(uint8_t i = 0 ; i < 255; i++)
-	{
-		asm("nop");
-		asm("nop");
-		asm("nop");
-		asm("nop");
-	}
-
-	uint8_t old_r = _prom_read();
-
-	// Try reading a few times to be sure,
-	// or until the values converge
-	for (uint8_t i = 0 ; i < 8 ; i++)
-	{
-		uint8_t r = _prom_read();
-		if (r == old_r)
-			break;
-		old_r = r;
-	}
-
-	return old_r;
-}
-
-
-static uint8_t
-usb_serial_getchar_echo(void)
-{
-	while (1)
-	{
-		while (usb_serial_available() == 0)
-			continue;
-
-		uint16_t c = usb_serial_getchar();
-		if (c == -1)
-			continue;
-		usb_serial_putchar(c);
-		return c;
-	}
-}
-
-static uint8_t
-hexdigit_parse(
-	uint8_t c
-)
-{
-	if ('0' <= c && c <= '9')
-		return c - '0';
-	if ('A' <= c && c <= 'F')
-		return c - 'A' + 0xA;
-	if ('a' <= c && c <= 'f')
-		return c - 'a' + 0xA;
-	return 0xFF;
-}
-
-static void
-hex32(
-	uint8_t * buf,
-	uint32_t addr
-)
-{
-	buf[7] = hexdigit(addr & 0xF); addr >>= 4;
-	buf[6] = hexdigit(addr & 0xF); addr >>= 4;
-	buf[5] = hexdigit(addr & 0xF); addr >>= 4;
-	buf[4] = hexdigit(addr & 0xF); addr >>= 4;
-	buf[3] = hexdigit(addr & 0xF); addr >>= 4;
-	buf[2] = hexdigit(addr & 0xF); addr >>= 4;
-	buf[1] = hexdigit(addr & 0xF); addr >>= 4;
-	buf[0] = hexdigit(addr & 0xF); addr >>= 4;
-}
-
-
-static void
-hexdump(
-	uint32_t addr
-)
-{
-	uint8_t buf[80];
-	hex32(buf, addr);
-
-	for (int i = 0 ; i < 16 ; i++)
-	{
-		uint8_t w = prom_read(addr++);
-		uint8_t x = 8 + i * 3;
-		buf[x+0] = ' ';
-		buf[x+1] = hexdigit(w >> 4);
-		buf[x+2] = hexdigit(w >> 0);
-
-		buf[8 + 16*3 + i + 2] = printable(w) ? w : '.';
-	}
-
-	buf[8 + 16 * 3 + 0] = ' ';
-	buf[8 + 16 * 3 + 1] = ' ';
-	buf[8 + 16 * 3 + 18] = '\r';
-	buf[8 + 16 * 3 + 19] = '\n';
-
-	usb_serial_write(buf, 8 + 16 * 3 + 20);
-}
-
-
-/** Read an address from the serial port, then read that from the PROM */
-static void
-read_addr(void)
-{
-	uint32_t addr = 0;
-	while (1)
-	{
-		uint8_t c = usb_serial_getchar_echo();
-		if (c == '\r')
-			break;
-		if (c == '\n')
-			continue;
-		uint8_t n = hexdigit_parse(c);
-		if (n == 0xFF)
-			goto error;
-
-		addr = (addr << 4) | n;
-	}
-
-	send_str(PSTR("\r\n"));
-
-	prom_setup();
-
-	for (uint8_t line = 0 ; line < 4 ; line++)
-	{
-		hexdump(addr);
-		addr += 16;
-	}
-	return;
-
-error:
-	send_str(PSTR("?\r\n"));
-}
-
-
-/** Send a single prom name to the serial port */
-static void
-prom_list_send(
-	int mode,
-	const prom_t * const prom,
-	int selected
-)
-{
-	uint8_t buf[32];
-
-	uint8_t off = 0;
-	if (selected)
-	{
-		buf[off++] = '*';
-		buf[off++] = '*';
-		buf[off++] = '*';
-		buf[off++] = ' ';
-	}
-
-	buf[off++] = hexdigit(mode);
-	buf[off++] = ' ';
-	memcpy(buf+off, prom->name, sizeof(prom->name));
-	off += sizeof(prom->name);
-	buf[off++] = '\r';
-	buf[off++] = '\n';
-
-	usb_serial_write(buf, off);
-}
-
-
-/** List all of the PROM models supported */
-static void
-prom_list(void)
-{
-	send_str(PSTR("\r\n"));
-	for (int i = 0 ; i < array_count(proms) ; i++)
-	{
-		const prom_t * const p = &proms[i];
-		prom_list_send(i, p, p == prom );
-	}
-}
-
-
-static void
-prom_mode(void)
-{
-	uint8_t c = usb_serial_getchar_echo();
-	send_str(PSTR("\r\n"));
-	if (c < '0' || '9' < c)
-	{
-		send_str(PSTR("?\r\n"));
-		return;
-	}
-
-	uint8_t mode = c - '0';
-	if (mode >= array_count(proms))
-	{
-		send_str(PSTR("?\r\n"));
-		return;
-	}
-
-	prom = &proms[mode];
-
-	prom_list_send(mode, prom, 1);
-}
-
-
-static xmodem_block_t xmodem_block;
-
-/** Send the entire PROM memory via xmodem */
-static void
-prom_send(void)
-{
-	if (xmodem_init(&xmodem_block) < 0)
-		return;
-
-	// Ending address
-	const uint32_t end_addr = (((uint32_t) 1) << prom->addr_width) - 1;
-
-	// Bring the pins up to level
-	prom_setup();
-
-	// Start sending!
-	uint32_t addr = 0;
-	while (1)
-	{
-		for (uint8_t off = 0 ; off < sizeof(xmodem_block.data) ; off++)
-			xmodem_block.data[off] = prom_read(addr++);
-
-		if (xmodem_send(&xmodem_block) < 0)
-			return;
-
-		// If we have wrapped the address, we are done
-		if (addr >= end_addr)
-			break;
-	}
-
-	xmodem_fini(&xmodem_block);
-}
-
-
-
-
-int main(void)
-{
-	// set for 16 MHz clock
-#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
-	CPU_PRESCALE(0);
-
-	// Disable the ADC
-	ADMUX = 0;
-
-	// initialize the USB, and then wait for the host
-	// to set configuration.  If the Teensy is powered
-	// without a PC connected to the USB port, this 
-	// will wait forever.
-	usb_init();
-	while (!usb_configured()) /* wait */ ;
-	_delay_ms(1000);
-
-	// wait for the user to run their terminal emulator program
-	// which sets DTR to indicate it is ready to receive.
-	while (!(usb_serial_get_control() & USB_SERIAL_DTR))
-		continue;
-
-
-	// discard anything that was received prior.  Sometimes the
-	// operating system or other software will send a modem
-	// "AT command", which can still be buffered.
-	usb_serial_flush_input();
-
-
-#if 0
-	uint16_t addr = 0;
-	char line[64];
-	uint8_t off = 0;
-
-	send_str(PSTR("Looking for strings\r\n"));
-
-	while (1)
-	{
-		addr++;
-		if (addr == 0)
-			send_str(PSTR("wrap\r\n"));
-
-		uint8_t byte = read_byte(addr);
-		if (byte == 0)
-			continue;
-
-		if (off == 0)
-		{
-			line[off++] = hexdigit(addr >> 12);
-			line[off++] = hexdigit(addr >>  8);
-			line[off++] = hexdigit(addr >>  4);
-			line[off++] = hexdigit(addr >>  0);
-			line[off++] = '=';
-		}
-
-		if (printable(byte))
-		{
-			line[off++] = byte;
-			if (off < sizeof(line) - 2)
-				continue;
-		} else {
-			line[off++] = hexdigit(byte >> 4);
-			line[off++] = hexdigit(byte >> 0);
-		}
-
-		line[off++] = '\r';
-		line[off++] = '\n';
-		usb_serial_write(line, off);
-		off = 0;
-	}
-#else
-	while (1)
-	{
-		// always put the PROM into tristate so that it is safe
-		// to swap the chips in between readings, and 
-		prom_tristate();
-
-		send_str(PSTR("> "));
-		char c = usb_serial_getchar_echo();
-		switch (c)
-		{
-		case XMODEM_NAK: prom_send(); break;
-		case 'r': read_addr(); break;
-		case 'l': prom_list(); break;
-		case 'm': prom_mode(); break;
-		case 'i': isp_read(0); break;
-		case '\n': break;
-		case '\r': break;
-		default:
-			send_str(PSTR("\r\n"
-"r000000 Read a hex word from address\r\n"
-"l       List chip modes\r\n"
-"mN      Select chip N\r\n"
-			));
-			break;
-		}
-	}
-#endif
-}
-
-
-// Send a string to the USB serial port.  The string must be in
-// flash memory, using PSTR
-//
-void send_str(const char *s)
-{
-	char c;
-	while (1) {
-		c = pgm_read_byte(s++);
-		if (!c) break;
-		usb_serial_putchar(c);
-	}
-}

unpackbits.py

-#!/usr/bin/python
-import sys
-
-skip = int(sys.argv[1])
-count = int(sys.argv[2])
-sys.stdin.read(skip)
-
-offset = skip
-
-# Look for the first end of scan line?
-started = 1
-debug = 0
-
-while True:
-    r = sys.stdin.read(1)
-    offset += 1
-    if not r:
-        break
-    n = ord(r[0])
-    if n < 128:
-	count = n + 1
-	if debug:
-		sys.stderr.write(str(offset) + ": COPY "+str(count)+"\n")
-	for i in range(count):
-		c = sys.stdin.read(1)
-		if debug:
-			sys.stderr.write(str(offset) + ": --- " + hex(ord(c)) + "\n")
-		offset += 1
-		if started:
-			sys.stdout.write(c)
-    elif n == 128:
-	if debug:
-		sys.stderr.write(str(offset) + ": SKIP\n")
-        pass
-    elif n < 256:
-        count = (256-n) + 1
-        r = sys.stdin.read(1)
-	offset += 1
-	if debug:
-		sys.stderr.write(str(offset) + ": RPT "+str(count)+": " + hex(ord(r)) + "\n")
-	if started:
-		for i in range(count):
-			sys.stdout.write(r)
-	if not started and ord(r) == 0x00 and count == 8:
-		started = 1
-		sys.stderr.write(str(offset) + ": First scanline started\n")
-    else:
-        sys.stderr.write("ERROR- VAL OUT OF RANGE\n")
-

xmodem.c

-/**
- * \file xmodem protocol
- *
- * Using USB serial
- */
-
-#include <avr/io.h>
-#include <avr/pgmspace.h>
-#include <avr/interrupt.h>
-#include <stdint.h>
-#include <string.h>
-#include <util/delay.h>
-#include "usb_serial.h"
-#include "xmodem.h"
-
-
-
-/** Send a block.
- * Compute the checksum and complement.
- *
- * \return 0 if all is ok, -1 if a cancel is requested or more
- * than 10 retries occur.
- */
-int
-xmodem_send(
-	xmodem_block_t * const block
-)
-{
-	// Compute the checksum and complement
-	uint8_t cksum = 0;
-	for (uint8_t i = 0 ; i < sizeof(block->data) ; i++)
-		cksum += block->data[i];
-
-	block->cksum = cksum;
-	block->block_num++;
-	block->block_num_complement = 0xFF - block->block_num;
-
-	// Send the block, and wait for an ACK
-	uint8_t retry_count = 0;
-
-	while (retry_count++ < 10)
-	{
-		usb_serial_write((void*) block, sizeof(*block));
-
-		// Wait for an ACK (done), CAN (abort) or NAK (retry)
-		while (1)
-		{
-			uint8_t c = usb_serial_getchar();
-			if (c == XMODEM_ACK)
-				return 0;
-			if (c == XMODEM_CAN)
-				return -1;
-			if (c == XMODEM_NAK)
-				break;
-		}
-	}
-
-	// Failure or cancel
-	return -1;
-}
-
-
-int
-xmodem_init(
-	xmodem_block_t * const block
-)
-{
-	block->soh = 0x01;
-	block->block_num = 0x00;
-
-	// wait for initial nak
-	while (1)
-	{
-		uint8_t c = usb_serial_getchar();
-		if (c == XMODEM_NAK)
-			return 0;
-		if (c == XMODEM_CAN)
-			return -1;
-	}
-}
-
-
-int
-xmodem_fini(
-	xmodem_block_t * const block
-)
-{
-#if 0
-/* Don't send EOF?  rx adds it to the file? */
-	block->block_num++;
-	memset(block->data, XMODEM_EOF, sizeof(block->data));
-	if (xmodem_send_block(block) < 0)
-		return;
-#endif
-
-	// File transmission complete.  send an EOT
-	// wait for an ACK or CAN
-	while (1)
-	{
-		usb_serial_putchar(XMODEM_EOT);
-
-		while (1)
-		{
-			uint16_t c = usb_serial_getchar();
-			if (c == -1)
-				continue;
-			if (c == XMODEM_ACK)
-				return 0;
-			if (c == XMODEM_CAN)
-				return -1;
-		}
-	}
-}

xmodem.h

-/** \file
- * xmodem file transfer protocol.
- */
-#ifndef _xmodem_h_
-#define _xmodem_h_
-
-#include <avr/io.h>
-#include <stdint.h>
-
-
-typedef struct
-{
-	uint8_t soh;
-	uint8_t block_num;
-	uint8_t block_num_complement;
-	uint8_t data[128];
-	uint8_t cksum;
-} __attribute__((__packed__))
-xmodem_block_t;
-
-#define XMODEM_SOH 0x01
-#define XMODEM_EOT 0x04
-#define XMODEM_ACK 0x06
-#define XMODEM_CAN 0x18
-#define XMODEM_C 0x43
-#define XMODEM_NAK 0x15
-#define XMODEM_EOF 0x1a
-
-
-int
-xmodem_init(
-	xmodem_block_t * const block
-);
-
-
-int
-xmodem_send(
-	xmodem_block_t * const block
-);
-
-
-int xmodem_fini(
-	xmodem_block_t * const block
-);
-
-
-#endif
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.