changeset 0:6dfcd8e5b8df v0.5

first release
author Frank Kingswood <frank@kingswood-consulting.co.uk>
date Tue, 25 Mar 2014 20:31:00 +0000
parents
children acfcaa160634
files .hgignore .hgtags Makefile avr32u4.h box commands.cc formatting.h gpib.cc gpib.h hardcopy main.cc program serial.cc serial.h usb_serial.c usb_serial.h
diffstat 16 files changed, 3916 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Tue Mar 25 20:31:00 2014 +0000
     1.3 @@ -0,0 +1,4 @@
     1.4 +syntax:glob
     1.5 +o/
     1.6 +*.avr
     1.7 +*.hex
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/.hgtags	Tue Mar 25 20:31:00 2014 +0000
     2.3 @@ -0,0 +1,3 @@
     2.4 +4bd0972616a38d9c7f1a7b55f17cdf19b2bb78c5 works
     2.5 +298ca4809d22222143b9f17c4d592c157050ea2e v0.0
     2.6 +ab020ba21ec04efebdad1d0ec93088331547fc3c v0.1
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/Makefile	Tue Mar 25 20:31:00 2014 +0000
     3.3 @@ -0,0 +1,123 @@
     3.4 +
     3.5 +# export PATH:=/usr/local/avr/bin:$(PATH)
     3.6 +# export LIBRARY_PATH:=/usr/local/avr/lib
     3.7 +
     3.8 +CPU:=atmega32u4
     3.9 +
    3.10 +CFLAGS:=-mmcu=$(CPU) -mtiny-stack -O3 -Os -DCPU=$(CPU) -DF_CPU=16 \
    3.11 +         -Werror -foptimize-sibling-calls -fpeephole -fpeephole2  \
    3.12 +         --param max-unrolled-insns=3 --param max-unroll-times=3  \
    3.13 +         --param inline-unit-growth=1 -fno-tree-scev-cprop -fsplit-wide-types
    3.14 +
    3.15 +# http://www.tty1.net/blog/2008/avr-gcc-optimisations_en.html
    3.16 +LDFLAGS:=$(CFLAGS) -Wl,--relax
    3.17 +
    3.18 +ifneq "$(LIST)" ""
    3.19 +   _LIST=-g -Wa,-ahlmns
    3.20 +endif
    3.21 +
    3.22 +V:=0
    3.23 +ifeq "$(V)" "0"
    3.24 +   .SILENT:
    3.25 +   DASHQ:=-q
    3.26 +else
    3.27 +   DASHV:=-v
    3.28 +endif
    3.29 +
    3.30 +all:            main.hex main.avr
    3.31 +
    3.32 +# --------------------------------------------------------------------------
    3.33 +
    3.34 +o:
    3.35 +		mkdir -p o
    3.36 +
    3.37 +o/%.o:%.S | o#
    3.38 +		@echo gcc $^
    3.39 +		avr-gcc -c $(CFLAGS) -o $@ $^ $(_LIST)
    3.40 +
    3.41 +o/%.o:%.c | o
    3.42 +		@echo gcc $^
    3.43 +		avr-gcc -c $(CFLAGS) -std=c99 -o $@ $^ $(_LIST)
    3.44 +
    3.45 +o/%.o:%.cc | o
    3.46 +		@echo g++ $^
    3.47 +		avr-g++ -c $(CFLAGS) -o $@ $^
    3.48 +
    3.49 +#%.avr:%.o
    3.50 +#		avr-gcc -L/usr/local/avr/lib $(CFLAGS) -o $@ $^ -v
    3.51 +#		@chmod -x $@
    3.52 +
    3.53 +# Convert to hex with objcopy. We can NOT use ld --oformat here.
    3.54 +%.hex:%.avr
    3.55 +		@echo objcopy $@
    3.56 +		avr-objcopy -j .text -j .data -O ihex $^ $@
    3.57 +		chmod -x $@
    3.58 +
    3.59 +# --------------------------------------------------------------------------
    3.60 +
    3.61 +# need something to pick up latest tag
    3.62 +# echo '"'$$(hg tags | sort | awk '/^v[0-9\.]+/||1 { V=$$1 } END { if(V!="") print " " V}')'"'
    3.63 +
    3.64 +version.h:      Makefile $(filter-out version.h,$(wildcard *.cc *.h))
    3.65 +	ID=$$(hg id -i) ; \
    3.66 +	TAG=$$(hg tags | sort | awk '/^v[0-9\.]+/ { V=$$1 } END { if(V!="") print " " V}') ; \
    3.67 +	REV=$$(hg id -r $${TAG:-0}) ; \
    3.68 +	if [ "$$ID" != "$$REV" ] ; then \
    3.69 +	   [ -n "$$TAG" ] && echo '"'$$TAG' "' ; \
    3.70 +	   echo '"'$$ID'"' ; \
    3.71 +	fi  >$@
    3.72 +
    3.73 +o/commands.o:   commands.cc version.h | o
    3.74 +		@echo g++ $^
    3.75 +		avr-g++ -c $(CFLAGS) -o $@ $<
    3.76 +
    3.77 +main.avr:       o/main.o o/commands.o o/gpib.o o/serial.o o/usb_serial.o
    3.78 +		@echo ld $^
    3.79 +		avr-g++ -L/usr/local/avr/lib $(LDFLAGS) -o $@ $^ $(DASHV)
    3.80 +		chmod -x $@
    3.81 +		avr-size $@
    3.82 +CLEAN+=main.avr version.h
    3.83 +
    3.84 +# --------------------------------------------------------------------------
    3.85 +
    3.86 +.PHONY: disas fuses program term setspeed clean rebuild
    3.87 +disas:          main.avr
    3.88 +		avr-objdump -z -d $^ | avr-c++filt
    3.89 +
    3.90 +LFUSE=0x62      # clkout=of sut=2 clksel=2 (rc)
    3.91 +LFUSE=0xb2      # clkout=on sut=3 clksel=2 (rc)
    3.92 +#HFUSE=0xc4      # extreset=off, debugwire=off, spi=off, wdt=on, eesave=on, bod=4=4.5V
    3.93 +# NEVER program HFUSE bit 7=0 or bit 5=1, because SPI can no longer be used
    3.94 +# HFUSE values should be 0b1X0XXXXX, or 0x8X, 0x9X, 0xCX, 0xDX
    3.95 +HFUSE=0xdf      # extreset=off, debugwire=off, spi=off, wdt=off, eesave=on, bod=7
    3.96 +EFUSE=0xff      # self-programming=on
    3.97 +
    3.98 +fuses:
    3.99 +		false Dangerous
   3.100 +		avrdude -p t$(CPU) -u -U efuse:w:$$(($(EFUSE))):m -U hfuse:w:$$(($(HFUSE))):m -U lfuse:w:$$(($(LFUSE))):m
   3.101 +
   3.102 +program:        main.hex
   3.103 +ifeq "$(CPU)" "atmega32u4"
   3.104 +		./program --program $(CPU) $^
   3.105 +else
   3.106 +		if lsusb -d 03eb:2104 ; then \
   3.107 +			avrdude -c avrispmkII -p m32u4 $(DASHQ) -U flash:w:$^ ; \
   3.108 +		elif lsusb -d  16c0:05dc ; then \
   3.109 +			avrdude -c usbasp-clone -p $(CPU) $(DASHQ) -U flash:w:$^ ;\
   3.110 +		fi
   3.111 +endif
   3.112 +
   3.113 +term:
   3.114 +		avrdude -p t$(CPU) -v -E noreset -t
   3.115 +
   3.116 +setspeed:
   3.117 +		avrdude -p t$(CPU) -v -E noreset -B300
   3.118 +
   3.119 +clean:
   3.120 +		-rm -r o
   3.121 +		-rm $(CLEAN)
   3.122 +
   3.123 +rebuild:
   3.124 +		$(MAKE) clean ; $(MAKE)
   3.125 +
   3.126 +# ----- EOF Makefile -----
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/avr32u4.h	Tue Mar 25 20:31:00 2014 +0000
     4.3 @@ -0,0 +1,83 @@
     4.4 +
     4.5 +// Teensy 2.0 has two complete 8-bit ports PB and PD
     4.6 +// Arduino Leonardo and "Pro Micro" have 15 out of 16, good try!
     4.7 +// 20 mA/pin, 100 mA max for 8-bit port
     4.8 +//
     4.9 +// 32U4       Arduino  GPIB      32U4       Arduino  GPIB
    4.10 +// ---------- -----    ----      ---------- -----    ----
    4.11 +// PB0 (SS)   -      : DIO1      PD0 (INT0) "d3"   : EOI
    4.12 +// PB1 (SCLK) "sck"  : DIO2      PD1 (INT1) "d2"   : NRFD
    4.13 +// PB2 (MOSI) "mosi" : DIO3      PD2 (INT2) "rxi"  : NDAC
    4.14 +// PB3 (MISO) "miso" : DIO4      PD3 (INT3) "txo"  : SRQ
    4.15 +// PB4        "d8"   : DIO5      PD4        "d4"     (pull down for arduino)
    4.16 +// PB5        "d9"   : DIO6      PD5        (LED)    (debug serial)
    4.17 +// PB6        "d10"  : DIO7      PD6 (LED)  -        -
    4.18 +// PB7        -      : DIO8      PD7        "d6"   : DAV
    4.19 +//
    4.20 +// Other pins
    4.21 +//
    4.22 +// 32U4       Arduino  GPIB      32U4       Arduino  GPIB
    4.23 +// ---------- -----    ----      ---------- -----    ----
    4.24 +// PF0 (ADC0) -        -         PC6        "d5"     DIO8
    4.25 +// PF1 (ADC1) -        -         PC7        -
    4.26 +// PF4 (ADC4) "a3"   : ATN       PE6        "d7"     DIO1
    4.27 +// PF5 (ADC5) "a2"   : IFC
    4.28 +// PF6 (ADC6) "a1"   : REN
    4.29 +// PF7 (ADC7) "a0"   : 
    4.30 +//
    4.31 +// Teensy has LED on PD6 to GND (shared)
    4.32 +// Arduino has LED on PD5 to VCC
    4.33 +//             and on PB0 to VCC (shared with DIO1)
    4.34 +
    4.35 +
    4.36 +/* -------------------------------------------------------------------------- */
    4.37 +
    4.38 +
    4.39 +// GPIB Connector
    4.40 +//
    4.41 +// Pin  Name    Signal Description          Pin  Name    Signal Description
    4.42 +// ---  ------  -------------------------   ---  ------  -------------------------
    4.43 +// 1    DIO1    Data Input/Output Bit 1     13   DIO5    Data Input/Output Bit 5
    4.44 +// 2    DIO2    Data Input/Output Bit 2     14   DIO6    Data Input/Output Bit 6
    4.45 +// 3    DIO3    Data Input/Output Bit 3     15   DIO7    Data Input/Output Bit 7
    4.46 +// 4    DIO4    Data Input/Output Bit 4     16   DIO8    Data Input/Output Bit 8
    4.47 +// 5    EIO     End-Or-Identify             17   REN     Remote Enable
    4.48 +// 6    DAV     Data Valid                  18   GND     Ground DAV
    4.49 +// 7    NRFD    Not Ready For Data          19   GND     Ground NRFD
    4.50 +// 8    NDAC    Not Data Accepted           20   GND     Ground NDAC
    4.51 +// 9    IFC     Interface Clear             21   GND     Ground IFC
    4.52 +// 10   SRQ     Service Request             22   GND     Ground SRQ
    4.53 +// 11   ATN     Attention                   23   GND     Ground ATN
    4.54 +// 12   Shield  Chassis Ground              24   GND     Ground DIO, REN, EOI
    4.55 +//
    4.56 +// DAV can be used to enable 74ABT541 output buffer (sinks 64 mA)
    4.57 +// Use 100R between A and B port.
    4.58 +//
    4.59 +//             +---+--+---+
    4.60 +// BUFEN = GAB |1  +--+ 20| VCC
    4.61 +//          A1 |2       19| /GBA = VCC
    4.62 +//          A2 |3       18| B1
    4.63 +//          A3 |4       17| B2
    4.64 +//   AVR    A4 |5  74   16| B3
    4.65 +//   PB     A5 |6  623  15| B4   GPIB
    4.66 +//          A6 |7       14| B5   BUS
    4.67 +//          A7 |8       13| B6
    4.68 +//          A8 |9       12| B7
    4.69 +//         GND |10      11| B8
    4.70 +//             +----------+
    4.71 +//
    4.72 +// Handshake  Output
    4.73 +// ---------  ---------
    4.74 +//   NRFD     Listener
    4.75 +//   NDAC     Listener
    4.76 +//   DAV      Talker
    4.77 +//
    4.78 +// Control    Output
    4.79 +// ---------  ---------
    4.80 +//   ATN      Controller
    4.81 +//   IFC      Controller
    4.82 +//   REN      Controller
    4.83 +//   SRQ      Any
    4.84 +//   EOI      Talker and Controller
    4.85 +//
    4.86 +// Parallel poll ATN & EIO asserted -> must respond within 200ns
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/box	Tue Mar 25 20:31:00 2014 +0000
     5.3 @@ -0,0 +1,71 @@
     5.4 +GPIB connector opening 34.1x14.4 mm with 2mm rounded off corners
     5.5 +
     5.6 +
     5.7 +
     5.8 +Teensy 2.0
     5.9 +==========
    5.10 +
    5.11 +View from back of plug
    5.12 +----------------------
    5.13 +
    5.14 +              a10        a9   a8        a7  a5   a4   a3   a2
    5.15 +          b4        b5            b11
    5.16 +         PF4  PD3  PF5  PD2  PD1  PD7  PD0  PB3  PB2  PB1  PB0
    5.17 + ------ ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
    5.18 +|Shield  ATN  SRQ  IFC NDAC NRFD  DAV  EIO  D4   D3   D2   D1 |
    5.19 +|   12   11   10    9    8    7    6    5    4    3    2    1 |
    5.20 +|                                                             |
    5.21 +|   24   23   22   21   20   19   18   17   16   15   14   13 |
    5.22 +|   GND  GND  GND  GND  GND  GND  GND  REN  D8   D7   D6   D5 |
    5.23 + ------ ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
    5.24 +                   GND                 PF6  PB7  PB6  PB5  PB4
    5.25 +                    a1                      a6
    5.26 +                                        b6        b8   b9  b10
    5.27 +
    5.28 +
    5.29 +
    5.30 +Shield 10nF//1M to USB shield
    5.31 +"Micro-Pro" arduino
    5.32 +===================
    5.33 +
    5.34 +View from back of plug
    5.35 +----------------------
    5.36 +
    5.37 + Shield  6.5  7.12 6.6  7.11 7.8  7.4  7.7  6.10 6.11 6.9  7.3
    5.38 +   10nF  a3   txo  a2   rxi  d2   d6   d3   miso mosi sck  d7
    5.39 +   //1M  PF4  PD3  PF5  PD2  PD1  PD7  PD0  PB3  PB2  PB1  PE6
    5.40 + ------ ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
    5.41 +|Shield  ATN  SRQ  IFC NDAC NRFD  DAV  EIO  D4   D3   D2   D1 |
    5.42 +|   12   11   10    9    8    7    6    5    4    3    2    1 |
    5.43 +|                                                             |
    5.44 +|   24   23   22   21   20   19   18   17   16   15   14   13 |
    5.45 +|   GND  GND  GND  GND  GND  GND  GND  REN  D8   D7   D6   D5 |
    5.46 + ------ ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
    5.47 +                   GND                 PF6  PC6  PB6  PB5  PB4
    5.48 +                                       a1   d5   d10  d9   d8
    5.49 +                                       6.7  7.5  6.12 7.1  7.2
    5.50 +
    5.51 +
    5.52 +
    5.53 +// 32U4       Arduino  GPIB      32U4       Arduino  GPIB
    5.54 +// ---------- -----    ----      ---------- -----    ----
    5.55 +// PB0 (SS)   -      : DIO1      PD0 (INT0) "d3"   : EOI
    5.56 +// PB1 (SCLK) "sck"  : DIO2      PD1 (INT1) "d2"   : NRFD
    5.57 +// PB2 (MOSI) "mosi" : DIO3      PD2 (INT2) "rxi"  : NDAC
    5.58 +// PB3 (MISO) "miso" : DIO4      PD3 (INT3) "txo"  : SRQ
    5.59 +// PB4        "d8"   : DIO5      PD4        "d4"     (pull down for arduino)
    5.60 +// PB5        "d9"   : DIO6      PD5        (LED)    (debug serial)
    5.61 +// PB6        "d10"  : DIO7      PD6 (LED)  -        -
    5.62 +// PB7        -      : DIO8      PD7        "d6"   : DAV
    5.63 +//
    5.64 +// Other pins
    5.65 +//
    5.66 +// 32U4       Arduino  GPIB      32U4       Arduino  GPIB
    5.67 +// ---------- -----    ----      ---------- -----    ----
    5.68 +// PF0 (ADC0) -        -         PC6        "d5"     DIO8
    5.69 +// PF1 (ADC1) -        -         PC7        -
    5.70 +// PF4 (ADC4) "a3"   : ATN       PE6        "d7"     DIO1
    5.71 +// PF5 (ADC5) "a2"   : IFC
    5.72 +// PF6 (ADC6) "a1"   : REN
    5.73 +// PF7 (ADC7) "a0"   :
    5.74 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/commands.cc	Tue Mar 25 20:31:00 2014 +0000
     6.3 @@ -0,0 +1,1284 @@
     6.4 +/* #------------------------------------------------------------------------#
     6.5 +   |                                                                        |
     6.6 +   |   commands.cc                                                          |
     6.7 +   |                                                                        |
     6.8 +   |   USB-GPIB command processing                                          |
     6.9 +   |                                                                        |
    6.10 +   |   Copyright 2014, Frank A. Kingswood, www.kingswood-consulting.co.uk   |
    6.11 +   |                                                                        |
    6.12 +   #------------------------------------------------------------------------# */
    6.13 +
    6.14 +#include <avr/io.h>
    6.15 +#include <avr/pgmspace.h>
    6.16 +#include <stdint.h>
    6.17 +#include <ctype.h>
    6.18 +#include <util/delay.h>
    6.19 +#include <avr/interrupt.h>
    6.20 +#include "usb_serial.h"
    6.21 +#include "serial.h"
    6.22 +#include "gpib.h"
    6.23 +
    6.24 +static const int16_t NONE=0x8000;
    6.25 +static const int16_t EINVCHAR=-1;
    6.26 +static const int16_t EBUFFER=-2;
    6.27 +static const int16_t ETOOMANY=-3;
    6.28 +static const int16_t ESYNTAX=-4;
    6.29 +static const int16_t ERANGE=-5;
    6.30 +static const int16_t EVALUE=-6;
    6.31 +static const int16_t EUNDERFLOW=-7;
    6.32 +static const int16_t ETIMEOUT=-8;
    6.33 +static const int16_t ECOMMAND=-100;
    6.34 +
    6.35 +/* -------------------------------------------------------------------------- */
    6.36 +
    6.37 +#define ROM_PTR /* PROGMEN as a modifier to a pointer */
    6.38 +#define STR2(a) #a
    6.39 +#define STR(a) STR2(a)
    6.40 +#define STRING(s) PROGMEM static const char String_##s[]=STR(s)
    6.41 +
    6.42 +typedef int16_t (*Method)(char *);
    6.43 +struct Commands
    6.44 +{
    6.45 +   const char *Command;
    6.46 +   Method Function;
    6.47 +} __attribute__((__progmem__));
    6.48 +const ROM_PTR struct Commands *FindCommand(const ROM_PTR struct Commands *table,
    6.49 +                                           const char *command);
    6.50 +
    6.51 +extern const struct Commands commandTable[];
    6.52 +
    6.53 +char *skipws(char *ptr)
    6.54 +{
    6.55 +   while(isspace(*ptr))
    6.56 +      ptr++;
    6.57 +   return ptr;
    6.58 +}
    6.59 +
    6.60 +int16_t strtoi(const char *ptr, const char **end)
    6.61 +{
    6.62 +   int16_t value=0;
    6.63 +
    6.64 +   char c=*ptr;
    6.65 +   if(c=='0' && ptr[1]=='x')
    6.66 +   {  ptr+=2;
    6.67 +      while(isxdigit(c=*ptr))
    6.68 +      {
    6.69 +         ptr++;
    6.70 +         if(c<='9')
    6.71 +            c-='0';
    6.72 +         else
    6.73 +            c=tolower(c)-'a'+10;
    6.74 +         value=(value<<4) | c;
    6.75 +      }
    6.76 +   }
    6.77 +   else
    6.78 +   {  ptr++;
    6.79 +      value=c-'0';
    6.80 +      while(isdigit(c=*ptr))
    6.81 +      {
    6.82 +         ptr++;
    6.83 +         c-='0';
    6.84 +         value=value*10 + c;
    6.85 +      }
    6.86 +   }
    6.87 +   if(end)
    6.88 +      *end=ptr;
    6.89 +   return value;
    6.90 +}
    6.91 +
    6.92 +/* ----- command functions -------------------------------------------------- */
    6.93 +
    6.94 +/* Return codes
    6.95 + * --------------
    6.96 + * ++eoi
    6.97 + *    - message when EOI is seen when listening and not in ++rd or ++read eoi command
    6.98 + * ++srq
    6.99 + *    - message when SRQ is asserted
   6.100 + * ++error <value>
   6.101 + *    - message when an error occurs
   6.102 + *
   6.103 + *
   6.104 + * Maybe later:
   6.105 + * ++dev <pad> <sad> <tmo> <eot> <eos> -> <name>
   6.106 + *     Assign settings to user-configurable device, return identifier
   6.107 + * ++config/++ask various options
   6.108 + * ++ln [<device>] -> result
   6.109 + *     check for presence of a device on the bus
   6.110 + *     (not clear how this is done?)
   6.111 + * ++onl [<device>] <v>
   6.112 + *     Set device online/offline
   6.113 + * ++pad <device> <address>
   6.114 + *     Change device primary address
   6.115 + * ++rsc
   6.116 + *     Request/release system control
   6.117 + * ++sad <device> <address>
   6.118 + *     Change device secondary address
   6.119 + *
   6.120 + */
   6.121 +
   6.122 +
   6.123 +/* ..........................................................................
   6.124 + *
   6.125 + * ++addr <addr> [<secondary>]
   6.126 + * ++addr? -> <addr>
   6.127 + *    - set or return default device address to <device> (default 1)
   6.128 + *    - may include secondary address either as second word or MSBs in <device>
   6.129 + */
   6.130 +int16_t Command_addr(char *tail)
   6.131 +{
   6.132 +   if(*tail==0 || *tail=='?')
   6.133 +      return GPIB.DeviceAddress;
   6.134 +
   6.135 +   uint16_t addr=strtoi(tail,(const char **)&tail);
   6.136 +
   6.137 +   if(*tail)
   6.138 +   {  if((addr & 0xffe0)!=0)
   6.139 +         return EVALUE;
   6.140 +
   6.141 +      tail=skipws(tail);
   6.142 +      if(*tail)
   6.143 +      {
   6.144 +         uint16_t second=strtoi(tail,(const char **)&tail);
   6.145 +         if((second & 0xffe0)!=0)
   6.146 +            return EVALUE;
   6.147 +         addr|=(0x60 | second)<<8;
   6.148 +      }
   6.149 +   }
   6.150 +   GPIB.DeviceAddress=addr;
   6.151 +
   6.152 +   return NONE;
   6.153 +}
   6.154 +
   6.155 +/* ..........................................................................
   6.156 + *
   6.157 + * ++ATN <value>
   6.158 + * ++ATN? -> <value>
   6.159 + *
   6.160 + *    set or return ~ATN
   6.161 + */
   6.162 +int16_t Command_ATN(char *tail)
   6.163 +{
   6.164 +   int16_t i;
   6.165 +   switch(*tail)
   6.166 +   {  case 0:
   6.167 +      case '?':
   6.168 +         return GPIB.ATN();
   6.169 +      case '0':
   6.170 +      case '1':
   6.171 +         GPIB.ATN(*tail&1);
   6.172 +         return NONE;
   6.173 +   }
   6.174 +
   6.175 +   return EVALUE;
   6.176 +}
   6.177 +
   6.178 +/* ..........................................................................
   6.179 + *
   6.180 + * ++auto <state>
   6.181 + *     if state==1: automatic ++read eoi after sending a string ending in "?"
   6.182 + *     elif state==0: leave in LISTEN state
   6.183 + */
   6.184 +int16_t Command_auto(char *tail)
   6.185 +{
   6.186 +   Serial.Send(ROMS("auto ")); Serial.Send(tail); Serial.Send();
   6.187 +   return ECOMMAND;
   6.188 +}
   6.189 +
   6.190 +/* ..........................................................................
   6.191 + *
   6.192 + * ++cac <v>
   6.193 + *    if v!=1: wait for handshake to complete
   6.194 + *    Become active controller
   6.195 + */
   6.196 +int16_t Command_cac(char *tail)
   6.197 +{
   6.198 +   GPIB.ATN(false);
   6.199 +   _delay_ms(1);
   6.200 +   GPIB.EOI(false);
   6.201 +   _delay_ms(1);
   6.202 +   GPIB.NRFD(false);
   6.203 +   _delay_ms(1);
   6.204 +   GPIB.DAV(false);
   6.205 +   _delay_ms(1);
   6.206 +   GPIB.NDAC(false);
   6.207 +   _delay_ms(1);
   6.208 +
   6.209 +   if(*tail!='1')
   6.210 +   {
   6.211 +      static const uint16_t TIMEOUT=2000; // 2 seconds
   6.212 +      uint16_t timeout;
   6.213 +      for(timeout=TIMEOUT; timeout!=0; timeout--)
   6.214 +      {
   6.215 +         _delay_ms(1);
   6.216 +
   6.217 +         if(!(GPIB.ATN() || GPIB.NRFD() || GPIB.NDAC() || GPIB.DAV()))
   6.218 +            break;
   6.219 +      }
   6.220 +
   6.221 +      if(!timeout)
   6.222 +         return ETIMEOUT;
   6.223 +   }
   6.224 +
   6.225 +   GPIB.Controller();
   6.226 +   return NONE;
   6.227 +}
   6.228 +
   6.229 +
   6.230 +/* ..........................................................................
   6.231 + *
   6.232 + * ++clr [<device>]
   6.233 + *    - selected/universal device clear
   6.234 + *    - if device=="all":
   6.235 + *     ++cmd MTA UNL DCL
   6.236 + *     else:
   6.237 + *     ++cmd MTA UNL LAD SAD SDC
   6.238 + */
   6.239 +int16_t Command_clr(char *tail)
   6.240 +{
   6.241 +   Serial.Send(ROMS("clr ")); Serial.Send(tail); Serial.Send();
   6.242 +   return ECOMMAND;
   6.243 +}
   6.244 +
   6.245 +/* ..........................................................................
   6.246 + *
   6.247 + * ++cmd <bytes or codes>
   6.248 + *    - set ATN=0, send bytes, set ATN=1, set ATN=float
   6.249 + *    - for each byte, if code is preceded by "-": EOI=0
   6.250 + *     else: EOI=1
   6.251 + */
   6.252 +
   6.253 +#define BYTE(s) { String_##s, Byte_##s }
   6.254 +
   6.255 +int16_t Byte_MLA(char *)
   6.256 +{  return 0x20|(GPIB.MyAddress&31);
   6.257 +}
   6.258 +
   6.259 +int16_t Byte_MSA(char *)
   6.260 +{
   6.261 +   if((GPIB.MyAddress & 0xff00)!=0)
   6.262 +      return 0x60|((GPIB.MyAddress>>8)&31);
   6.263 +}
   6.264 +
   6.265 +int16_t Byte_MTA(char *)
   6.266 +{  return 0x40|(GPIB.MyAddress&31);
   6.267 +}
   6.268 +
   6.269 +int16_t Byte_DCL(char *)
   6.270 +{  return 0x14;
   6.271 +}
   6.272 +
   6.273 +int16_t Byte_GET(char *)
   6.274 +{  return 0x08;
   6.275 +}
   6.276 +
   6.277 +int16_t Byte_GTL(char *)
   6.278 +{  return 0x01;
   6.279 +}
   6.280 +
   6.281 +int16_t Byte_LLO(char *)
   6.282 +{  return 0x11;
   6.283 +}
   6.284 +
   6.285 +int16_t Byte_PPC(char *)
   6.286 +{  return 0x05;
   6.287 +}
   6.288 +
   6.289 +int16_t Byte_PPU(char *)
   6.290 +{  return 0x15;
   6.291 +}
   6.292 +
   6.293 +int16_t Byte_SDC(char *)
   6.294 +{  return 0x04;
   6.295 +}
   6.296 +
   6.297 +int16_t Byte_SPD(char *)
   6.298 +{  return 0x19;
   6.299 +}
   6.300 +
   6.301 +int16_t Byte_SPE(char *)
   6.302 +{  return 0x18;
   6.303 +}
   6.304 +
   6.305 +int16_t Byte_TCT(char *)
   6.306 +{  return 0x09;
   6.307 +}
   6.308 +
   6.309 +int16_t Byte_UNL(char *)
   6.310 +{  return 0x3f;
   6.311 +}
   6.312 +
   6.313 +int16_t Byte_UNT(char *)
   6.314 +{  return 0x5f;
   6.315 +}
   6.316 +
   6.317 +int16_t Byte_LAD(char *)
   6.318 +{  return 0x20|(GPIB.DeviceAddress&31);
   6.319 +}
   6.320 +
   6.321 +int16_t Byte_TAD(char *)
   6.322 +{  return 0x40|(GPIB.DeviceAddress&31);
   6.323 +}
   6.324 +
   6.325 +int16_t Byte_SAD(char *)
   6.326 +{
   6.327 +   if((GPIB.DeviceAddress & 0xff00)!=0)
   6.328 +      return 0x60|((GPIB.DeviceAddress>>8)&31);
   6.329 +   return 0;
   6.330 +}
   6.331 +
   6.332 +#undef SPE
   6.333 +STRING(DCL); STRING(GET); STRING(GTL); STRING(LAD); STRING(LLO);
   6.334 +STRING(MLA); STRING(MSA); STRING(MTA); STRING(PPC); STRING(PPU);
   6.335 +STRING(SAD); STRING(SDC); STRING(SPD); STRING(SPE); STRING(TAD);
   6.336 +STRING(TCT); STRING(UNL); STRING(UNT);
   6.337 +
   6.338 +static const struct Commands byteTable[]=
   6.339 +{
   6.340 +   BYTE(DCL), BYTE(GET), BYTE(GTL), BYTE(LAD), BYTE(LLO),
   6.341 +   BYTE(MLA), BYTE(MSA), BYTE(MTA), BYTE(PPC), BYTE(PPU),
   6.342 +   BYTE(SAD), BYTE(SDC), BYTE(SPD), BYTE(SPE), BYTE(TAD),
   6.343 +   BYTE(TCT), BYTE(UNL), BYTE(UNT),
   6.344 +   { 0,0 },
   6.345 +};
   6.346 +
   6.347 +#define Debug USB
   6.348 +
   6.349 +int16_t Command_cmd_wrt(char *tail,bool atn)
   6.350 +{
   6.351 +   GPIB.ATN(atn);
   6.352 +   uint8_t eoi=0;
   6.353 +   while(char c=*tail)
   6.354 +   {  const char *word=tail++;
   6.355 +
   6.356 +      if(c=='-')
   6.357 +      {  eoi=1;
   6.358 +         continue;
   6.359 +      }
   6.360 +
   6.361 +      uint8_t byte=0;
   6.362 +
   6.363 +      if(c=='"')
   6.364 +      {
   6.365 +         while((c=*tail)!='"' && c>=' ')
   6.366 +         {
   6.367 +            tail++;
   6.368 +
   6.369 +            GPIB.EOI(eoi && *tail=='"');
   6.370 +            byte=GPIB.Out(c);
   6.371 +            GPIB.EOI(false);
   6.372 +
   6.373 +            if(byte)
   6.374 +               goto fail;
   6.375 +         }
   6.376 +
   6.377 +         if(c!='"')
   6.378 +            goto fail;
   6.379 +
   6.380 +         tail++;
   6.381 +      }
   6.382 +      else
   6.383 +      {
   6.384 +         uint8_t skip=0;
   6.385 +
   6.386 +         if(isdigit(c))
   6.387 +         {
   6.388 +            if(c=='0' && *tail=='x')
   6.389 +            {  tail++;
   6.390 +               while(isxdigit(c=*tail))
   6.391 +               {
   6.392 +                  byte<<=4;
   6.393 +                  if(c<='9')
   6.394 +                     byte+=c-'0';
   6.395 +                  else
   6.396 +                     byte+=tolower(c)-'a'+10;
   6.397 +                  tail++;
   6.398 +               }
   6.399 +            }
   6.400 +            else
   6.401 +            {
   6.402 +               byte=c-'0';
   6.403 +               while(isdigit(c=*tail))
   6.404 +               {
   6.405 +                  byte=byte*10+c-'0';
   6.406 +                  tail++;
   6.407 +               }
   6.408 +            }
   6.409 +
   6.410 +            if(!(c==' ' || c==0))
   6.411 +               goto fail;
   6.412 +         }
   6.413 +         else
   6.414 +         {
   6.415 +            while(isalnum(*tail))
   6.416 +               tail++;
   6.417 +
   6.418 +            c=*tail;
   6.419 +            *tail=0;
   6.420 +
   6.421 +            const ROM_PTR struct Commands *cmd=FindCommand(byteTable,word);
   6.422 +
   6.423 +            if(!cmd)
   6.424 +               goto fail;
   6.425 +
   6.426 +            *tail=c;
   6.427 +            Method f=(Method)(pgm_read_word(&cmd->Function));
   6.428 +
   6.429 +            byte=f(tail);
   6.430 +
   6.431 +            // handle cases where there is nothing to send
   6.432 +            if(!byte)
   6.433 +               skip=1;
   6.434 +         }
   6.435 +
   6.436 +         if(!skip)
   6.437 +         {
   6.438 +            GPIB.EOI(eoi);
   6.439 +            byte=GPIB.Out(byte);
   6.440 +            GPIB.EOI(false);
   6.441 +            if(byte)
   6.442 +               goto fail;
   6.443 +         }
   6.444 +      }
   6.445 +
   6.446 +      tail=skipws(tail);
   6.447 +      eoi=0;
   6.448 +   }
   6.449 +
   6.450 +   // moved to rd
   6.451 +   // GPIB.ATN(false);
   6.452 +   return NONE;
   6.453 +
   6.454 +fail:
   6.455 +   GPIB.EOI(false);
   6.456 +   GPIB.ATN(false);
   6.457 +   return EINVCHAR;
   6.458 +}
   6.459 +
   6.460 +int16_t Command_cmd(char *tail)
   6.461 +{
   6.462 +   return Command_cmd_wrt(tail,true);
   6.463 +}
   6.464 +
   6.465 +/* ..........................................................................
   6.466 + *
   6.467 + *  ++data? -> <byte>
   6.468 + *     return ~DIO[8:1]
   6.469 + */
   6.470 +int16_t Command_data(char *tail)
   6.471 +{
   6.472 +   return GPIB.Data();
   6.473 +}
   6.474 +
   6.475 +/* ..........................................................................
   6.476 + *
   6.477 + * ++DAV <value>
   6.478 + * ++DAV? -> <value>
   6.479 + *
   6.480 + *    set or return ~DAV
   6.481 + */
   6.482 +int16_t Command_DAV(char *tail)
   6.483 +{
   6.484 +   switch(*tail)
   6.485 +   {  case 0:
   6.486 +      case '?':
   6.487 +         return GPIB.DAV();
   6.488 +      case '0':
   6.489 +      case '1':
   6.490 +         GPIB.DAV(*tail&1);
   6.491 +         return NONE;
   6.492 +   }
   6.493 +
   6.494 +   return EVALUE;
   6.495 +}
   6.496 +
   6.497 +/* ..........................................................................
   6.498 + *
   6.499 + * ++DEBUG <value>
   6.500 + *     do whatever we think is interesting
   6.501 + */
   6.502 +int16_t Command_DEBUG(char *tail)
   6.503 +{
   6.504 +   if(*tail)
   6.505 +   {
   6.506 +      int16_t addr=strtoi(tail,(const char **)&tail);
   6.507 +
   6.508 +      if(!*tail)
   6.509 +      {
   6.510 +         USB.Send(addr);
   6.511 +         USB.Send();
   6.512 +         USB.Flush();
   6.513 +
   6.514 +         _delay_ms(100);
   6.515 +
   6.516 +         Method f=(Method)addr;
   6.517 +         cli();
   6.518 +         UDCON = 1;
   6.519 +         USBCON = (1<<FRZCLK);  // disable USB
   6.520 +         UCSR1B = 0;
   6.521 +         EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
   6.522 +         TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
   6.523 +         DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
   6.524 +         PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
   6.525 +         _delay_ms(10);
   6.526 +
   6.527 +         f(tail);
   6.528 +         sei();
   6.529 +      }
   6.530 +   }
   6.531 +
   6.532 +   USB.Send(ROMS("ddrb="));   USB.Hex(uint8_t(DDRB));
   6.533 +   USB.Send(ROMS(" portb=")); USB.Hex(uint8_t(PORTB));
   6.534 +   USB.Send(ROMS(" pinb="));  USB.Hex(uint8_t(PINB));
   6.535 +   USB.Send();
   6.536 +
   6.537 +   USB.Send(ROMS("ddrc="));   USB.Hex(uint8_t(DDRC));
   6.538 +   USB.Send(ROMS(" portc=")); USB.Hex(uint8_t(PORTC));
   6.539 +   USB.Send(ROMS(" pinc="));  USB.Hex(uint8_t(PINC));
   6.540 +   USB.Send();
   6.541 +
   6.542 +   USB.Send(ROMS("ddrd="));   USB.Hex(uint8_t(DDRD));
   6.543 +   USB.Send(ROMS(" portd=")); USB.Hex(uint8_t(PORTD));
   6.544 +   USB.Send(ROMS(" pind="));  USB.Hex(uint8_t(PIND));
   6.545 +   USB.Send();
   6.546 +
   6.547 +   USB.Send(ROMS("ddre="));   USB.Hex(uint8_t(DDRE));
   6.548 +   USB.Send(ROMS(" porte=")); USB.Hex(uint8_t(PORTE));
   6.549 +   USB.Send(ROMS(" pine="));  USB.Hex(uint8_t(PINE));
   6.550 +   USB.Send();
   6.551 +
   6.552 +   USB.Send(ROMS("ddrf="));   USB.Hex(uint8_t(DDRF));
   6.553 +   USB.Send(ROMS(" portf=")); USB.Hex(uint8_t(PORTF));
   6.554 +   USB.Send(ROMS(" pinf="));  USB.Hex(uint8_t(PINF));
   6.555 +   USB.Send();
   6.556 +
   6.557 +   GPIB.Report();
   6.558 +   USB.Send();
   6.559 +
   6.560 +   return NONE;
   6.561 +}
   6.562 +
   6.563 +/* ..........................................................................
   6.564 + *
   6.565 + * ++EOI <value>
   6.566 + * ++EOI? -> <value>
   6.567 + *
   6.568 + *    set or return ~EOI
   6.569 + */
   6.570 +int16_t Command_EOI(char *tail)
   6.571 +{
   6.572 +   switch(*tail)
   6.573 +   {  case 0:
   6.574 +      case '?':
   6.575 +         return GPIB.EOI();
   6.576 +      case '0':
   6.577 +      case '1':
   6.578 +         GPIB.EOI(*tail&1);
   6.579 +         return NONE;
   6.580 +   }
   6.581 +
   6.582 +   return EVALUE;
   6.583 +}
   6.584 +
   6.585 +/* ..........................................................................
   6.586 + *
   6.587 + * ++eoi <mode>
   6.588 + *     if mode==0: no EOI asserted
   6.589 + *     else: assert EOI on last byte of a command (default)
   6.590 + */
   6.591 +int16_t Command_eoi(char *tail)
   6.592 +{
   6.593 +   Serial.Send(ROMS("eoi ")); Serial.Send(tail); Serial.Send();
   6.594 +   return ECOMMAND;
   6.595 +}
   6.596 +
   6.597 +/* ..........................................................................
   6.598 + *
   6.599 + * ++eos <mode>
   6.600 + *     if mode==0: append "\r\n" to commands
   6.601 + *     elif mode==1: append "\r" to commands
   6.602 + *     elif mode==2: append "\n" to commands
   6.603 + *     else: do not append anything (default)
   6.604 + * ++eos {4|8} <byte>
   6.605 + *     if arg=0,1,2,3: prologix
   6.606 + *     else:
   6.607 + *     if first arg==4 or 12: terminate reads on <byte>
   6.608 + *     if first arg==8 or 12: set EOI when writing <byte>
   6.609 + */
   6.610 +int16_t Command_eos(char *tail)
   6.611 +{
   6.612 +   Serial.Send(ROMS("eos ")); Serial.Send(tail); Serial.Send();
   6.613 +   return ECOMMAND;
   6.614 +}
   6.615 +
   6.616 +/* ..........................................................................
   6.617 + *
   6.618 + * ++eot_char <byte>
   6.619 + *     set eot_char
   6.620 + */
   6.621 +int16_t Command_eot_char(char *tail)
   6.622 +{
   6.623 +   Serial.Send(ROMS("eot_char ")); Serial.Send(tail); Serial.Send();
   6.624 +   return ECOMMAND;
   6.625 +}
   6.626 +
   6.627 +/* ..........................................................................
   6.628 + *
   6.629 + * ++eot_enable <eot>
   6.630 + *     control how EOI when receiving data is handled
   6.631 + *     if eot==0: ignore
   6.632 + *     elif eot==1: send <eot_char>
   6.633 + *     else: send ++eoi (default)
   6.634 + */
   6.635 +int16_t Command_eot_enable(char *tail)
   6.636 +{
   6.637 +   Serial.Send(ROMS("eot_enable ")); Serial.Send(tail); Serial.Send();
   6.638 +   return ECOMMAND;
   6.639 +}
   6.640 +
   6.641 +/* ..........................................................................
   6.642 + *
   6.643 + *
   6.644 + *
   6.645 + */
   6.646 +int16_t Command_error(char *tail)
   6.647 +{
   6.648 +   Serial.Send(ROMS("error ")); Serial.Send(tail); Serial.Send();
   6.649 +   return ECOMMAND;
   6.650 +}
   6.651 +
   6.652 +/* ..........................................................................
   6.653 + *
   6.654 + * ++gts <v>
   6.655 + *     if v:
   6.656 + *        transfer data as acceptor, until END
   6.657 + *     float all pins
   6.658 + *     ++mode 0 (device)
   6.659 + */
   6.660 +int16_t Command_gts(char *tail)
   6.661 +{
   6.662 +   Serial.Send(ROMS("gts ")); Serial.Send(tail); Serial.Send();
   6.663 +   GPIB.Float();
   6.664 +   return ECOMMAND;
   6.665 +}
   6.666 +
   6.667 +/* ..........................................................................
   6.668 + *
   6.669 + * ++ver
   6.670 + *     Display version string
   6.671 + */
   6.672 +void Version()
   6.673 +{
   6.674 +   static const char version[] PROGMEM =
   6.675 +                          " version"
   6.676 +                          #include "version.h"
   6.677 +                          "\r\n";
   6.678 +   USB.Send(ROMS("Kingswood USB-GPIB-32U4 "));
   6.679 +   if(GPIB.MicroPro)
   6.680 +      USB.Send(ROMS("MicroPro"));
   6.681 +   else
   6.682 +      USB.Send(ROMS("Teensy"));
   6.683 +   USB.Send(ROM(version));
   6.684 +}
   6.685 +
   6.686 +/* ..........................................................................
   6.687 + *
   6.688 + * ++IFC <value>
   6.689 + * ++IFC? -> <value>
   6.690 + *    set or return ~IFC
   6.691 + */
   6.692 +int16_t Command_IFC(char *tail)
   6.693 +{
   6.694 +   switch(*tail)
   6.695 +   {  case 0:
   6.696 +      case '?':
   6.697 +         return GPIB.IFC();
   6.698 +      case '0':
   6.699 +      case '1':
   6.700 +         GPIB.IFC(*tail&1);
   6.701 +         return NONE;
   6.702 +   }
   6.703 +
   6.704 +   return EVALUE;
   6.705 +}
   6.706 +
   6.707 +/* ..........................................................................
   6.708 + *
   6.709 + * ++lines? -> <byte>
   6.710 + *    - return ~{EOI,ATN,SRQ,REN,IFC,NRFD,NDAC,DAV}
   6.711 + */
   6.712 +int16_t Command_lines(char *tail)
   6.713 +{
   6.714 +   uint8_t byte=0;
   6.715 +   if(GPIB.EOI())  byte|=1<<7;
   6.716 +   if(GPIB.ATN())  byte|=1<<6;
   6.717 +   if(GPIB.SRQ())  byte|=1<<5;
   6.718 +   if(GPIB.REN())  byte|=1<<4;
   6.719 +   if(GPIB.IFC())  byte|=1<<3;
   6.720 +   if(GPIB.NRFD()) byte|=1<<2;
   6.721 +   if(GPIB.NDAC()) byte|=1<<1;
   6.722 +   if(GPIB.DAV())  byte|=1<<0;
   6.723 +
   6.724 +   return byte;
   6.725 +}
   6.726 +
   6.727 +/* ..........................................................................
   6.728 + *
   6.729 + * ++llo [<device>]
   6.730 + *    equivalent to ++cmd LAD SAD LLO UNL
   6.731 + */
   6.732 +int16_t Command_llo(char *tail)
   6.733 +{
   6.734 +   Serial.Send(ROMS("llo ")); Serial.Send(tail); Serial.Send();
   6.735 +   return ECOMMAND;
   6.736 +}
   6.737 +
   6.738 +/* ..........................................................................
   6.739 + *
   6.740 + * ++loc [<device>]
   6.741 + *    equivalent to ++cmd TAD SAD UNL LAD SAD GTL
   6.742 + */
   6.743 +int16_t Command_loc(char *tail)
   6.744 +{
   6.745 +   Serial.Send(ROMS("loc ")); Serial.Send(tail); Serial.Send();
   6.746 +   return ECOMMAND;
   6.747 +}
   6.748 +
   6.749 +/* ..........................................................................
   6.750 + *
   6.751 + * ++lon <value>
   6.752 + *    enable listen only (promiscuous listen) mode
   6.753 + */
   6.754 +int16_t Command_lon(char *tail)
   6.755 +{
   6.756 +   Serial.Send(ROMS("lon ")); Serial.Send(tail); Serial.Send();
   6.757 +   return ECOMMAND;
   6.758 +}
   6.759 +
   6.760 +/* ..........................................................................
   6.761 + *
   6.762 + * ++mode <mode>
   6.763 + *     if mode==0 or mode=='d': device mode
   6.764 + *     elif mode==1 or mode=='c': controller in command mode
   6.765 + *     elif mode=='+': prompting mode (default)
   6.766 + */
   6.767 +int16_t Command_mode(char *tail)
   6.768 +{
   6.769 +   Serial.Send(ROMS("mode ")); Serial.Send(tail); Serial.Send();
   6.770 +   return ECOMMAND;
   6.771 +}
   6.772 +
   6.773 +/* ..........................................................................
   6.774 + *
   6.775 + * ++NDAC <value>
   6.776 + * ++NDAC? -> <value>
   6.777 + *
   6.778 + *    set or return ~NDAC
   6.779 + */
   6.780 +int16_t Command_NDAC(char *tail)
   6.781 +{
   6.782 +   switch(*tail)
   6.783 +   {  case 0:
   6.784 +      case '?':
   6.785 +         return GPIB.NDAC();
   6.786 +      case '0':
   6.787 +      case '1':
   6.788 +         GPIB.NDAC(*tail&1);
   6.789 +         return NONE;
   6.790 +   }
   6.791 +
   6.792 +   return EVALUE;
   6.793 +}
   6.794 +
   6.795 +/* ..........................................................................
   6.796 + *
   6.797 + * ++NRFD <value>
   6.798 + * ++NRFD? -> <value>
   6.799 + *
   6.800 + *    set or return ~NRFD
   6.801 + */
   6.802 +int16_t Command_NRFD(char *tail)
   6.803 +{
   6.804 +   switch(*tail)
   6.805 +   {  case 0:
   6.806 +      case '?':
   6.807 +         return GPIB.NRFD();
   6.808 +      case '0':
   6.809 +      case '1':
   6.810 +         GPIB.NRFD(*tail&1);
   6.811 +         return NONE;
   6.812 +   }
   6.813 +
   6.814 +   return EVALUE;
   6.815 +}
   6.816 +
   6.817 +/* ..........................................................................
   6.818 + *
   6.819 + * ++pct <address>
   6.820 + *    pass CIC to device
   6.821 + *    equivalent to ++cmd UNL LAD SAD TAD SAD TCT
   6.822 + */
   6.823 +int16_t Command_pct(char *tail)
   6.824 +{
   6.825 +   Serial.Send(ROMS("pct ")); Serial.Send(tail); Serial.Send();
   6.826 +   return ECOMMAND;
   6.827 +}
   6.828 +
   6.829 +/* ..........................................................................
   6.830 + *
   6.831 + * ++rd <count>
   6.832 + *    read <count> bytes or until EOI or timeout
   6.833 + */
   6.834 +int16_t Command_rd(char *tail)
   6.835 +{
   6.836 +   GPIB.NDAC(true);
   6.837 +   GPIB.NRFD(true);
   6.838 +   _delay_us(1);
   6.839 +   GPIB.ATN(false);
   6.840 +
   6.841 +   while(true)
   6.842 +   {
   6.843 +      int16_t data=GPIB.In();
   6.844 +
   6.845 +      if(data<0)
   6.846 +         break;
   6.847 +
   6.848 +      USB.SendSafeChar(data);
   6.849 +
   6.850 +      if(data&0xff00)
   6.851 +         return data>>8;
   6.852 +   }
   6.853 +
   6.854 +   return NONE;
   6.855 +}
   6.856 +
   6.857 +/* ..........................................................................
   6.858 + *
   6.859 + * ++read [<end>]
   6.860 + *     ++cmd UNL UNT TAD SAD MLA
   6.861 + *     if end=="eoi": read until eoi
   6.862 + *     elif end=="tmo": read until timeout
   6.863 + *     elif end: read until byte <end>
   6.864 + *     else: read until timeout
   6.865 + * ++read <device> <end>
   6.866 + *     ++cmd UNL UNT <device> MLA
   6.867 + *     if end=="eoi": read until eoi
   6.868 + *     elif end=="tmo": read until timeout
   6.869 + *     else: read until byte <end>
   6.870 + */
   6.871 +int16_t Command_read(char *tail)
   6.872 +{
   6.873 +   uint8_t byte;
   6.874 +
   6.875 +   GPIB.ATN(true);
   6.876 +   GPIB.EOI(false);
   6.877 +   GPIB.Out(Byte_UNL(0));
   6.878 +   GPIB.Out(Byte_MLA(0));
   6.879 +   GPIB.Out(Byte_TAD(0));
   6.880 +   byte=Byte_SAD(0);
   6.881 +   if(byte)
   6.882 +      GPIB.Out(byte);
   6.883 +
   6.884 +   int16_t r=Command_rd(tail);
   6.885 +
   6.886 +   GPIB.NDAC(false);
   6.887 +   GPIB.NRFD(false);
   6.888 +
   6.889 +   USB.Send();
   6.890 +   return r<0 ? r : NONE;
   6.891 +}
   6.892 +
   6.893 +/* ..........................................................................
   6.894 + *
   6.895 + * ++REN <value>
   6.896 + * ++REN? -> <value>
   6.897 + *
   6.898 + *    set or return ~REN
   6.899 + */
   6.900 +int16_t Command_REN(char *tail)
   6.901 +{
   6.902 +   switch(*tail)
   6.903 +   {  case 0:
   6.904 +      case '?':
   6.905 +         return GPIB.REN();
   6.906 +      case '0':
   6.907 +      case '1':
   6.908 +         GPIB.REN(*tail&1);
   6.909 +         return NONE;
   6.910 +   }
   6.911 +
   6.912 +   return EVALUE;
   6.913 +}
   6.914 +
   6.915 +/* ..........................................................................
   6.916 + *
   6.917 + * ++rpp -> <result>
   6.918 + *     perform parallel poll by asserting ATN and EOI, reading response from data bus
   6.919 + */
   6.920 +int16_t Command_rpp(char *tail)
   6.921 +{
   6.922 +   Serial.Send(ROMS("rpp ")); Serial.Send(tail); Serial.Send();
   6.923 +   return ECOMMAND;
   6.924 +}
   6.925 +
   6.926 +/* ..........................................................................
   6.927 + *
   6.928 + * ++rsp <device> -> <result>
   6.929 + *     read serial poll data, equivalent to
   6.930 + *     ++cmd UNL MLA SPE TAD SAD
   6.931 + *     ++rd <1 byte>
   6.932 + *     ++cmd SPD
   6.933 + */
   6.934 +int16_t Command_rsp(char *tail)
   6.935 +{
   6.936 +   Serial.Send(ROMS("rsp ")); Serial.Send(tail); Serial.Send();
   6.937 +   return ECOMMAND;
   6.938 +}
   6.939 +
   6.940 +/* ..........................................................................
   6.941 + *
   6.942 + * ++rst
   6.943 + *    - float all pins
   6.944 + *    - set defaults
   6.945 + */
   6.946 +int16_t Command_rst(char *tail)
   6.947 +{
   6.948 +   GPIB.Initialize();
   6.949 +   return NONE;
   6.950 +}
   6.951 +
   6.952 +/* ..........................................................................
   6.953 + *
   6.954 + * ++savecfg <state>
   6.955 + *     (no operation)
   6.956 + *     if state=1: save <mode> <addr> <auto> <aoi> <eos> <eot> <timeout> whenver changed
   6.957 + *     else: do not save
   6.958 + */
   6.959 +int16_t Command_savecfg(char *tail)
   6.960 +{
   6.961 +   Serial.Send(ROMS("savecfg ")); Serial.Send(tail); Serial.Send();
   6.962 +   return ECOMMAND;
   6.963 +}
   6.964 +
   6.965 +/* ..........................................................................
   6.966 + *
   6.967 + * ++self <address> [<secondary>]
   6.968 + * ++self? -> <address>
   6.969 + *    set or return address of USB-GPIB (default 0)
   6.970 + */
   6.971 +int16_t Command_self(char *tail)
   6.972 +{
   6.973 +   if(*tail==0 || *tail=='?')
   6.974 +      return GPIB.MyAddress;
   6.975 +
   6.976 +   uint16_t addr=strtoi(tail,(const char **)&tail);
   6.977 +   USB.Hex(addr);
   6.978 +
   6.979 +   if(*tail)
   6.980 +   {  if((addr & 0xffe0)!=0)
   6.981 +         return EVALUE;
   6.982 +
   6.983 +      tail=skipws(tail);
   6.984 +      if(*tail)
   6.985 +      {
   6.986 +         uint16_t second=strtoi(tail,(const char **)&tail);
   6.987 +         if((second & 0xffe0)!=0)
   6.988 +            return EVALUE;
   6.989 +         addr|=(0x60 | second)<<8;
   6.990 +      }
   6.991 +   }
   6.992 +   USB.Hex(addr);
   6.993 +
   6.994 +   GPIB.MyAddress=addr;
   6.995 +
   6.996 +   return NONE;
   6.997 +}
   6.998 +
   6.999 +/* ..........................................................................
  6.1000 + *
  6.1001 + * ++sic [<value>]
  6.1002 + *    send interface clear
  6.1003 + */
  6.1004 +int16_t Command_sic(char *tail)
  6.1005 +{
  6.1006 +   GPIB.IFC(true);
  6.1007 +   for(uint8_t i=0; i<100; i++)
  6.1008 +   {  _delay_ms(100);
  6.1009 +      if(!(GPIB.DAV() || GPIB.NRFD() || GPIB.NDAC()))
  6.1010 +         break;
  6.1011 +   }
  6.1012 +   GPIB.IFC(false);
  6.1013 +
  6.1014 +   return NONE;
  6.1015 +}
  6.1016 +
  6.1017 +/* ..........................................................................
  6.1018 + *
  6.1019 + * ++spoll
  6.1020 + *     serial poll
  6.1021 + */
  6.1022 +int16_t Command_spoll(char *tail)
  6.1023 +{
  6.1024 +   Serial.Send(ROMS("spoll ")); Serial.Send(tail); Serial.Send();
  6.1025 +   return ECOMMAND;
  6.1026 +}
  6.1027 +
  6.1028 +/* ..........................................................................
  6.1029 + *
  6.1030 + * ++SRQ <value>
  6.1031 + * ++SRQ? -> <value>
  6.1032 + *
  6.1033 + *    set or return ~SRQ
  6.1034 + */
  6.1035 +int16_t Command_SRQ(char *tail)
  6.1036 +{
  6.1037 +   switch(*tail)
  6.1038 +   {  case 0:
  6.1039 +      case '?':
  6.1040 +         return GPIB.SRQ();
  6.1041 +      case '0':
  6.1042 +      case '1':
  6.1043 +         GPIB.SRQ(*tail&1);
  6.1044 +         return NONE;
  6.1045 +   }
  6.1046 +
  6.1047 +   return EVALUE;
  6.1048 +}
  6.1049 +
  6.1050 +/* ..........................................................................
  6.1051 + *
  6.1052 + * ++status <value>
  6.1053 + * ++status? -> <value>
  6.1054 + *     report device status
  6.1055 + * ++rsv <byte>
  6.1056 + *     set or return status byte
  6.1057 + *     if byte&0x40: SRQ=0
  6.1058 + */
  6.1059 +int16_t Command_status(char *tail)
  6.1060 +{
  6.1061 +   Serial.Send(ROMS("status ")); Serial.Send(tail); Serial.Send();
  6.1062 +   return ECOMMAND;
  6.1063 +}
  6.1064 +
  6.1065 +/* ..........................................................................
  6.1066 + *
  6.1067 + * ++tmo <timeout>
  6.1068 + *     set timeout in ms (up to 65 seconds)
  6.1069 + */
  6.1070 +int16_t Command_tmo(char *tail)
  6.1071 +{
  6.1072 +   if(*tail==0 || *tail=='?')
  6.1073 +      return GPIB.Timeout;
  6.1074 +
  6.1075 +   uint16_t tmo=strtoi(tail,(const char **)&tail);
  6.1076 +   if(*tail)
  6.1077 +      return EVALUE;
  6.1078 +
  6.1079 +   GPIB.Timeout=tmo;
  6.1080 +   return NONE;
  6.1081 +}
  6.1082 +
  6.1083 +/* ..........................................................................
  6.1084 + *
  6.1085 + * ++trg <device> [<device>...]
  6.1086 + *     triggers one or more devices
  6.1087 + *     equivalent to ++cmd MTA UNL LAD SAD ... GET
  6.1088 + */
  6.1089 +int16_t Command_trg(char *tail)
  6.1090 +{
  6.1091 +   Serial.Send(ROMS("trg ")); Serial.Send(tail); Serial.Send();
  6.1092 +   return ECOMMAND;
  6.1093 +}
  6.1094 +
  6.1095 +/* ..........................................................................
  6.1096 + *
  6.1097 + * ++ver
  6.1098 + *     show version
  6.1099 + */
  6.1100 +int16_t Command_ver(char *tail)
  6.1101 +{
  6.1102 +   Version();
  6.1103 +   return NONE;
  6.1104 +}
  6.1105 +
  6.1106 +/* ..........................................................................
  6.1107 + *
  6.1108 + * ++wrt <bytes>
  6.1109 + *    - set ATN=1, send bytes, set ATN=float
  6.1110 + *    - for each byte, if code is preceded by "-": EOI=0
  6.1111 + *     else: EOI=1
  6.1112 + */
  6.1113 +int16_t Command_wrt(char *tail)
  6.1114 +{
  6.1115 +   return Command_cmd_wrt(tail,false);
  6.1116 +}
  6.1117 +
  6.1118 +/* ..........................................................................
  6.1119 + *
  6.1120 + * ++write <bytes>
  6.1121 + *    - set ATN=1, send MTA UNL LAD SAD, followed by bytes
  6.1122 + */
  6.1123 +int16_t Command_write(char *tail)
  6.1124 +{
  6.1125 +   uint8_t byte;
  6.1126 +
  6.1127 +   GPIB.ATN(true);
  6.1128 +   GPIB.EOI(false);
  6.1129 +   GPIB.Out(Byte_MTA(0));
  6.1130 +   GPIB.Out(Byte_UNL(0));
  6.1131 +   GPIB.Out(Byte_LAD(0));
  6.1132 +   byte=Byte_SAD(0);
  6.1133 +   if(byte)
  6.1134 +      GPIB.Out(byte);
  6.1135 +
  6.1136 +   int16_t r=Command_wrt(tail);
  6.1137 +
  6.1138 +   return r;
  6.1139 +}
  6.1140 +
  6.1141 +
  6.1142 +/* ----- command strings ---------------------------------------------------- */
  6.1143 +
  6.1144 +STRING(addr);   STRING(ATN);    STRING(auto);   STRING(cac);
  6.1145 +STRING(clr);    STRING(cmd);    STRING(data);   STRING(DAV);
  6.1146 +STRING(DEBUG);  STRING(EOI);    STRING(eoi);    STRING(eos);
  6.1147 +STRING(eot_char);               STRING(eot_enable);
  6.1148 +STRING(error);  STRING(gts);    STRING(help);   STRING(IFC);
  6.1149 +STRING(lines);  STRING(llo);
  6.1150 +STRING(loc);    STRING(lon);    STRING(mode);   STRING(NDAC);
  6.1151 +STRING(NRFD);   STRING(pct);    STRING(rd);     STRING(read);
  6.1152 +STRING(REN);    STRING(rpp);
  6.1153 +STRING(rsp);    STRING(rst);    STRING(rsv);    STRING(savecfg);
  6.1154 +STRING(self);   STRING(sic);    STRING(spoll);  STRING(sre);
  6.1155 +STRING(SRQ);    STRING(status); STRING(tmo);    STRING(trg);
  6.1156 +STRING(ver);    STRING(write);  STRING(wrt);
  6.1157 +
  6.1158 +#define COMMAND(s) { String_##s, Command_##s }
  6.1159 +
  6.1160 +int16_t Command_help(char *tail);
  6.1161 +const struct Commands commandTable[]=
  6.1162 +{
  6.1163 +   COMMAND(ATN),    COMMAND(DAV),    COMMAND(DEBUG),  COMMAND(EOI),
  6.1164 +   COMMAND(IFC),    COMMAND(NDAC),   COMMAND(NRFD),   COMMAND(REN),
  6.1165 +   COMMAND(SRQ),
  6.1166 +
  6.1167 +   COMMAND(addr),   COMMAND(auto),   COMMAND(cac),
  6.1168 +   COMMAND(clr),    COMMAND(cmd),    COMMAND(data),
  6.1169 +   COMMAND(eoi),    COMMAND(eos),    COMMAND(eot_char),
  6.1170 +   COMMAND(eot_enable),
  6.1171 +   COMMAND(error),  COMMAND(gts),    COMMAND(help),
  6.1172 +   COMMAND(lines),  COMMAND(llo),    COMMAND(loc),    COMMAND(lon),
  6.1173 +   COMMAND(mode),   COMMAND(pct),
  6.1174 +   COMMAND(rd),     COMMAND(read),
  6.1175 +   COMMAND(rpp),    COMMAND(rsp),    COMMAND(rst),
  6.1176 +   { String_rsv, Command_status },
  6.1177 +   COMMAND(savecfg),
  6.1178 +   COMMAND(self),   COMMAND(sic),
  6.1179 +   COMMAND(spoll),
  6.1180 +   { String_sre, Command_REN },
  6.1181 +   COMMAND(status), COMMAND(tmo),    COMMAND(trg),
  6.1182 +   COMMAND(ver),    COMMAND(write),  COMMAND(wrt),
  6.1183 +   { 0,0 },
  6.1184 +};
  6.1185 +
  6.1186 +const ROM_PTR struct Commands *FindCommand(const ROM_PTR struct Commands *table,
  6.1187 +                                           const char *command)
  6.1188 +{
  6.1189 +   uint8_t lim;
  6.1190 +   for(lim=0; pgm_read_word(&table[lim].Command)!=0; lim++)
  6.1191 +      { }
  6.1192 +
  6.1193 +   for(; lim!=0; lim>>=1)
  6.1194 +   {
  6.1195 +      const ROM_PTR struct Commands *p = table + (lim >> 1);
  6.1196 +      const ROM_PTR char *entry=(const ROM_PTR char *)pgm_read_word(&p->Command);
  6.1197 +      int8_t cmp=strcmp_P(command, entry);
  6.1198 +
  6.1199 +      if(cmp==0)
  6.1200 +         return p;
  6.1201 +      else if(cmp > 0)
  6.1202 +      {  /* command > p: move right */
  6.1203 +         table = p + 1;
  6.1204 +         lim--;
  6.1205 +      }
  6.1206 +      else
  6.1207 +      { /* move left */ }
  6.1208 +   }
  6.1209 +
  6.1210 +   return 0;
  6.1211 +}
  6.1212 +
  6.1213 +
  6.1214 +int16_t Command(char *command)
  6.1215 +{  char c;
  6.1216 +   char *tail=command;
  6.1217 +
  6.1218 +   if(*command<' ')
  6.1219 +      return 0;
  6.1220 +
  6.1221 +   int r=ECOMMAND;
  6.1222 +   if(*command=='?')
  6.1223 +      r=Command_help(command+1);
  6.1224 +   else
  6.1225 +   {
  6.1226 +      while(isalnum(*tail))
  6.1227 +         tail++;
  6.1228 +
  6.1229 +      c=*tail;
  6.1230 +      *tail=0;
  6.1231 +
  6.1232 +      const ROM_PTR struct Commands *cmd=FindCommand(commandTable,command);
  6.1233 +
  6.1234 +      if(cmd)
  6.1235 +      {
  6.1236 +         *tail=c;
  6.1237 +         tail=skipws(tail);
  6.1238 +
  6.1239 +         Method f=(Method)(pgm_read_word(&cmd->Function));
  6.1240 +         r=f(tail);
  6.1241 +      }
  6.1242 +   }
  6.1243 +
  6.1244 +   if(r!=NONE)
  6.1245 +   {
  6.1246 +      USB.Send(r);
  6.1247 +      USB.Send();
  6.1248 +   }
  6.1249 +   return r;
  6.1250 +}
  6.1251 +
  6.1252 +
  6.1253 +/* ..........................................................................
  6.1254 + *
  6.1255 + * ++help
  6.1256 + *    show available commands
  6.1257 + */
  6.1258 +int16_t Command_help(char *tail)
  6.1259 +{
  6.1260 +   Version();
  6.1261 +   USB.Send(ROMS("Available commands:"));
  6.1262 +
  6.1263 +   const char *p;
  6.1264 +   for(uint8_t i=0; (p=(const char *)pgm_read_word(&commandTable[i].Command))!=0; i++)
  6.1265 +   {
  6.1266 +      char c=pgm_read_byte(p);
  6.1267 +
  6.1268 +      if(*tail=='?' || c>='a' || c==*tail)
  6.1269 +      {
  6.1270 +         USB.Send(ROMS("\r\n   ++"));
  6.1271 +         USB.Send(ROM(p));
  6.1272 +         if(p==String_cmd)
  6.1273 +         {
  6.1274 +            USB.Send(ROMS(" [-]<byte> ... or one of:\r\n        "));
  6.1275 +            for(uint8_t i=0; (p=(const char *)pgm_read_word(&byteTable[i].Command))!=0; i++)
  6.1276 +            {  USB.Send(' ');
  6.1277 +               USB.Send(ROM(p));
  6.1278 +            }
  6.1279 +         }
  6.1280 +      }
  6.1281 +   }
  6.1282 +   USB.Send(ROMS("\r\n"));
  6.1283 +   return NONE;
  6.1284 +}
  6.1285 +
  6.1286 +/* ----- EOF commands.cc ----- */
  6.1287 +
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/formatting.h	Tue Mar 25 20:31:00 2014 +0000
     7.3 @@ -0,0 +1,135 @@
     7.4 +/* #------------------------------------------------------------------------#
     7.5 +   |                                                                        |
     7.6 +   |   formatting.h                                                         |
     7.7 +   |                                                                        |
     7.8 +   |   String formatting helper class, used as CRTP.                        |
     7.9 +   |                                                                        |
    7.10 +   |   Copyright 2014, Frank A. Kingswood, www.kingswood-consulting.co.uk   |
    7.11 +   |                                                                        |
    7.12 +   #------------------------------------------------------------------------# */
    7.13 +
    7.14 +#ifndef FORMATTING_H_
    7.15 +#define FORMATTING_H_
    7.16 +#include <avr/pgmspace.h>
    7.17 +
    7.18 +enum _ROMS { A=0, B=0xffff };
    7.19 +#define ROM(s) ((_ROMS)(intptr_t)(s))
    7.20 +#define ROMS(s) ROM(PSTR(s))
    7.21 +
    7.22 +template<class Output> class Formatting
    7.23 +{
    7.24 +public:
    7.25 +
    7.26 +   static void Send(char c)
    7.27 +   {
    7.28 +      Output::Send_(c);
    7.29 +   }
    7.30 +
    7.31 +   static void __attribute__((noinline)) SendSafeChar(char c)
    7.32 +   {
    7.33 +      // a bit of safety - output only visible chars and make the rest octal
    7.34 +      if((c>=32 && c<127) || c==13 || c==10 || c==9)
    7.35 +         Send(c);
    7.36 +      else
    7.37 +      {  Send('\\');
    7.38 +         Send('0'+((c>>6))&3);
    7.39 +         Send('0'+((c>>3))&7);
    7.40 +         Send('0'+((c>>0))&7);
    7.41 +      }
    7.42 +   }
    7.43 +
    7.44 +   static void __attribute__((noinline)) Send(const char *message)
    7.45 +   {
    7.46 +      while(char c=*message)
    7.47 +      {
    7.48 +         SendSafeChar(c);
    7.49 +         message++;
    7.50 +      }
    7.51 +   }
    7.52 +
    7.53 +   static void __attribute__((noinline)) Send(_ROMS message)
    7.54 +   {
    7.55 +      intptr_t m=message;
    7.56 +      while(char c=pgm_read_byte_near(m))
    7.57 +      {
    7.58 +         SendSafeChar(c);
    7.59 +         m++;
    7.60 +      }
    7.61 +   }
    7.62 +
    7.63 +   static void __attribute__((noinline)) Send(uint16_t value)
    7.64 +   {
    7.65 +      static const unsigned powers[]={10000,1000,100,10,0};
    7.66 +      bool f=false;
    7.67 +      for(uint8_t i=0;;i++)
    7.68 +      {  unsigned n=powers[i];
    7.69 +         if(n==0)
    7.70 +            break;
    7.71 +         char d='0';
    7.72 +         while(value>=n)
    7.73 +         {  value-=n;
    7.74 +            d=d+1;
    7.75 +         }
    7.76 +         if(d!='0')
    7.77 +            f=true;
    7.78 +         if(f)
    7.79 +            Send(d);
    7.80 +      }
    7.81 +      Send(char('0'+value));
    7.82 +   }
    7.83 +
    7.84 +   static void __attribute__((noinline)) Hex(uint16_t value)
    7.85 +   {
    7.86 +      Send(ROMS("0x"));
    7.87 +      SendHex8(value>>8);
    7.88 +      SendHex8(value);
    7.89 +   }
    7.90 +
    7.91 +   static void __attribute__((noinline)) Hex(int16_t value)
    7.92 +   {  Hex(uint16_t(value));
    7.93 +   }
    7.94 +
    7.95 +   static void __attribute__((noinline)) Hex(uint8_t value)
    7.96 +   {
    7.97 +      Send(ROMS("0x"));
    7.98 +      SendHex8(value);
    7.99 +   }
   7.100 +
   7.101 +   static void __attribute__((noinline)) Hex(int8_t value)
   7.102 +   {  Hex(uint8_t(value));
   7.103 +   }
   7.104 +
   7.105 +   static void __attribute__((noinline)) Send(int16_t value)
   7.106 +   {
   7.107 +      uint16_t v;
   7.108 +      if(value<0)
   7.109 +      {  Send('-');
   7.110 +         v=-value;
   7.111 +      }
   7.112 +      else
   7.113 +         v=value;
   7.114 +      Send(v);
   7.115 +   }
   7.116 +
   7.117 +   static void __attribute__((noinline)) Send()
   7.118 +   {  Send(char('\r'));
   7.119 +      Send(char('\n'));
   7.120 +   }
   7.121 +
   7.122 +private:
   7.123 +   static void __attribute__((noinline)) SendHex8(uint8_t value)
   7.124 +   {  SendHex4(value>>4);
   7.125 +      SendHex4(value);
   7.126 +   }
   7.127 +   static void __attribute__((noinline)) SendHex4(uint8_t value)
   7.128 +   {  value&=15;
   7.129 +      if(value>9)
   7.130 +         Send(char('a'-10+value));
   7.131 +      else
   7.132 +         Send(char('0'+value));
   7.133 +   }
   7.134 +};
   7.135 +
   7.136 +#endif /* FORMATTING_H_ */
   7.137 +
   7.138 +/* ----- EOF formatting.h ----- */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/gpib.cc	Tue Mar 25 20:31:00 2014 +0000
     8.3 @@ -0,0 +1,365 @@
     8.4 +/* #------------------------------------------------------------------------#
     8.5 +   |                                                                        |
     8.6 +   |   gpib.cc                                                              |
     8.7 +   |                                                                        |
     8.8 +   |   USB-GPIB GPIB processing and state machine.                          |
     8.9 +   |                                                                        |
    8.10 +   |   Copyright 2014, Frank A. Kingswood, www.kingswood-consulting.co.uk   |
    8.11 +   |                                                                        |
    8.12 +   #------------------------------------------------------------------------# */
    8.13 +
    8.14 +#include <avr/io.h>
    8.15 +#include <avr/pgmspace.h>
    8.16 +#include <stdint.h>
    8.17 +#include <ctype.h>
    8.18 +#include <util/delay.h>
    8.19 +#include "usb_serial.h"
    8.20 +#include "serial.h"
    8.21 +#include "gpib.h"
    8.22 +
    8.23 +#define Debug USB
    8.24 +
    8.25 +uint16_t GPIBDriver::MyAddress;
    8.26 +uint16_t GPIBDriver::DeviceAddress;
    8.27 +uint16_t GPIBDriver::Timeout;
    8.28 +bool GPIBDriver::MicroPro;
    8.29 +
    8.30 +GPIBDriver::GPIBDriver()
    8.31 +{
    8.32 +   Initialize();
    8.33 +}
    8.34 +
    8.35 +void GPIBDriver::Initialize()
    8.36 +{
    8.37 +   MyAddress=0;
    8.38 +   DeviceAddress=1;
    8.39 +   MicroPro=test_bit_clear(PIND,PORTD_TEENSY_N_ARDUINO);
    8.40 +   Float();
    8.41 +}
    8.42 +
    8.43 +// float data bus
    8.44 +void GPIBDriver::FloatData()
    8.45 +{
    8.46 +   DDRB=0;
    8.47 +   PORTB=0xff;
    8.48 +   if(MicroPro)
    8.49 +   {  clear_bit(DDRE,6);
    8.50 +      clear_bit(DDRC,6);
    8.51 +   }
    8.52 +}
    8.53 +
    8.54 +// float all pins
    8.55 +void GPIBDriver::Float()
    8.56 +{
    8.57 +   // data lines all inputs
    8.58 +   FloatData();
    8.59 +
    8.60 +   static const uint8_t used_c=(1<<PORTC_DIO8);
    8.61 +   DDRC&=0xff^used_c;
    8.62 +   PORTC=(PORTC&~used_c)|(0xff&used_c);
    8.63 +
    8.64 +   static const uint8_t used_e=(1<<PORTE_DIO1);
    8.65 +   DDRE&=0xff^used_e;
    8.66 +   PORTE=(PORTE&~used_e)|(0xff&used_e);
    8.67 +
    8.68 +   static const uint8_t used_d=(1<<PORTD_EOI) |
    8.69 +                               (1<<PORTD_NDAC) |
    8.70 +                               (1<<PORTD_NRFD) |
    8.71 +                               (1<<PORTD_SRQ) |
    8.72 +                               (1<<PORTD_TEENSY_N_ARDUINO) |
    8.73 +                               (1<<PORTD_DAV);
    8.74 +   DDRD=0xff^used_d;
    8.75 +   PORTD=(PORTD&~used_d)|(0xff&used_d);
    8.76 +
    8.77 +   // controls, used indicates bits that are used by us
    8.78 +   static const uint8_t used_f=(1<<PORTF_ATN) | (1<<PORTF_IFC) | (1<<PORTF_REN) | (1<<PORTF_DIO8);
    8.79 +   DDRF&=0xff^used_f;
    8.80 +   PORTF=(PORTF&~used_f)|(0xff&used_f);
    8.81 +}
    8.82 +
    8.83 +// drive LED
    8.84 +void GPIBDriver::LED(bool on)
    8.85 +{
    8.86 +   if(MicroPro)
    8.87 +   {  if(on)
    8.88 +         set_bit(PORTD,PORTD_LED_MP);
    8.89 +      else
    8.90 +         clear_bit(PORTD,PORTD_LED_MP);
    8.91 +   }
    8.92 +   else
    8.93 +   {  if(on)
    8.94 +         set_bit(PORTD,PORTD_LED_T);
    8.95 +      else
    8.96 +         clear_bit(PORTD,PORTD_LED_T);
    8.97 +   }
    8.98 +}
    8.99 +
   8.100 +// Become controller in charge of the bus
   8.101 +//
   8.102 +// ++cic
   8.103 +//    - float all pins
   8.104 +//    - REN=0
   8.105 +
   8.106 +void GPIBDriver::Controller()
   8.107 +{
   8.108 +   Float();
   8.109 +
   8.110 +   // start driving ATN IFC and REN, pull up DIO8
   8.111 +   PORTF |= (1<<PORTF_ATN) | (1<<PORTF_IFC) | (1<<PORTF_REN) | (1<<PORTF_DIO8);
   8.112 +   DDRF  |= (1<<PORTF_ATN) | (1<<PORTF_IFC) | (1<<PORTF_REN);
   8.113 +
   8.114 +   // pull /REN low to become actice controller
   8.115 +   REN(true);
   8.116 +}
   8.117 +
   8.118 +
   8.119 +uint8_t GPIBDriver::Lines()
   8.120 +{
   8.121 +   uint8_t pd=PIND & ((1<<PORTD_EOI) | (1<<PORTD_NRFD) | (1<<PORTD_NDAC) |
   8.122 +                      (1<<PORTD_SRQ) | (1<<PORTD_DAV));
   8.123 +   uint8_t pf=PINF & ((1<<PORTF_ATN) | (1<<PORTF_IFC) | (1<<PORTF_REN));
   8.124 +
   8.125 +   return ~(pf | pd);
   8.126 +}
   8.127 +
   8.128 +void GPIBDriver::Report(const char *msg)
   8.129 +{
   8.130 +   if(msg)
   8.131 +   {
   8.132 +      Debug.Send(msg);
   8.133 +      Debug.Send(':');
   8.134 +   }
   8.135 +   Debug.Send('<');
   8.136 +   Debug.Hex(Data());
   8.137 +
   8.138 +   uint8_t lines=Lines();
   8.139 +   if(lines & (1<<PORTD_EOI))  Debug.Send(ROMS(" EOI"));
   8.140 +   if(lines & (1<<PORTF_ATN))  Debug.Send(ROMS(" ATN"));
   8.141 +   if(lines & (1<<PORTD_SRQ))  Debug.Send(ROMS(" SRQ"));
   8.142 +   if(lines & (1<<PORTF_REN))  Debug.Send(ROMS(" REN"));
   8.143 +   if(lines & (1<<PORTF_IFC))  Debug.Send(ROMS(" IFC"));
   8.144 +   if(lines & (1<<PORTD_NRFD)) Debug.Send(ROMS(" NRFD"));
   8.145 +   if(lines & (1<<PORTD_NDAC)) Debug.Send(ROMS(" NDAC"));
   8.146 +   if(lines & (1<<PORTD_DAV))  Debug.Send(ROMS(" DAV"));
   8.147 +
   8.148 +   Debug.Send('>');
   8.149 +   if(msg)
   8.150 +      Debug.Send();
   8.151 +}
   8.152 +
   8.153 +static const uint32_t TIMEOUT=0x1ff000ULL;  // 20 seconds
   8.154 +
   8.155 +int16_t GPIBDriver::Command(const int16_t *command)
   8.156 +{
   8.157 +   int8_t status=0;
   8.158 +   while(int16_t word=pgm_read_word(*command++))
   8.159 +   {
   8.160 +      ATN(word&(1<<9));
   8.161 +      EOI(word&(1<<8));
   8.162 +      status=Out(word);
   8.163 +      if(status)
   8.164 +         break;
   8.165 +   }
   8.166 +   return -status;
   8.167 +}
   8.168 +
   8.169 +void GPIBDriver::Data(uint8_t byte)
   8.170 +{
   8.171 +   PORTB=~byte;
   8.172 +   DDRB=SAFER ? byte : 0xff;
   8.173 +   if(MicroPro)
   8.174 +   {
   8.175 +      clear_bit(DDRB,0)
   8.176 +      ;
   8.177 +      // pathetic board does not have an 8-bit port
   8.178 +      if(byte&1)
   8.179 +      {  clear_bit(PORTE,6);
   8.180 +         set_bit(DDRE,6);
   8.181 +      }
   8.182 +      else
   8.183 +      {  clear_bit(DDRE,6);
   8.184 +         set_bit(PORTE,6);
   8.185 +      }
   8.186 +
   8.187 +      if(byte&0x80)
   8.188 +      {  clear_bit(PORTC,6);
   8.189 +         set_bit(DDRC,6);
   8.190 +      }
   8.191 +      else
   8.192 +      {  clear_bit(DDRC,6);
   8.193 +         set_bit(PORTC,6);
   8.194 +      }
   8.195 +   }
   8.196 +}
   8.197 +
   8.198 +uint8_t GPIBDriver::Out(uint8_t byte)
   8.199 +{
   8.200 +   DAV(false);
   8.201 +
   8.202 +   if(!NRFD() && !NDAC())
   8.203 +   {  USB.Send("++error 1\r\n");
   8.204 +      // disabled while debugging
   8.205 +      // return -1;
   8.206 +   }
   8.207 +
   8.208 +   // drive data
   8.209 +   Data(byte);
   8.210 +
   8.211 +   // settling delay
   8.212 +   _delay_us(2);
   8.213 +
   8.214 +   uint32_t timeout;
   8.215 +   for(timeout=TIMEOUT; timeout!=0; timeout--)
   8.216 +   {
   8.217 +      _delay_us(10);
   8.218 +
   8.219 +      if(!NRFD())
   8.220 +         break;
   8.221 +   }
   8.222 +
   8.223 +   if(!timeout)
   8.224 +      goto fail;
   8.225 +
   8.226 +   DAV(true);
   8.227 +
   8.228 +   for(timeout=TIMEOUT; timeout!=0; timeout--)
   8.229 +   {
   8.230 +      _delay_us(10);
   8.231 +
   8.232 +      if(!NDAC())
   8.233 +         break;
   8.234 +   }
   8.235 +
   8.236 +   if(!timeout)
   8.237 +      goto fail;
   8.238 +
   8.239 +   DAV(false);
   8.240 +
   8.241 +   // float data bus
   8.242 +   PORTB=0xff;
   8.243 +   DDRB=0;
   8.244 +
   8.245 +   return 0;
   8.246 +
   8.247 +fail:
   8.248 +   DAV(false);
   8.249 +
   8.250 +   // float data bus
   8.251 +   PORTB=0xff;
   8.252 +   DDRB=0;
   8.253 +
   8.254 +   USB.Send(ROMS("++error 2\r\n"));
   8.255 +   return -1;
   8.256 +}
   8.257 +
   8.258 +/* .......................................................................... */
   8.259 +
   8.260 +uint8_t GPIBDriver::Data()
   8.261 +{
   8.262 +   uint8_t byte=~PINB;
   8.263 +   if(MicroPro)
   8.264 +   {
   8.265 +      // pathetic board does not have an 8-bit port
   8.266 +      byte &= 0x7e;
   8.267 +      if(test_bit_clear(PINE,6))
   8.268 +         byte |= 1;
   8.269 +      if(test_bit_clear(PINE,6))
   8.270 +         byte |= 0x80;
   8.271 +   }
   8.272 +}
   8.273 +
   8.274 +int16_t GPIBDriver::In()
   8.275 +{
   8.276 +   NRFD(true);
   8.277 +   NDAC(true);
   8.278 +
   8.279 +   // ready for data
   8.280 +   NRFD(false);
   8.281 +
   8.282 +   uint8_t byte,atn,eoi;
   8.283 +   uint32_t timeout;
   8.284 +   for(timeout=TIMEOUT; timeout!=0; timeout--)
   8.285 +   {
   8.286 +      _delay_us(10);
   8.287 +
   8.288 +      if(DAV())
   8.289 +         break;
   8.290 +   }
   8.291 +
   8.292 +   if(!timeout)
   8.293 +      goto fail;
   8.294 +
   8.295 +   NRFD(true);
   8.296 +
   8.297 +   byte=Data();
   8.298 +
   8.299 +   atn=ATN();
   8.300 +   eoi=EOI();
   8.301 +
   8.302 +   NDAC(false);
   8.303 +
   8.304 +   for(timeout=TIMEOUT; timeout!=0; timeout--)
   8.305 +   {
   8.306 +      _delay_us(10);
   8.307 +
   8.308 +      if(!DAV())
   8.309 +         break;
   8.310 +   }
   8.311 +
   8.312 +   if(!timeout)
   8.313 +      goto fail;
   8.314 +
   8.315 +   if(!eoi)
   8.316 +      NDAC(true);
   8.317 +
   8.318 +   return byte | (eoi<<8) | (atn<<9);
   8.319 +
   8.320 +fail:
   8.321 +   NDAC(false);
   8.322 +   NRFD(false);
   8.323 +   USB.Send(ROMS("++error 4\r\n"));
   8.324 +   return -1;
   8.325 +}
   8.326 +
   8.327 +const GPIBDriver __attribute__((__progmem__)) GPIB;
   8.328 +
   8.329 +//
   8.330 +
   8.331 +// GPIB System Concepts
   8.332 +// ====================
   8.333 +//                                    ______________________
   8.334 +// ATN_________________________ATN___/                      ATN
   8.335 +//
   8.336 +//    ______          _________   ________          ________
   8.337 +// DAV      \________/         DAV        \________/        DAV
   8.338 +//
   8.339 +//        _____           _____    __________           ____
   8.340 +// NRFD__/     \_________/     NRFD          \_________/    NRFD
   8.341 +//
   8.342 +//                _____                         _____
   8.343 +// NDAC__________/     \_______NDAC____________/     \______NDAC
   8.344 +//
   8.345 +//         ________________           ___________________
   8.346 +// DATA---<________________>---DATA--<___________________>--DATA
   8.347 +//
   8.348 +//
   8.349 +// TNT4882 Manual
   8.350 +// ==============
   8.351 +//        __________________________
   8.352 +// ATN___/                          ATN
   8.353 +//
   8.354 +//    ___________          _________
   8.355 +// DAV           \________/         DAV
   8.356 +//
   8.357 +//           ________            ___
   8.358 +// NRFD_____/        \__________/   NRFD
   8.359 +//
   8.360 +//                      _____
   8.361 +// NDAC________________/     \______NDAC
   8.362 +//
   8.363 +//              ___________________
   8.364 +// DATA--------<___________________>--DATA
   8.365 +//
   8.366 +
   8.367 +/* ----- EOF gpib.cc ----- */
   8.368 +
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/gpib.h	Tue Mar 25 20:31:00 2014 +0000
     9.3 @@ -0,0 +1,321 @@
     9.4 +/* #------------------------------------------------------------------------#
     9.5 +   |                                                                        |
     9.6 +   |   gpib.h                                                               |
     9.7 +   |                                                                        |
     9.8 +   |   USB-GPIB GPIB processing and state machine.                          |
     9.9 +   |                                                                        |
    9.10 +   |   Copyright 2014, Frank A. Kingswood, www.kingswood-consulting.co.uk   |
    9.11 +   |                                                                        |
    9.12 +   #------------------------------------------------------------------------# */
    9.13 +
    9.14 +#ifndef GPIB_H_
    9.15 +#define GPIB_H_
    9.16 +
    9.17 +#include <avr/io.h>
    9.18 +
    9.19 +class GPIBDriver
    9.20 +{
    9.21 +public:
    9.22 +   static const bool SAFER=1;
    9.23 +
    9.24 +   static const unsigned PORTD_EOI=0,
    9.25 +                         PORTD_NRFD=1,
    9.26 +                         PORTD_NDAC=2,
    9.27 +                         PORTD_SRQ=3,
    9.28 +                         PORTD_TEENSY_N_ARDUINO=4,
    9.29 +                         PORTD_LED_MP=5,   // /LED on Arduino, serial on Teensy
    9.30 +                         PORTD_LED_T=6,   // LED on Teensy
    9.31 +                         PORTD_DAV=7;
    9.32 +
    9.33 +   // By happy coincidence the bits here are unused on port D
    9.34 +   static const unsigned PORTF_ATN=4,
    9.35 +                         PORTF_IFC=5,
    9.36 +                         PORTF_REN=6,
    9.37 +                         PORTF_DIO8=7;
    9.38 +
    9.39 +   // Data pins for MicroPro
    9.40 +   static const unsigned PORTC_DIO8=6;
    9.41 +   static const unsigned PORTE_DIO1=6;
    9.42 +
    9.43 +public:
    9.44 +   GPIBDriver();
    9.45 +   static void LED(bool);
    9.46 +
    9.47 +   /* ..... public data ........................................................ */
    9.48 +
    9.49 +   static uint16_t MyAddress;
    9.50 +   static uint16_t DeviceAddress;
    9.51 +   static uint16_t Timeout;
    9.52 +   static bool MicroPro;
    9.53 +
    9.54 +   /* ..... high level commands ................................................ */
    9.55 +
    9.56 +   static void Initialize();
    9.57 +   static void Float();
    9.58 +   static void Controller();
    9.59 +
    9.60 +   int16_t Command(const int16_t *command);  // UNIM
    9.61 +
    9.62 +   /* ..... byte level commands ................................................ */
    9.63 +
    9.64 +   static uint8_t Out(uint8_t byte);
    9.65 +   static int16_t In();
    9.66 +   static void Report(const char *msg=0);
    9.67 +
    9.68 +   static uint8_t Lines();
    9.69 +   #define set_bit(port_,bit_)                           \
    9.70 +      do                                                 \
    9.71 +      {  static const uint8_t port=_SFR_IO_ADDR(port_);  \
    9.72 +         static const uint8_t bit=bit_;                  \
    9.73 +         __asm__ __volatile__ ("sbi %0,%1"::"I"(port),"I"(bit):"memory"); \
    9.74 +      } while(0)
    9.75 +
    9.76 +   #define clear_bit(port_,bit_)                         \
    9.77 +      do                                                 \
    9.78 +      {  static const uint8_t port=_SFR_IO_ADDR(port_);  \
    9.79 +         static const uint8_t bit=bit_;                  \
    9.80 +         __asm__ __volatile__ ("cbi %0,%1"::"I"(port),"I"(bit):"memory"); \
    9.81 +      } while(0)
    9.82 +
    9.83 +   #define test_bit_set(port_,bit_)                      \
    9.84 +      ({  static const uint8_t port=_SFR_IO_ADDR(port_); \
    9.85 +          static const uint8_t bit=bit_;                 \
    9.86 +          uint8_t value;                                 \
    9.87 +          __asm__ __volatile__ (                         \
    9.88 +          "  clr %0 \n"                                  \
    9.89 +          "  sbic %1,%2 \n"                              \
    9.90 +          "  inc %0 \n"                                  \
    9.91 +          :"=r"(value)                                   \
    9.92 +          :"I"(port),"I"(bit)                            \
    9.93 +          :"memory");                                    \
    9.94 +          0xff&value;                                    \
    9.95 +      })
    9.96 +
    9.97 +   #define test_bit_clear(port_,bit_)                    \
    9.98 +      ({  static const uint8_t port=_SFR_IO_ADDR(port_); \
    9.99 +          static const uint8_t bit=bit_;                 \
   9.100 +          uint8_t value;                                 \
   9.101 +          __asm__ __volatile__ (                         \
   9.102 +          "  clr %0 \n"                                  \
   9.103 +          "  sbis %1,%2 \n"                              \
   9.104 +          "  inc %0 \n"                                  \
   9.105 +          :"=r"(value)                                   \
   9.106 +          :"I"(port),"I"(bit)                            \
   9.107 +          :"memory");                                    \
   9.108 +          0xff&value;                                    \
   9.109 +      })
   9.110 +
   9.111 +
   9.112 +   /* ..... bit level commands ................................................. */
   9.113 +
   9.114 +   static void FloatData();
   9.115 +   static uint8_t Data();
   9.116 +   static void Data(uint8_t byte);
   9.117 +
   9.118 +   // Who is allowed to drive the signals
   9.119 +   //
   9.120 +   // Control    Output
   9.121 +   // ---------  ---------
   9.122 +   //   NRFD     Listener
   9.123 +   //   NDAC     Listener
   9.124 +   //   DAV      Talker
   9.125 +   //
   9.126 +   // Control    Output
   9.127 +   // ---------  ---------
   9.128 +   //   ATN      Controller
   9.129 +   //   IFC      Controller
   9.130 +   //   REN      Controller
   9.131 +   //   SRQ      Any
   9.132 +   //   EOI      Talker and Controller
   9.133 +
   9.134 +   inline static void ATN(bool value)
   9.135 +   {
   9.136 +      if(!value)
   9.137 +      {  if(SAFER) clear_bit(DDRF,PORTF_ATN);
   9.138 +         set_bit(PORTF,PORTF_ATN);
   9.139 +      }
   9.140 +      else
   9.141 +      {  clear_bit(PORTF,PORTF_ATN);
   9.142 +         if(SAFER) set_bit(DDRF,PORTF_ATN);
   9.143 +      }
   9.144 +   }
   9.145 +   inline static void IFC(bool value)
   9.146 +   {
   9.147 +      if(!value)
   9.148 +      {  if(SAFER) clear_bit(DDRF,PORTF_IFC);
   9.149 +         set_bit(PORTF,PORTF_IFC);
   9.150 +      }
   9.151 +      else
   9.152 +      {  clear_bit(PORTF,PORTF_IFC);
   9.153 +         if(SAFER) set_bit(DDRF,PORTF_IFC);
   9.154 +      }
   9.155 +   }
   9.156 +   inline static void REN(bool value)
   9.157 +   {
   9.158 +      if(!value)
   9.159 +      {  if(SAFER) clear_bit(DDRF,PORTF_REN);
   9.160 +         set_bit(PORTF,PORTF_REN);
   9.161 +      }
   9.162 +      else
   9.163 +      {  clear_bit(PORTF,PORTF_REN);
   9.164 +         if(SAFER) set_bit(DDRF,PORTF_REN);
   9.165 +      }
   9.166 +   }
   9.167 +
   9.168 +   // shared pins, must not actively drive high
   9.169 +   inline static void EOI(bool value)
   9.170 +   {
   9.171 +      if(!value)
   9.172 +      {  clear_bit(DDRD,PORTD_EOI);
   9.173 +         set_bit(PORTD,PORTD_EOI);
   9.174 +      }
   9.175 +      else
   9.176 +      {  clear_bit(PORTD,PORTD_EOI);
   9.177 +         set_bit(DDRD,PORTD_EOI);
   9.178 +      }
   9.179 +   }
   9.180 +   inline static void NDAC(bool value)
   9.181 +   {
   9.182 +      if(!value)
   9.183 +      {  clear_bit(DDRD,PORTD_NDAC);
   9.184 +         set_bit(PORTD,PORTD_NDAC);
   9.185 +      }
   9.186 +      else
   9.187 +      {  clear_bit(PORTD,PORTD_NDAC);
   9.188 +         set_bit(DDRD,PORTD_NDAC);
   9.189 +      }
   9.190 +   }
   9.191 +   inline static void NRFD(bool value)
   9.192 +   {
   9.193 +      if(!value)
   9.194 +      {  clear_bit(DDRD,PORTD_NRFD);
   9.195 +         set_bit(PORTD,PORTD_NRFD);
   9.196 +      }
   9.197 +      else
   9.198 +      {  clear_bit(PORTD,PORTD_NRFD);
   9.199 +         set_bit(DDRD,PORTD_NRFD);
   9.200 +      }
   9.201 +   }
   9.202 +   inline static void SRQ(bool value)
   9.203 +   {
   9.204 +      if(!value)
   9.205 +      {  clear_bit(DDRD,PORTD_SRQ);
   9.206 +         set_bit(PORTD,PORTD_SRQ);
   9.207 +      }
   9.208 +      else
   9.209 +      {  clear_bit(PORTD,PORTD_SRQ);
   9.210 +         set_bit(DDRD,PORTD_SRQ);
   9.211 +      }
   9.212 +   }
   9.213 +   inline static void DAV(bool value)
   9.214 +   {
   9.215 +      if(!value)
   9.216 +      {  clear_bit(DDRD,PORTD_DAV);
   9.217 +         set_bit(PORTD,PORTD_DAV);
   9.218 +      }
   9.219 +      else
   9.220 +      {  clear_bit(PORTD,PORTD_DAV);
   9.221 +         set_bit(DDRD,PORTD_DAV);
   9.222 +      }
   9.223 +   }
   9.224 +
   9.225 +   inline static uint8_t EOI()
   9.226 +   {
   9.227 +      return test_bit_clear(PIND,PORTD_EOI);
   9.228 +   }
   9.229 +   inline static uint8_t NDAC()
   9.230 +   {
   9.231 +      return test_bit_clear(PIND,PORTD_NDAC);
   9.232 +   }
   9.233 +   inline static uint8_t NRFD()
   9.234 +   {
   9.235 +      return test_bit_clear(PIND,PORTD_NRFD);
   9.236 +   }
   9.237 +   inline static uint8_t SRQ()
   9.238 +   {
   9.239 +      return test_bit_clear(PIND,PORTD_SRQ);
   9.240 +   }
   9.241 +   inline static uint8_t DAV()
   9.242 +   {
   9.243 +      return test_bit_clear(PIND,PORTD_DAV);
   9.244 +   }
   9.245 +   inline static int ATN()
   9.246 +   {
   9.247 +      return test_bit_clear(PINF,PORTF_ATN);
   9.248 +   }
   9.249 +   inline static uint8_t IFC()
   9.250 +   {
   9.251 +      return test_bit_clear(PINF,PORTF_IFC);
   9.252 +   }
   9.253 +   inline static uint8_t REN()
   9.254 +   {
   9.255 +      return test_bit_clear(PINF,PORTF_REN);
   9.256 +   }
   9.257 +};
   9.258 +
   9.259 +extern const GPIBDriver GPIB;
   9.260 +
   9.261 +// #define GPIB_S_DAT  1
   9.262 +// #define GPIB_R_DAT  2
   9.263 +// #define GPIB_R_SRQ  3
   9.264 +// #define RD_AD_CMD   4
   9.265 +// #define SET_IO_CMD  5
   9.266 +// #define RESET_CMD       6
   9.267 +//
   9.268 +// #define FLASH_SECTION_READ     0x01
   9.269 +// #define FLASH_SECTION_WRITE    0x02
   9.270 +//
   9.271 +// #define TIMEOUT 100000
   9.272 +// #define true 1
   9.273 +// #define false 0
   9.274 +// //
   9.275 +// // GPIB receive finite-state-machine states
   9.276 +// //
   9.277 +// #define GPIB_RX_START           0
   9.278 +// #define GPIB_RX_ACCEPT          1
   9.279 +// #define GPIB_RX_WAIT_DAV        2
   9.280 +// #define GPIB_RX_DAV_LOW         3
   9.281 +// #define GPIB_RX_WAIT_DAV_HIGH   4
   9.282 +// #define GPIB_RX_DAV_HIGH        5
   9.283 +// #define GPIB_RX_EOI             6
   9.284 +// #define GPIB_RX_FINISH          9
   9.285 +// #define GPIB_RX_DAV_TIMEOUT     10
   9.286 +// #define GPIB_RX_DONE            99
   9.287 +//
   9.288 +// //
   9.289 +// // GPIB send finite-state-machine states
   9.290 +// //
   9.291 +// #define GPIB_TX_START           0
   9.292 +// #define GPIB_TX_CHECK           1
   9.293 +// #define GPIB_TX_PUT_DATA        2
   9.294 +// #define GPIB_TX_WAIT_FOR_NRFD   3
   9.295 +// #define GPIB_TX_SET_DAV_LOW     4
   9.296 +// #define GPIB_TX_WAIT_FOR_NDAC   5
   9.297 +// #define GPIB_TX_SET_DAV_HIGH    6
   9.298 +// #define GPIB_TX_FINISH          9
   9.299 +// #define GPIB_TX_ERROR           98
   9.300 +// #define GPIB_TX_DONE            99
   9.301 +//
   9.302 +// #define GPIB_MAX_TX_LEN         64      // Max length of transmit GPIB string
   9.303 +// #define GPIB_MAX_RX_LEN         128     // Max length of receive GPIB string
   9.304 +// #define GPIB_MAX_CMD_LEN        32      // Max length of GPIB incoming command
   9.305 +//
   9.306 +// extern unsigned char gpib_buff[GPIB_MAX_RX_LEN];
   9.307 +// extern unsigned char gpib_ptr;
   9.308 +// extern char gpib_tx_buff[GPIB_MAX_TX_LEN];
   9.309 +// extern char gpib_tx_ptr;
   9.310 +// extern char gpib_cmd_buff[GPIB_MAX_CMD_LEN];
   9.311 +// extern unsigned char gpib_cmd_ptr;
   9.312 +// extern unsigned char listening;
   9.313 +// extern unsigned char in_command;
   9.314 +//
   9.315 +// void gpib_init(void);
   9.316 +// void sendgpib (void);
   9.317 +// int readgpib(void);
   9.318 +// void gpib_ren(unsigned char state);
   9.319 +// void gpib_ifc(void);
   9.320 +
   9.321 +#endif /* GPIB_H_ */
   9.322 +
   9.323 +/* ----- EOF gpib.h ----- */
   9.324 +
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/hardcopy	Tue Mar 25 20:31:00 2014 +0000
    10.3 @@ -0,0 +1,67 @@
    10.4 +#!/usr/bin/env python
    10.5 +
    10.6 +import argparse,os,sys,tempfile,time
    10.7 +try:
    10.8 +   import serial
    10.9 +except ImportError:
   10.10 +   print "Serial library not found - install python-serial"
   10.11 +   sys.exit(99)
   10.12 +
   10.13 +def main():
   10.14 +   p=argparse.ArgumentParser(description="Take hardcopy from Tek scope")
   10.15 +   p.add_argument(dest="File", metavar="file", type=str, nargs="?", default="hardcopy.bmp",
   10.16 +                  help="output file to write")
   10.17 +   p.add_argument("-d","--port", dest="Device", action="store", default=0,
   10.18 +                  help="serial port to use")
   10.19 +   args=p.parse_args()
   10.20 +
   10.21 +   if args.Device=="-":
   10.22 +      class S:
   10.23 +         def read(self,bytes=1<<14):return os.read(0,min(bytes,1<<14))
   10.24 +         def write(self,data):return os.write(1,data)
   10.25 +      usbgpib=S()
   10.26 +   else:
   10.27 +      usbgpib=serial.Serial(args.Device,timeout=5)
   10.28 +
   10.29 +   data=""
   10.30 +   while True:
   10.31 +      d=usbgpib.read(1)
   10.32 +      if d=="" or d==chr(13) or d==chr(10):
   10.33 +         break
   10.34 +      data+=d
   10.35 +   if "USB-GPIB" not in data:
   10.36 +      print "USB-GPIB not found"
   10.37 +      sys.exit(2)
   10.38 +
   10.39 +   usbgpib.write("rst\n")
   10.40 +   time.sleep(0.2)
   10.41 +   usbgpib.write("cac\n")
   10.42 +   time.sleep(0.2)
   10.43 +   usbgpib.write("cmd MTA UNL LAD\n")
   10.44 +   usbgpib.write("wrt -\"hardcopy start\"\n")
   10.45 +   usbgpib.write("cmd UNL MLA TAD\n")
   10.46 +   usbgpib.write("read\n")
   10.47 +   data=""
   10.48 +   while True:
   10.49 +      d=usbgpib.read()
   10.50 +      if d=="":
   10.51 +         break
   10.52 +      data+=d
   10.53 +   usbgpib.write("rst\n")
   10.54 +
   10.55 +   if data.startswith("\r"): data=data[1:]
   10.56 +   if data.startswith("\n"): data=data[1:]
   10.57 +
   10.58 +   print "%d bytes"%len(data)
   10.59 +   if args.File.endswith(".bmp"):
   10.60 +      fd=file(args.File,"wb")
   10.61 +      fd.write(data)
   10.62 +   else:
   10.63 +      fd=tempfile.NamedTemporaryFile("wb",suffix=".bmp")
   10.64 +      fd.write(data)
   10.65 +      fd.flush()
   10.66 +      os.system("convert %s %s"%(fd.name,args.File))
   10.67 +      del fd
   10.68 +
   10.69 +if __name__=="__main__":
   10.70 +   main()
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/main.cc	Tue Mar 25 20:31:00 2014 +0000
    11.3 @@ -0,0 +1,151 @@
    11.4 +/* #------------------------------------------------------------------------#
    11.5 +   |                                                                        |
    11.6 +   |   main.cc                                                              |
    11.7 +   |                                                                        |
    11.8 +   |   USB-GPIB startup and main loop.                                      |
    11.9 +   |                                                                        |
   11.10 +   |   Based in part on Simple example for Teensy USB Development Board.    |
   11.11 +   |   http://www.pjrc.com/teensy/  Copyright (c) 2008 PJRC.COM, LLC        |
   11.12 +   |                                                                        |
   11.13 +   |   Copyright 2014, Frank A. Kingswood, www.kingswood-consulting.co.uk   |
   11.14 +   |                                                                        |
   11.15 +   #------------------------------------------------------------------------# */
   11.16 +
   11.17 +#include <avr/io.h>
   11.18 +#include <avr/pgmspace.h>
   11.19 +#include <stdint.h>
   11.20 +#include <util/delay.h>
   11.21 +#include "usb_serial.h"
   11.22 +#include "serial.h"
   11.23 +#include "gpib.h"
   11.24 +
   11.25 +#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
   11.26 +
   11.27 +uint8_t recv_str(char *buf, uint8_t size);
   11.28 +const UsbSerial __attribute__((__progmem__)) USB;
   11.29 +
   11.30 +
   11.31 +/* -------------------------------------------------------------------------- */
   11.32 +
   11.33 +void Version();
   11.34 +int16_t Command(char *);
   11.35 +
   11.36 +int main(void)
   11.37 +{
   11.38 +   uint8_t n;
   11.39 +   static char buf[100];
   11.40 +
   11.41 +   // set for 16 MHz clock, and turn on the LED
   11.42 +   CPU_PRESCALE(0);
   11.43 +
   11.44 +   GPIB.Initialize();
   11.45 +   GPIB.LED(true);
   11.46 +   Serial.Initialize();
   11.47 +
   11.48 +   // initialize the USB, and then wait for the host
   11.49 +   // to set configuration.  If the Teensy is powered
   11.50 +   // without a PC connected to the USB port, this
   11.51 +   // will wait forever.
   11.52 +   USB.Initialize();
   11.53 +   while (!usb_configured())
   11.54 +      { }
   11.55 +   _delay_ms(1000);
   11.56 +
   11.57 +   while (1)
   11.58 +   {
   11.59 +      // wait for the user to run their terminal emulator program
   11.60 +      // which sets DTR to indicate it is ready to receive.
   11.61 +      while (!(usb_serial_get_control() & USB_SERIAL_DTR))
   11.62 +         { }
   11.63 +
   11.64 +      // discard anything that was received prior.  Sometimes the
   11.65 +      // operating system or other software will send a modem
   11.66 +      // "AT command", which can still be buffered.
   11.67 +      usb_serial_flush_input();
   11.68 +
   11.69 +      // print a nice welcome message
   11.70 +      Version();
   11.71 +
   11.72 +      // state
   11.73 +      bool DirectMode=false;
   11.74 +
   11.75 +      // and then listen for commands and process them
   11.76 +      while(1)
   11.77 +      {
   11.78 +         //GPIB.Report();
   11.79 +         USB.Send(ROMS("++"));
   11.80 +
   11.81 +         GPIB.LED(false);
   11.82 +
   11.83 +         n = recv_str(buf, sizeof(buf));
   11.84 +         if(n == 255)
   11.85 +            break;
   11.86 +         buf[n]=0;
   11.87 +
   11.88 +         GPIB.LED(true);
   11.89 +
   11.90 +         if(n>3 && buf[0]=='+' && buf[1]=='+')
   11.91 +         {
   11.92 +            USB.Send();
   11.93 +            Command(buf+2);
   11.94 +         }
   11.95 +         else if(!DirectMode)
   11.96 +         {
   11.97 +            USB.Send();
   11.98 +            Command(buf);
   11.99 +         }
  11.100 +         else
  11.101 +         {
  11.102 +            // send GPIB
  11.103 +         }
  11.104 +      }
  11.105 +   }
  11.106 +}
  11.107 +
  11.108 +// Receive a string from the USB serial port.  The string is stored
  11.109 +// in the buffer and this function will not exceed the buffer size.
  11.110 +// A carriage return or newline completes the string, and is not
  11.111 +// stored into the buffer.
  11.112 +// The return value is the number of characters received, or 255 if
  11.113 +// the virtual serial connection was closed while waiting.
  11.114 +//
  11.115 +uint8_t recv_str(char *buf, uint8_t size)
  11.116 +{
  11.117 +   int16_t r;
  11.118 +   uint8_t count=0;
  11.119 +
  11.120 +   while(count < size)
  11.121 +   {
  11.122 +      r = usb_serial_getchar();
  11.123 +      if(r==-1)
  11.124 +      {
  11.125 +         if(!usb_configured() || !(usb_serial_get_control() & USB_SERIAL_DTR))
  11.126 +         {
  11.127 +            // user no longer connected
  11.128 +            return 255;
  11.129 +         }
  11.130 +         // just a normal timeout, keep waiting
  11.131 +      }
  11.132 +      else
  11.133 +      {
  11.134 +         if(r=='\r' || r=='\n')
  11.135 +            return count;
  11.136 +         if(r=='\b' && count>0)
  11.137 +         {  --buf;
  11.138 +            --count;
  11.139 +            usb_serial_putchar(r);
  11.140 +            usb_serial_putchar(' ');
  11.141 +            usb_serial_putchar(r);
  11.142 +         }
  11.143 +         else if(r >= ' ' && r <= '~')
  11.144 +         {
  11.145 +            *buf++ = r;
  11.146 +            usb_serial_putchar(r);
  11.147 +            count++;
  11.148 +         }
  11.149 +      }
  11.150 +   }
  11.151 +   return count;
  11.152 +}
  11.153 +
  11.154 +/* ----- EOF main.cc ----- */
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/program	Tue Mar 25 20:31:00 2014 +0000
    12.3 @@ -0,0 +1,79 @@
    12.4 +#!/bin/sh
    12.5 +set -e
    12.6 +
    12.7 +if [ $# -ne 3 ] || [ "$1" = "--help" ] ; then
    12.8 +   echo "Called from Makefile to program USB-GPIB"
    12.9 +   exit 1
   12.10 +fi
   12.11 +
   12.12 +for DEV in /dev/ttyUSB0* ; do
   12.13 +   true
   12.14 +done
   12.15 +
   12.16 +MODE=
   12.17 +if lsusb -d 16c0:047a ; then
   12.18 +   echo "Autodetecting USB-GPIB"
   12.19 +
   12.20 +   exec 3<>$DEV
   12.21 +
   12.22 +   (
   12.23 +      sleep 1
   12.24 +      kill -ALRM $$
   12.25 +   ) &
   12.26 +   trap "true" ALRM
   12.27 +   while read X ; do echo $X ; done
   12.28 +   sleep 1
   12.29 +
   12.30 +   echo "++ver" >&3
   12.31 +   read V <&3
   12.32 +   case "$V" in
   12.33 +      *USB-GPIB-32U4*)
   12.34 +         echo "Found USB-GPIB"
   12.35 +         ;;
   12.36 +      *)
   12.37 +         exit 2
   12.38 +         ;;
   12.39 +   esac
   12.40 +
   12.41 +   # call the boot loader
   12.42 +   case "$V" in
   12.43 +      *Teensy*)
   12.44 +         echo "++DEBUG 0x7e00" >&3
   12.45 +         MODE=Teensy
   12.46 +         ;;
   12.47 +      *)
   12.48 +         echo "++DEBUG 0x7800" >&3
   12.49 +         MODE=AVR109
   12.50 +         ;;
   12.51 +   esac
   12.52 +
   12.53 +   exec 3>&-
   12.54 +   sleep 0.5
   12.55 +
   12.56 +elif lsusb -d 2341:8036 ; then
   12.57 +   MODE=AVR109
   12.58 +
   12.59 +elif lsusb -d 16c0:0478 ; then
   12.60 +   MODE=Teensy
   12.61 +
   12.62 +else
   12.63 +   echo "No device found"
   12.64 +   exit 1
   12.65 +fi
   12.66 +
   12.67 +echo "$MODE boot loader"
   12.68 +
   12.69 +if [ "$1" != "--program" ] ; then
   12.70 +   exit 1
   12.71 +fi
   12.72 +
   12.73 +set -x
   12.74 +
   12.75 +case "$MODE" in
   12.76 +   Teensy)
   12.77 +      teensy_loader_cli -mmcu="$2" -w -v "$3"
   12.78 +      ;;
   12.79 +   AVR109)
   12.80 +      avrdude -c avr109 -P $DEV -p "$2" -q -U flash:w:"$3"
   12.81 +      ;;
   12.82 +esac
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/serial.cc	Tue Mar 25 20:31:00 2014 +0000
    13.3 @@ -0,0 +1,136 @@
    13.4 +/* #------------------------------------------------------------------------#
    13.5 +   |                                                                        |
    13.6 +   |   serial.cc                                                            |
    13.7 +   |                                                                        |
    13.8 +   |   Debugging (transmit only) serial port.                               |
    13.9 +   |                                                                        |
   13.10 +   |   Copyright 2014, Frank A. Kingswood, www.kingswood-consulting.co.uk   |
   13.11 +   |                                                                        |
   13.12 +   #------------------------------------------------------------------------# */
   13.13 +
   13.14 +#include <avr/io.h>
   13.15 +#include <avr/wdt.h>
   13.16 +#include <avr/interrupt.h>
   13.17 +#include <stdint.h>
   13.18 +
   13.19 +#include "serial.h"
   13.20 +
   13.21 +#if !defined(SERIAL_PORT) || !defined(SERIAL_TXD)
   13.22 +   #ifdef __AVR_ATtiny85__
   13.23 +      #define SERIAL_PORT PORTB
   13.24 +      #define SERIAL_TXD  PB4
   13.25 +   #elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
   13.26 +      #define SERIAL_PORT PORTA
   13.27 +      #define SERIAL_TXD  PA7
   13.28 +   #elif defined(__AVR_ATtiny441__) || defined(__AVR_ATtiny841__)
   13.29 +      // These devices have hardware UART, not implemented here
   13.30 +      #define SERIAL_PORT PORTA
   13.31 +      #define SERIAL_TXD  PA7
   13.32 +      #define SERIAL_RXD  PB2
   13.33 +   #elif defined __AVR_ATmega32U4__
   13.34 +      // These devices have hardware UART but using a spare port pin here
   13.35 +      #define SERIAL_PORT PORTD
   13.36 +      #define SERIAL_TXD  PD5    // near switch
   13.37 +   #endif
   13.38 +#endif
   13.39 +
   13.40 +#if !defined(SERIAL_BAUD)
   13.41 +   #define SERIAL_BAUD 38400
   13.42 +#endif
   13.43 +
   13.44 +// Note on ABI: function calls  R18-R27, R30, R31 clobbered
   13.45 +//                              R2-R17, R28, R29 saved
   13.46 +
   13.47 +inline static void set_high()
   13.48 +{  static const uint8_t port=_SFR_IO_ADDR(SERIAL_PORT);
   13.49 +   static const uint8_t bit=SERIAL_TXD;
   13.50 +   __asm__ __volatile__ ("sbi %0,%1"::"I"(port),"I"(bit):"memory");
   13.51 +}
   13.52 +
   13.53 +inline static void set_low()
   13.54 +{  static const uint8_t port=_SFR_IO_ADDR(SERIAL_PORT);
   13.55 +   static const uint8_t bit=SERIAL_TXD;
   13.56 +   __asm__ __volatile__ ("cbi %0,%1"::"I"(port),"I"(bit):"memory");
   13.57 +}
   13.58 +
   13.59 +void __attribute__((noinline)) DebugSerial::delay()
   13.60 +{
   13.61 +   // 38400bps -> 26us
   13.62 +   // 19200bps -> 52us
   13.63 +   // 9600bps -> 104us
   13.64 +   // 7=fudge factor for call and loop overhead, below
   13.65 +#if SERIAL_BAUD==38400
   13.66 +   uint8_t count=F_CPU*26/3-(F_CPU>1?8:6);
   13.67 +#elif SERIAL_BAUD==19200
   13.68 +   uint8_t count=F_CPU*52/3-6;
   13.69 +#else // SERIAL_BAUD==9600
   13.70 +   uint8_t count=F_CPU*104/3-7;
   13.71 +#endif
   13.72 +   char dummy;
   13.73 +   __asm__ __volatile__ (
   13.74 +      "1: subi %0,1   \n"
   13.75 +      "   brne 1b     \n"
   13.76 +   #if SERIAL_BAUD==38400 && F_CPU==1
   13.77 +      "   breq 2f     \n"
   13.78 +      "2:             \n"
   13.79 +   #endif
   13.80 +      : "=r"(dummy)
   13.81 +      : "0"(count)
   13.82 +      : "0"
   13.83 +   );
   13.84 +}
   13.85 +
   13.86 +void __attribute__((noinline)) DebugSerial::Send_(char byte)
   13.87 +{
   13.88 +   static const uint8_t port=_SFR_IO_ADDR(SERIAL_PORT);
   13.89 +   static const uint8_t bit=SERIAL_TXD;
   13.90 +
   13.91 +   cli();
   13.92 +
   13.93 +   // start bit
   13.94 +   set_low();
   13.95 +
   13.96 +   for(uint8_t i=0;i<9;i++)
   13.97 +   {
   13.98 +      delay();
   13.99 +
  13.100 +      __asm__ __volatile__(
  13.101 +      "   asr %0       \n"
  13.102 +      "   brcs 1f      \n"
  13.103 +      "   nop          \n"
  13.104 +      "   cbi %2,%3    \n"
  13.105 +      "   brcc 2f      \n"
  13.106 +      "1: sbi %2,%3    \n"
  13.107 +      "   nop          \n"
  13.108 +      "2: \n"
  13.109 +      :"=r"(byte)
  13.110 +      :"0"(byte),"I"(port),"I"(bit));
  13.111 +   }
  13.112 +
  13.113 +   // final data bit (MSB)
  13.114 +   delay();
  13.115 +
  13.116 +   // safe to enable interrupts now, no problem if stop bit is a bit longer.
  13.117 +   sei();
  13.118 +   set_high();
  13.119 +   delay();
  13.120 +#ifdef  SERIAL_TWO_STOP_BITS
  13.121 +   // two stop bits
  13.122 +   delay();
  13.123 +#endif
  13.124 +}
  13.125 +
  13.126 +DebugSerial::DebugSerial()
  13.127 +{  Initialize();
  13.128 +}
  13.129 +
  13.130 +void DebugSerial::Initialize()
  13.131 +{  static const uint8_t port=_SFR_IO_ADDR(SERIAL_PORT)-1;
  13.132 +   static const uint8_t bit=SERIAL_TXD;
  13.133 +   __asm__ __volatile__ ("sbi %0,%1"::"I"(port),"I"(bit));
  13.134 +   set_high();
  13.135 +}
  13.136 +
  13.137 +const DebugSerial __attribute__((__progmem__)) Serial;
  13.138 +
  13.139 +/* ----- EOF serial.cc ----- */
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/serial.h	Tue Mar 25 20:31:00 2014 +0000
    14.3 @@ -0,0 +1,31 @@
    14.4 +/* #------------------------------------------------------------------------#
    14.5 +   |                                                                        |
    14.6 +   |   serial.h                                                             |
    14.7 +   |                                                                        |
    14.8 +   |   Debugging (transmit only) serial port.                               |
    14.9 +   |                                                                        |
   14.10 +   |   Copyright 2014, Frank A. Kingswood, www.kingswood-consulting.co.uk   |
   14.11 +   |                                                                        |
   14.12 +   #------------------------------------------------------------------------# */
   14.13 +
   14.14 +#ifndef SERIAL_H_
   14.15 +#define SERIAL_H_
   14.16 +
   14.17 +#include "formatting.h"
   14.18 +//#define static_assert(COND) do { typedef char static_assertion[(COND)?1:-1]; } while(0)
   14.19 +
   14.20 +class DebugSerial:public Formatting<DebugSerial>
   14.21 +{
   14.22 +public:
   14.23 +   // public methods
   14.24 +   DebugSerial();
   14.25 +   static void Initialize();
   14.26 +
   14.27 +   static __attribute__((noinline)) void Send_(char c);
   14.28 +private:
   14.29 +   static void delay();
   14.30 +};
   14.31 +
   14.32 +extern const DebugSerial Serial;
   14.33 +
   14.34 +#endif /* SERIAL_H_ */
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/usb_serial.c	Tue Mar 25 20:31:00 2014 +0000
    15.3 @@ -0,0 +1,904 @@
    15.4 +/* USB Serial Example for Teensy USB Development Board
    15.5 + * http://www.pjrc.com/teensy/usb_serial.html
    15.6 + * Copyright (c) 2008,2010,2011 PJRC.COM, LLC
    15.7 + *
    15.8 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    15.9 + * of this software and associated documentation files (the "Software"), to deal
   15.10 + * in the Software without restriction, including without limitation the rights
   15.11 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   15.12 + * copies of the Software, and to permit persons to whom the Software is
   15.13 + * furnished to do so, subject to the following conditions:
   15.14 + *
   15.15 + * The above copyright notice and this permission notice shall be included in
   15.16 + * all copies or substantial portions of the Software.
   15.17 + *
   15.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   15.19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   15.20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   15.21 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   15.22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   15.23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   15.24 + * THE SOFTWARE.
   15.25 + */
   15.26 +
   15.27 +// Version 1.0: Initial Release
   15.28 +// Version 1.1: support Teensy++
   15.29 +// Version 1.2: fixed usb_serial_available
   15.30 +// Version 1.3: added transmit bandwidth test
   15.31 +// Version 1.4: added usb_serial_write
   15.32 +// Version 1.5: add support for Teensy 2.0
   15.33 +// Version 1.6: fix zero length packet bug
   15.34 +// Version 1.7: fix usb_serial_set_control
   15.35 +
   15.36 +#define USB_SERIAL_PRIVATE_INCLUDE
   15.37 +#include "usb_serial.h"
   15.38 +
   15.39 +
   15.40 +/**************************************************************************
   15.41 + *
   15.42 + *  Configurable Options
   15.43 + *
   15.44 + **************************************************************************/
   15.45 +
   15.46 +// You can change these to give your code its own name.  On Windows,
   15.47 +// these are only used before an INF file (driver install) is loaded.
   15.48 +#define STR_MANUFACTURER   L"Frank Kingswood"
   15.49 +#define STR_PRODUCT        L"USB-GPIB-32U4"
   15.50 +
   15.51 +// All USB serial devices are supposed to have a serial number
   15.52 +// (according to Microsoft).  On windows, a new COM port is created
   15.53 +// for every unique serial/vendor/product number combination.  If
   15.54 +// you program 2 identical boards with 2 different serial numbers
   15.55 +// and they are assigned COM7 and COM8, each will always get the
   15.56 +// same COM port number because Windows remembers serial numbers.
   15.57 +//
   15.58 +// On Mac OS-X, a device file is created automatically which
   15.59 +// incorperates the serial number, eg, /dev/cu-usbmodem12341
   15.60 +//
   15.61 +// Linux by default ignores the serial number, and creates device
   15.62 +// files named /dev/ttyACM0, /dev/ttyACM1... in the order connected.
   15.63 +// Udev rules (in /etc/udev/rules.d) can define persistent device
   15.64 +// names linked to this serial number, as well as permissions, owner
   15.65 +// and group settings.
   15.66 +#define STR_SERIAL_NUMBER  L"324"
   15.67 +
   15.68 +// Mac OS-X and Linux automatically load the correct drivers.  On
   15.69 +// Windows, even though the driver is supplied by Microsoft, an
   15.70 +// INF file is needed to load the driver.  These numbers need to
   15.71 +// match the INF file.
   15.72 +#define VENDOR_ID          0x16C0
   15.73 +#define PRODUCT_ID         0x047A
   15.74 +
   15.75 +// When you write data, it goes into a USB endpoint buffer, which
   15.76 +// is transmitted to the PC when it becomes full, or after a timeout
   15.77 +// with no more writes.  Even if you write in exactly packet-size
   15.78 +// increments, this timeout is used to send a "zero length packet"
   15.79 +// that tells the PC no more data is expected and it should pass
   15.80 +// any buffered data to the application that may be waiting.  If
   15.81 +// you want data sent immediately, call usb_serial_flush_output().
   15.82 +#define TRANSMIT_FLUSH_TIMEOUT   5   /* in milliseconds */
   15.83 +
   15.84 +// If the PC is connected but not "listening", this is the length
   15.85 +// of time before usb_serial_getchar() returns with an error.  This
   15.86 +// is roughly equivilant to a real UART simply transmitting the
   15.87 +// bits on a wire where nobody is listening, except you get an error
   15.88 +// code which you can ignore for serial-like discard of data, or
   15.89 +// use to know your data wasn't sent.
   15.90 +#define TRANSMIT_TIMEOUT   25   /* in milliseconds */
   15.91 +
   15.92 +// USB devices are supposed to implment a halt feature, which is
   15.93 +// rarely (if ever) used.  If you comment this line out, the halt
   15.94 +// code will be removed, saving 116 bytes of space (gcc 4.3.0).
   15.95 +// This is not strictly USB compliant, but works with all major
   15.96 +// operating systems.
   15.97 +#define SUPPORT_ENDPOINT_HALT
   15.98 +
   15.99 +
  15.100 +
  15.101 +/**************************************************************************
  15.102 + *
  15.103 + *  Endpoint Buffer Configuration
  15.104 + *
  15.105 + **************************************************************************/
  15.106 +
  15.107 +// These buffer sizes are best for most applications, but perhaps if you
  15.108 +// want more buffering on some endpoint at the expense of others, this
  15.109 +// is where you can make such changes.  The AT90USB162 has only 176 bytes
  15.110 +// of DPRAM (USB buffers) and only endpoints 3 & 4 can double buffer.
  15.111 +
  15.112 +#define ENDPOINT0_SIZE     16
  15.113 +#define CDC_ACM_ENDPOINT   2
  15.114 +#define CDC_RX_ENDPOINT    3
  15.115 +#define CDC_TX_ENDPOINT    4
  15.116 +#if defined(__AVR_AT90USB162__)
  15.117 +   #define CDC_ACM_SIZE    16
  15.118 +   #define CDC_ACM_BUFFER  EP_SINGLE_BUFFER
  15.119 +   #define CDC_RX_SIZE     32
  15.120 +   #define CDC_RX_BUFFER   EP_DOUBLE_BUFFER
  15.121 +   #define CDC_TX_SIZE     32
  15.122 +   #define CDC_TX_BUFFER   EP_DOUBLE_BUFFER
  15.123 +#else
  15.124 +   #define CDC_ACM_SIZE    16
  15.125 +   #define CDC_ACM_BUFFER  EP_SINGLE_BUFFER
  15.126 +   #define CDC_RX_SIZE     64
  15.127 +   #define CDC_RX_BUFFER   EP_DOUBLE_BUFFER
  15.128 +   #define CDC_TX_SIZE     64
  15.129 +   #define CDC_TX_BUFFER   EP_DOUBLE_BUFFER
  15.130 +#endif
  15.131 +
  15.132 +static const uint8_t PROGMEM endpoint_config_table[] = {
  15.133 +   0,
  15.134 +   1, EP_TYPE_INTERRUPT_IN,  EP_SIZE(CDC_ACM_SIZE) | CDC_ACM_BUFFER,
  15.135 +   1, EP_TYPE_BULK_OUT,      EP_SIZE(CDC_RX_SIZE) | CDC_RX_BUFFER,
  15.136 +   1, EP_TYPE_BULK_IN,       EP_SIZE(CDC_TX_SIZE) | CDC_TX_BUFFER
  15.137 +};
  15.138 +
  15.139 +
  15.140 +/**************************************************************************
  15.141 + *
  15.142 + *  Descriptor Data
  15.143 + *
  15.144 + **************************************************************************/
  15.145 +
  15.146 +// Descriptors are the data that your computer reads when it auto-detects
  15.147 +// this USB device (called "enumeration" in USB lingo).  The most commonly
  15.148 +// changed items are editable at the top of this file.  Changing things
  15.149 +// in here should only be done by those who've read chapter 9 of the USB
  15.150 +// spec and relevant portions of any USB class specifications!
  15.151 +
  15.152 +static const uint8_t PROGMEM device_descriptor[] = {
  15.153 +   18,                                 // bLength
  15.154 +   1,                                  // bDescriptorType
  15.155 +   0x00, 0x02,                         // bcdUSB
  15.156 +   2,                                  // bDeviceClass
  15.157 +   0,                                  // bDeviceSubClass
  15.158 +   0,                                  // bDeviceProtocol
  15.159 +   ENDPOINT0_SIZE,                     // bMaxPacketSize0
  15.160 +   LSB(VENDOR_ID), MSB(VENDOR_ID),     // idVendor
  15.161 +   LSB(PRODUCT_ID), MSB(PRODUCT_ID),   // idProduct
  15.162 +   0x00, 0x01,                         // bcdDevice
  15.163 +   1,                                  // iManufacturer
  15.164 +   2,                                  // iProduct
  15.165 +   3,                                  // iSerialNumber
  15.166 +   1                                   // bNumConfigurations
  15.167 +};
  15.168 +
  15.169 +#define CONFIG1_DESC_SIZE (9+9+5+5+4+5+7+9+7+7)
  15.170 +static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
  15.171 +   // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
  15.172 +   9,                            // bLength;
  15.173 +   2,                            // bDescriptorType;
  15.174 +   LSB(CONFIG1_DESC_SIZE),       // wTotalLength
  15.175 +   MSB(CONFIG1_DESC_SIZE),
  15.176 +   2,                            // bNumInterfaces
  15.177 +   1,                            // bConfigurationValue
  15.178 +   0,                            // iConfiguration
  15.179 +   0xC0,                         // bmAttributes
  15.180 +   50,                           // bMaxPower
  15.181 +   // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
  15.182 +   9,                            // bLength
  15.183 +   4,                            // bDescriptorType
  15.184 +   0,                            // bInterfaceNumber
  15.185 +   0,                            // bAlternateSetting
  15.186 +   1,                            // bNumEndpoints
  15.187 +   0x02,                         // bInterfaceClass
  15.188 +   0x02,                         // bInterfaceSubClass
  15.189 +   0x01,                         // bInterfaceProtocol
  15.190 +   0,                            // iInterface
  15.191 +   // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26
  15.192 +   5,                            // bFunctionLength
  15.193 +   0x24,                         // bDescriptorType
  15.194 +   0x00,                         // bDescriptorSubtype
  15.195 +   0x10, 0x01,                   // bcdCDC
  15.196 +   // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27
  15.197 +   5,                            // bFunctionLength
  15.198 +   0x24,                         // bDescriptorType
  15.199 +   0x01,                         // bDescriptorSubtype
  15.200 +   0x01,                         // bmCapabilities
  15.201 +   1,                            // bDataInterface
  15.202 +   // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28
  15.203 +   4,                            // bFunctionLength
  15.204 +   0x24,                         // bDescriptorType
  15.205 +   0x02,                         // bDescriptorSubtype
  15.206 +   0x06,                         // bmCapabilities
  15.207 +   // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33
  15.208 +   5,                            // bFunctionLength
  15.209 +   0x24,                         // bDescriptorType
  15.210 +   0x06,                         // bDescriptorSubtype
  15.211 +   0,                            // bMasterInterface
  15.212 +   1,                            // bSlaveInterface0
  15.213 +   // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
  15.214 +   7,                            // bLength
  15.215 +   5,                            // bDescriptorType
  15.216 +   CDC_ACM_ENDPOINT | 0x80,      // bEndpointAddress
  15.217 +   0x03,                         // bmAttributes (0x03=intr)
  15.218 +   CDC_ACM_SIZE, 0,              // wMaxPacketSize
  15.219 +   64,                           // bInterval
  15.220 +   // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
  15.221 +   9,                            // bLength
  15.222 +   4,                            // bDescriptorType
  15.223 +   1,                            // bInterfaceNumber
  15.224 +   0,                            // bAlternateSetting
  15.225 +   2,                            // bNumEndpoints
  15.226 +   0x0A,                         // bInterfaceClass
  15.227 +   0x00,                         // bInterfaceSubClass
  15.228 +   0x00,                         // bInterfaceProtocol
  15.229 +   0,                            // iInterface
  15.230 +   // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
  15.231 +   7,                            // bLength
  15.232 +   5,                            // bDescriptorType
  15.233 +   CDC_RX_ENDPOINT,              // bEndpointAddress
  15.234 +   0x02,                         // bmAttributes (0x02=bulk)
  15.235 +   CDC_RX_SIZE, 0,               // wMaxPacketSize
  15.236 +   0,                            // bInterval
  15.237 +   // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
  15.238 +   7,                            // bLength
  15.239 +   5,                            // bDescriptorType
  15.240 +   CDC_TX_ENDPOINT | 0x80,       // bEndpointAddress
  15.241 +   0x02,                         // bmAttributes (0x02=bulk)
  15.242 +   CDC_TX_SIZE, 0,               // wMaxPacketSize
  15.243 +   0                             // bInterval
  15.244 +};
  15.245 +
  15.246 +// If you're desperate for a little extra code memory, these strings
  15.247 +// can be completely removed if iManufacturer, iProduct, iSerialNumber
  15.248 +// in the device desciptor are changed to zeros.
  15.249 +struct usb_string_descriptor_struct {
  15.250 +   uint8_t bLength;
  15.251 +   uint8_t bDescriptorType;
  15.252 +   int16_t wString[];
  15.253 +};
  15.254 +static const struct usb_string_descriptor_struct PROGMEM string0 = {
  15.255 +   4,
  15.256 +   3,
  15.257 +   {0x0409}
  15.258 +};
  15.259 +static const struct usb_string_descriptor_struct PROGMEM string1 = {
  15.260 +   sizeof(STR_MANUFACTURER),
  15.261 +   3,
  15.262 +   STR_MANUFACTURER
  15.263 +};
  15.264 +static const struct usb_string_descriptor_struct PROGMEM string2 = {
  15.265 +   sizeof(STR_PRODUCT),
  15.266 +   3,
  15.267 +   STR_PRODUCT
  15.268 +};
  15.269 +static const struct usb_string_descriptor_struct PROGMEM string3 = {
  15.270 +   sizeof(STR_SERIAL_NUMBER),
  15.271 +   3,
  15.272 +   STR_SERIAL_NUMBER
  15.273 +};
  15.274 +
  15.275 +// This table defines which descriptor data is sent for each specific
  15.276 +// request from the host (in wValue and wIndex).
  15.277 +static const struct descriptor_list_struct {
  15.278 +   uint16_t wValue;
  15.279 +   uint16_t wIndex;
  15.280 +   const uint8_t  *addr;
  15.281 +   uint8_t     length;
  15.282 +} PROGMEM descriptor_list[] = {
  15.283 +   {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
  15.284 +   {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
  15.285 +   {0x0300, 0x0000, (const uint8_t *)&string0, 4},
  15.286 +   {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
  15.287 +   {0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)},
  15.288 +   {0x0303, 0x0409, (const uint8_t *)&string3, sizeof(STR_SERIAL_NUMBER)}
  15.289 +};
  15.290 +#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))
  15.291 +
  15.292 +
  15.293 +/**************************************************************************
  15.294 + *
  15.295 + *  Variables - these are the only non-stack RAM usage
  15.296 + *
  15.297 + **************************************************************************/
  15.298 +
  15.299 +// zero when we are not configured, non-zero when enumerated
  15.300 +static volatile uint8_t usb_configuration=0;
  15.301 +
  15.302 +// the time remaining before we transmit any partially full
  15.303 +// packet, or send a zero length packet.
  15.304 +static volatile uint8_t transmit_flush_timer=0;
  15.305 +static uint8_t transmit_previous_timeout=0;
  15.306 +
  15.307 +// serial port settings (baud rate, control signals, etc) set
  15.308 +// by the PC.  These are ignored, but kept in RAM.
  15.309 +static uint8_t cdc_line_coding[7]={0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x08};
  15.310 +static uint8_t cdc_line_rtsdtr=0;
  15.311 +
  15.312 +
  15.313 +/**************************************************************************
  15.314 + *
  15.315 + *  Public Functions - these are the API intended for the user
  15.316 + *
  15.317 + **************************************************************************/
  15.318 +
  15.319 +// initialize USB serial
  15.320 +void usb_init(void)
  15.321 +{
  15.322 +   HW_CONFIG();
  15.323 +        USB_FREEZE();            // enable USB
  15.324 +        PLL_CONFIG();            // config PLL, 16 MHz xtal
  15.325 +        while (!(PLLCSR & (1<<PLOCK))) ;  // wait for PLL lock
  15.326 +        USB_CONFIG();            // start USB clock
  15.327 +        UDCON = 0;            // enable attach resistor
  15.328 +   usb_configuration = 0;
  15.329 +   cdc_line_rtsdtr = 0;
  15.330 +        UDIEN = (1<<EORSTE)|(1<<SOFE);
  15.331 +   sei();
  15.332 +}
  15.333 +
  15.334 +// return 0 if the USB is not configured, or the configuration
  15.335 +// number selected by the HOST
  15.336 +uint8_t usb_configured(void)
  15.337 +{
  15.338 +   return usb_configuration;
  15.339 +}
  15.340 +
  15.341 +// get the next character, or -1 if nothing received
  15.342 +int16_t usb_serial_getchar(void)
  15.343 +{
  15.344 +   uint8_t c, intr_state;
  15.345 +
  15.346 +   // interrupts are disabled so these functions can be
  15.347 +   // used from the main program or interrupt context,
  15.348 +   // even both in the same program!
  15.349 +   intr_state = SREG;
  15.350 +   cli();
  15.351 +   if (!usb_configuration) {
  15.352 +      SREG = intr_state;
  15.353 +      return -1;
  15.354 +   }
  15.355 +   UENUM = CDC_RX_ENDPOINT;
  15.356 +   retry:
  15.357 +   c = UEINTX;
  15.358 +   if (!(c & (1<<RWAL))) {
  15.359 +      // no data in buffer
  15.360 +      if (c & (1<<RXOUTI)) {
  15.361 +         UEINTX = 0x6B;
  15.362 +         goto retry;
  15.363 +      }
  15.364 +      SREG = intr_state;
  15.365 +      return -1;
  15.366 +   }
  15.367 +   // take one byte out of the buffer
  15.368 +   c = UEDATX;
  15.369 +   // if buffer completely used, release it
  15.370 +   if (!(UEINTX & (1<<RWAL))) UEINTX = 0x6B;
  15.371 +   SREG = intr_state;
  15.372 +   return c;
  15.373 +}
  15.374 +
  15.375 +// number of bytes available in the receive buffer
  15.376 +uint8_t usb_serial_available(void)
  15.377 +{
  15.378 +   uint8_t n=0, i, intr_state;
  15.379 +
  15.380 +   intr_state = SREG;
  15.381 +   cli();
  15.382 +   if (usb_configuration) {
  15.383 +      UENUM = CDC_RX_ENDPOINT;
  15.384 +      n = UEBCLX;
  15.385 +      if (!n) {
  15.386 +         i = UEINTX;
  15.387 +         if (i & (1<<RXOUTI) && !(i & (1<<RWAL))) UEINTX = 0x6B;
  15.388 +      }
  15.389 +   }
  15.390 +   SREG = intr_state;
  15.391 +   return n;
  15.392 +}
  15.393 +
  15.394 +// discard any buffered input
  15.395 +void usb_serial_flush_input(void)
  15.396 +{
  15.397 +   uint8_t intr_state;
  15.398 +
  15.399 +   if (usb_configuration) {
  15.400 +      intr_state = SREG;
  15.401 +      cli();
  15.402 +      UENUM = CDC_RX_ENDPOINT;
  15.403 +      while ((UEINTX & (1<<RWAL))) {
  15.404 +         UEINTX = 0x6B;
  15.405 +      }
  15.406 +      SREG = intr_state;
  15.407 +   }
  15.408 +}
  15.409 +
  15.410 +// transmit a character.  0 returned on success, -1 on error
  15.411 +int8_t usb_serial_putchar(uint8_t c)
  15.412 +{
  15.413 +   uint8_t timeout, intr_state;
  15.414 +
  15.415 +   // if we're not online (enumerated and configured), error
  15.416 +   if (!usb_configuration) return -1;
  15.417 +   // interrupts are disabled so these functions can be
  15.418 +   // used from the main program or interrupt context,
  15.419 +   // even both in the same program!
  15.420 +   intr_state = SREG;
  15.421 +   cli();
  15.422 +   UENUM = CDC_TX_ENDPOINT;
  15.423 +   // if we gave up due to timeout before, don't wait again
  15.424 +   if (transmit_previous_timeout) {
  15.425 +      if (!(UEINTX & (1<<RWAL))) {
  15.426 +         SREG = intr_state;
  15.427 +         return -1;
  15.428 +      }
  15.429 +      transmit_previous_timeout = 0;
  15.430 +   }
  15.431 +   // wait for the FIFO to be ready to accept data
  15.432 +   timeout = UDFNUML + TRANSMIT_TIMEOUT;
  15.433 +   while (1) {
  15.434 +      // are we ready to transmit?
  15.435 +      if (UEINTX & (1<<RWAL)) break;
  15.436 +      SREG = intr_state;
  15.437 +      // have we waited too long?  This happens if the user
  15.438 +      // is not running an application that is listening
  15.439 +      if (UDFNUML == timeout) {
  15.440 +         transmit_previous_timeout = 1;
  15.441 +         return -1;
  15.442 +      }
  15.443 +      // has the USB gone offline?
  15.444 +      if (!usb_configuration) return -1;
  15.445 +      // get ready to try checking again
  15.446 +      intr_state = SREG;
  15.447 +      cli();
  15.448 +      UENUM = CDC_TX_ENDPOINT;
  15.449 +   }
  15.450 +   // actually write the byte into the FIFO
  15.451 +   UEDATX = c;
  15.452 +   // if this completed a packet, transmit it now!
  15.453 +   if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A;
  15.454 +   transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
  15.455 +   SREG = intr_state;
  15.456 +   return 0;
  15.457 +}
  15.458 +
  15.459 +
  15.460 +// transmit a character, but do not wait if the buffer is full,
  15.461 +//   0 returned on success, -1 on buffer full or error
  15.462 +int8_t usb_serial_putchar_nowait(uint8_t c)
  15.463 +{
  15.464 +   uint8_t intr_state;
  15.465 +
  15.466 +   if (!usb_configuration) return -1;
  15.467 +   intr_state = SREG;
  15.468 +   cli();
  15.469 +   UENUM = CDC_TX_ENDPOINT;
  15.470 +   if (!(UEINTX & (1<<RWAL))) {
  15.471 +      // buffer is full
  15.472 +      SREG = intr_state;
  15.473 +      return -1;
  15.474 +   }
  15.475 +   // actually write the byte into the FIFO
  15.476 +   UEDATX = c;
  15.477 +      // if this completed a packet, transmit it now!
  15.478 +   if (!(UEINTX & (1<<RWAL))) UEINTX = 0x3A;
  15.479 +   transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
  15.480 +   SREG = intr_state;
  15.481 +   return 0;
  15.482 +}
  15.483 +
  15.484 +// Send a string to the USB serial port.
  15.485 +int8_t usb_serial_puts(const char *string)
  15.486 +{  char c;
  15.487 +
  15.488 +   while((c=*string++)!=0)
  15.489 +   {
  15.490 +      int8_t r=usb_serial_putchar(c);
  15.491 +      if(r)
  15.492 +         return r;
  15.493 +   }
  15.494 +   return 0;
  15.495 +}
  15.496 +
  15.497 +// Send a string to the USB serial port.
  15.498 +// The string must be in program memory memory.
  15.499 +int8_t usb_serial_puts_P(const char *string)
  15.500 +{  char c;
  15.501 +
  15.502 +   while((c=pgm_read_byte(string++))!=0)
  15.503 +   {
  15.504 +      int8_t r=usb_serial_putchar(c);
  15.505 +      if(r)
  15.506 +         return r;
  15.507 +   }
  15.508 +   return 0;
  15.509 +}
  15.510 +
  15.511 +// transmit a buffer.
  15.512 +//  0 returned on success, -1 on error
  15.513 +// This function is optimized for speed!  Each call takes approx 6.1 us overhead
  15.514 +// plus 0.25 us per byte.  12 Mbit/sec USB has 8.67 us per-packet overhead and
  15.515 +// takes 0.67 us per byte.  If called with 64 byte packet-size blocks, this function
  15.516 +// can transmit at full USB speed using 43% CPU time.  The maximum theoretical speed
  15.517 +// is 19 packets per USB frame, or 1216 kbytes/sec.  However, bulk endpoints have the
  15.518 +// lowest priority, so any other USB devices will likely reduce the speed.  Speed
  15.519 +// can also be limited by how quickly the PC-based software reads data, as the host
  15.520 +// controller in the PC will not allocate bandwitdh without a pending read request.
  15.521 +// (thanks to Victor Suarez for testing and feedback and initial code)
  15.522 +
  15.523 +int8_t usb_serial_write(const uint8_t *buffer, uint16_t size)
  15.524 +{
  15.525 +   uint8_t timeout, intr_state, write_size;
  15.526 +
  15.527 +   // if we're not online (enumerated and configured), error
  15.528 +   if (!usb_configuration) return -1;
  15.529 +   // interrupts are disabled so these functions can be
  15.530 +   // used from the main program or interrupt context,
  15.531 +   // even both in the same program!
  15.532 +   intr_state = SREG;
  15.533 +   cli();
  15.534 +   UENUM = CDC_TX_ENDPOINT;
  15.535 +   // if we gave up due to timeout before, don't wait again
  15.536 +   if (transmit_previous_timeout) {
  15.537 +      if (!(UEINTX & (1<<RWAL))) {
  15.538 +         SREG = intr_state;
  15.539 +         return -1;
  15.540 +      }
  15.541 +      transmit_previous_timeout = 0;
  15.542 +   }
  15.543 +   // each iteration of this loop transmits a packet
  15.544 +   while (size) {
  15.545 +      // wait for the FIFO to be ready to accept data
  15.546 +      timeout = UDFNUML + TRANSMIT_TIMEOUT;
  15.547 +      while (1) {
  15.548 +         // are we ready to transmit?
  15.549 +         if (UEINTX & (1<<RWAL)) break;
  15.550 +         SREG = intr_state;
  15.551 +         // have we waited too long?  This happens if the user
  15.552 +         // is not running an application that is listening
  15.553 +         if (UDFNUML == timeout) {
  15.554 +            transmit_previous_timeout = 1;
  15.555 +            return -1;
  15.556 +         }
  15.557 +         // has the USB gone offline?
  15.558 +         if (!usb_configuration) return -1;
  15.559 +         // get ready to try checking again
  15.560 +         intr_state = SREG;
  15.561 +         cli();
  15.562 +         UENUM = CDC_TX_ENDPOINT;
  15.563 +      }
  15.564 +
  15.565 +      // compute how many bytes will fit into the next packet
  15.566 +      write_size = CDC_TX_SIZE - UEBCLX;
  15.567 +      if (write_size > size) write_size = size;
  15.568 +      size -= write_size;
  15.569 +
  15.570 +      // write the packet
  15.571 +      switch(write_size%8) {
  15.572 +         case 0: do { write_size-=8;
  15.573 +                      UEDATX = buffer[0];
  15.574 +         case 7:      UEDATX = buffer[1];
  15.575 +         case 6:      UEDATX = buffer[2];
  15.576 +         case 5:      UEDATX = buffer[3];
  15.577 +         case 4:      UEDATX = buffer[4];
  15.578 +         case 3:      UEDATX = buffer[5];
  15.579 +         case 2:      UEDATX = buffer[6];
  15.580 +         case 1:      UEDATX = buffer[7];
  15.581 +                      buffer+=8;
  15.582 +                 } while(write_size>=8);
  15.583 +      }
  15.584 +
  15.585 +      // if this completed a packet, transmit it now!
  15.586 +      if (!(UEINTX & (1<<RWAL)))
  15.587 +         UEINTX = 0x3A;
  15.588 +      transmit_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
  15.589 +      SREG = intr_state;
  15.590 +   }
  15.591 +   return 0;
  15.592 +}
  15.593 +
  15.594 +
  15.595 +// immediately transmit any buffered output.
  15.596 +// This doesn't actually transmit the data - that is impossible!
  15.597 +// USB devices only transmit when the host allows, so the best
  15.598 +// we can do is release the FIFO buffer for when the host wants it
  15.599 +void usb_serial_flush_output(void)
  15.600 +{
  15.601 +   uint8_t intr_state;
  15.602 +
  15.603 +   intr_state = SREG;
  15.604 +   cli();
  15.605 +   if (transmit_flush_timer) {
  15.606 +      UENUM = CDC_TX_ENDPOINT;
  15.607 +      UEINTX = 0x3A;
  15.608 +      transmit_flush_timer = 0;
  15.609 +   }
  15.610 +   SREG = intr_state;
  15.611 +}
  15.612 +
  15.613 +// functions to read the various async serial settings.  These
  15.614 +// aren't actually used by USB at all (communication is always
  15.615 +// at full USB speed), but they are set by the host so we can
  15.616 +// set them properly if we're converting the USB to a real serial
  15.617 +// communication
  15.618 +uint32_t usb_serial_get_baud(void)
  15.619 +{
  15.620 +   const uint32_t *p=(const uint32_t *)cdc_line_coding;
  15.621 +   return *p;
  15.622 +}
  15.623 +uint8_t usb_serial_get_stopbits(void)
  15.624 +{
  15.625 +   return cdc_line_coding[4];
  15.626 +}
  15.627 +uint8_t usb_serial_get_paritytype(void)
  15.628 +{
  15.629 +   return cdc_line_coding[5];
  15.630 +}
  15.631 +uint8_t usb_serial_get_numbits(void)
  15.632 +{
  15.633 +   return cdc_line_coding[6];
  15.634 +}
  15.635 +uint8_t usb_serial_get_control(void)
  15.636 +{
  15.637 +   return cdc_line_rtsdtr;
  15.638 +}
  15.639 +// write the control signals, DCD, DSR, RI, etc
  15.640 +// There is no CTS signal.  If software on the host has transmitted
  15.641 +// data to you but you haven't been calling the getchar function,
  15.642 +// it remains buffered (either here or on the host) and can not be
  15.643 +// lost because you weren't listening at the right time, like it
  15.644 +// would in real serial communication.
  15.645 +int8_t usb_serial_set_control(uint8_t signals)
  15.646 +{
  15.647 +   uint8_t intr_state;
  15.648 +
  15.649 +   intr_state = SREG;
  15.650 +   cli();
  15.651 +   if (!usb_configuration) {
  15.652 +      // we're not enumerated/configured
  15.653 +      SREG = intr_state;
  15.654 +      return -1;
  15.655 +   }
  15.656 +
  15.657 +   UENUM = CDC_ACM_ENDPOINT;
  15.658 +   if (!(UEINTX & (1<<RWAL))) {
  15.659 +      // unable to write
  15.660 +      // TODO; should this try to abort the previously
  15.661 +      // buffered message??
  15.662 +      SREG = intr_state;
  15.663 +      return -1;
  15.664 +   }
  15.665 +   UEDATX = 0xA1;
  15.666 +   UEDATX = 0x20;
  15.667 +   UEDATX = 0;
  15.668 +   UEDATX = 0;
  15.669 +   UEDATX = 0; // 0 seems to work nicely.  what if this is 1??
  15.670 +   UEDATX = 0;
  15.671 +   UEDATX = 1;
  15.672 +   UEDATX = 0;
  15.673 +   UEDATX = signals;
  15.674 +   UEINTX = 0x3A;
  15.675 +   SREG = intr_state;
  15.676 +   return 0;
  15.677 +}
  15.678 +
  15.679 +
  15.680 +
  15.681 +/**************************************************************************
  15.682 + *
  15.683 + *  Private Functions - not intended for general user consumption....
  15.684 + *
  15.685 + **************************************************************************/
  15.686 +
  15.687 +
  15.688 +// USB Device Interrupt - handle all device-level events
  15.689 +// the transmit buffer flushing is triggered by the start of frame
  15.690 +//
  15.691 +ISR(USB_GEN_vect)
  15.692 +{
  15.693 +   uint8_t intbits, t;
  15.694 +
  15.695 +   intbits = UDINT;
  15.696 +   UDINT = 0;
  15.697 +   if (intbits & (1<<EORSTI)) {
  15.698 +      UENUM = 0;
  15.699 +      UECONX = 1;
  15.700 +      UECFG0X = EP_TYPE_CONTROL;
  15.701 +      UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER;
  15.702 +      UEIENX = (1<<RXSTPE);
  15.703 +      usb_configuration = 0;
  15.704 +      cdc_line_rtsdtr = 0;
  15.705 +   }
  15.706 +   if (intbits & (1<<SOFI)) {
  15.707 +      if (usb_configuration) {
  15.708 +         t = transmit_flush_timer;
  15.709 +         if (t) {
  15.710 +            transmit_flush_timer = --t;
  15.711 +            if (!t) {
  15.712 +               UENUM = CDC_TX_ENDPOINT;
  15.713 +               UEINTX = 0x3A;
  15.714 +            }
  15.715 +         }
  15.716 +      }
  15.717 +   }
  15.718 +}
  15.719 +
  15.720 +
  15.721 +// Misc functions to wait for ready and send/receive packets
  15.722 +static inline void usb_wait_in_ready(void)
  15.723 +{
  15.724 +   while (!(UEINTX & (1<<TXINI))) ;
  15.725 +}
  15.726 +static inline void usb_send_in(void)
  15.727 +{
  15.728 +   UEINTX = ~(1<<TXINI);
  15.729 +}
  15.730 +static inline void usb_wait_receive_out(void)
  15.731 +{
  15.732 +   while (!(UEINTX & (1<<RXOUTI))) ;
  15.733 +}
  15.734 +static inline void usb_ack_out(void)
  15.735 +{
  15.736 +   UEINTX = ~(1<<RXOUTI);
  15.737 +}
  15.738 +
  15.739 +
  15.740 +
  15.741 +// USB Endpoint Interrupt - endpoint 0 is handled here.  The
  15.742 +// other endpoints are manipulated by the user-callable
  15.743 +// functions, and the start-of-frame interrupt.
  15.744 +//
  15.745 +ISR(USB_COM_vect)
  15.746 +{
  15.747 +   uint8_t intbits;
  15.748 +   const uint8_t *list;
  15.749 +   const uint8_t *cfg;
  15.750 +   uint8_t i, n, len, en;
  15.751 +   uint8_t *p;
  15.752 +   uint8_t bmRequestType;
  15.753 +   uint8_t bRequest;
  15.754 +   uint16_t wValue;
  15.755 +   uint16_t wIndex;
  15.756 +   uint16_t wLength;
  15.757 +   uint16_t desc_val;
  15.758 +   const uint8_t *desc_addr;
  15.759 +   uint8_t  desc_length;
  15.760 +
  15.761 +   UENUM = 0;
  15.762 +   intbits = UEINTX;
  15.763 +   if (intbits & (1<<RXSTPI)) {
  15.764 +      bmRequestType = UEDATX;
  15.765 +      bRequest = UEDATX;
  15.766 +      wValue = UEDATX;
  15.767 +      wValue |= (UEDATX << 8);
  15.768 +      wIndex = UEDATX;
  15.769 +      wIndex |= (UEDATX << 8);
  15.770 +      wLength = UEDATX;
  15.771 +      wLength |= (UEDATX << 8);
  15.772 +      UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
  15.773 +      if (bRequest == GET_DESCRIPTOR) {
  15.774 +         list = (const uint8_t *)descriptor_list;
  15.775 +         for (i=0; ; i++) {
  15.776 +            if (i >= NUM_DESC_LIST) {
  15.777 +               UECONX = (1<<STALLRQ)|(1<<EPEN);  //stall
  15.778 +               return;
  15.779 +            }
  15.780 +            desc_val = pgm_read_word(list);
  15.781 +            if (desc_val != wValue) {
  15.782 +               list += sizeof(struct descriptor_list_struct);
  15.783 +               continue;
  15.784 +            }
  15.785 +            list += 2;
  15.786 +            desc_val = pgm_read_word(list);
  15.787 +            if (desc_val != wIndex) {
  15.788 +               list += sizeof(struct descriptor_list_struct)-2;
  15.789 +               continue;
  15.790 +            }
  15.791 +            list += 2;
  15.792 +            desc_addr = (const uint8_t *)pgm_read_word(list);
  15.793 +            list += 2;
  15.794 +            desc_length = pgm_read_byte(list);
  15.795 +            break;
  15.796 +         }
  15.797 +         len = (wLength < 256) ? wLength : 255;
  15.798 +         if (len > desc_length) len = desc_length;
  15.799 +         do {
  15.800 +            // wait for host ready for IN packet
  15.801 +            do {
  15.802 +               i = UEINTX;
  15.803 +            } while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
  15.804 +            if (i & (1<<RXOUTI)) return;  // abort
  15.805 +            // send IN packet
  15.806 +            n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
  15.807 +            for (i = n; i; i--) {
  15.808 +               UEDATX = pgm_read_byte(desc_addr++);
  15.809 +            }
  15.810 +            len -= n;
  15.811 +            usb_send_in();
  15.812 +         } while (len || n == ENDPOINT0_SIZE);
  15.813 +         return;
  15.814 +      }
  15.815 +      if (bRequest == SET_ADDRESS) {
  15.816 +         usb_send_in();
  15.817 +         usb_wait_in_ready();
  15.818 +         UDADDR = wValue | (1<<ADDEN);
  15.819 +         return;
  15.820 +      }
  15.821 +      if (bRequest == SET_CONFIGURATION && bmRequestType == 0) {
  15.822 +         usb_configuration = wValue;
  15.823 +         cdc_line_rtsdtr = 0;
  15.824 +         transmit_flush_timer = 0;
  15.825 +         usb_send_in();
  15.826 +         cfg = endpoint_config_table;
  15.827 +         for (i=1; i<5; i++) {
  15.828 +            UENUM = i;
  15.829 +            en = pgm_read_byte(cfg++);
  15.830 +            UECONX = en;
  15.831 +            if (en) {
  15.832 +               UECFG0X = pgm_read_byte(cfg++);
  15.833 +               UECFG1X = pgm_read_byte(cfg++);
  15.834 +            }
  15.835 +         }
  15.836 +            UERST = 0x1E;
  15.837 +            UERST = 0;
  15.838 +         return;
  15.839 +      }
  15.840 +      if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) {
  15.841 +         usb_wait_in_ready();
  15.842 +         UEDATX = usb_configuration;
  15.843 +         usb_send_in();
  15.844 +         return;
  15.845 +      }
  15.846 +      if (bRequest == CDC_GET_LINE_CODING && bmRequestType == 0xA1) {
  15.847 +         usb_wait_in_ready();
  15.848 +         p = cdc_line_coding;
  15.849 +         for (i=0; i<7; i++) {
  15.850 +            UEDATX = *p++;
  15.851 +         }
  15.852 +         usb_send_in();
  15.853 +         return;
  15.854 +      }
  15.855 +      if (bRequest == CDC_SET_LINE_CODING && bmRequestType == 0x21) {
  15.856 +         usb_wait_receive_out();
  15.857 +         p = cdc_line_coding;
  15.858 +         for (i=0; i<7; i++) {
  15.859 +            *p++ = UEDATX;
  15.860 +         }
  15.861 +         usb_ack_out();
  15.862 +         usb_send_in();
  15.863 +         return;
  15.864 +      }
  15.865 +      if (bRequest == CDC_SET_CONTROL_LINE_STATE && bmRequestType == 0x21) {
  15.866 +         cdc_line_rtsdtr = wValue;
  15.867 +         usb_wait_in_ready();
  15.868 +         usb_send_in();
  15.869 +         return;
  15.870 +      }
  15.871 +      if (bRequest == GET_STATUS) {
  15.872 +         usb_wait_in_ready();
  15.873 +         i = 0;
  15.874 +         #ifdef SUPPORT_ENDPOINT_HALT
  15.875 +         if (bmRequestType == 0x82) {
  15.876 +            UENUM = wIndex;
  15.877 +            if (UECONX & (1<<STALLRQ)) i = 1;
  15.878 +            UENUM = 0;
  15.879 +         }
  15.880 +         #endif
  15.881 +         UEDATX = i;
  15.882 +         UEDATX = 0;
  15.883 +         usb_send_in();
  15.884 +         return;
  15.885 +      }
  15.886 +   #ifdef SUPPORT_ENDPOINT_HALT
  15.887 +      if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE) && bmRequestType == 0x02 && wValue == 0) {
  15.888 +         i = wIndex & 0x7F;
  15.889 +         if (i >= 1 && i <= MAX_ENDPOINT) {
  15.890 +            usb_send_in();
  15.891 +            UENUM = i;
  15.892 +            if (bRequest == SET_FEATURE) {
  15.893 +               UECONX = (1<<STALLRQ)|(1<<EPEN);
  15.894 +            } else {
  15.895 +               UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN);
  15.896 +               UERST = (1 << i);
  15.897 +               UERST = 0;
  15.898 +            }
  15.899 +            return;
  15.900 +         }
  15.901 +      }
  15.902 +   #endif
  15.903 +   }
  15.904 +   UECONX = (1<<STALLRQ) | (1<<EPEN);  // stall
  15.905 +}
  15.906 +
  15.907 +/* ----- EOF usb_serial.c ----- */
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/usb_serial.h	Tue Mar 25 20:31:00 2014 +0000
    16.3 @@ -0,0 +1,159 @@
    16.4 +/* USB Serial code for Teensy USB Development Board
    16.5 + * http://www.pjrc.com/teensy/usb_serial.html
    16.6 + * Copyright (c) 2008,2010,2011 PJRC.COM, LLC
    16.7 + */
    16.8 +
    16.9 +#ifndef usb_serial_h__
   16.10 +#define usb_serial_h__
   16.11 +
   16.12 +#include <stdint.h>
   16.13 +
   16.14 +#ifdef __cplusplus
   16.15 +
   16.16 +#include "formatting.h"
   16.17 +
   16.18 +extern "C" {
   16.19 +#endif
   16.20 +
   16.21 +// setup
   16.22 +void usb_init(void);       // initialize everything
   16.23 +uint8_t usb_configured(void);    // is the USB port configured
   16.24 +
   16.25 +// receiving data
   16.26 +int16_t usb_serial_getchar(void);   // receive a character (-1 if timeout/error)
   16.27 +uint8_t usb_serial_available(void); // number of bytes in receive buffer
   16.28 +void usb_serial_flush_input(void);  // discard any buffered input
   16.29 +
   16.30 +// transmitting data
   16.31 +int8_t usb_serial_putchar(uint8_t c);  // transmit a character
   16.32 +int8_t usb_serial_putchar_nowait(uint8_t c);  // transmit a character, do not wait
   16.33 +int8_t usb_serial_write(const uint8_t *buffer, uint16_t size); // transmit a buffer
   16.34 +void usb_serial_flush_output(void); // immediately transmit any buffered output
   16.35 +int8_t usb_serial_puts(const char *);
   16.36 +int8_t usb_serial_puts_P(const char *);
   16.37 +
   16.38 +// serial parameters
   16.39 +uint32_t usb_serial_get_baud(void); // get the baud rate
   16.40 +uint8_t usb_serial_get_stopbits(void); // get the number of stop bits
   16.41 +uint8_t usb_serial_get_paritytype(void);// get the parity type
   16.42 +uint8_t usb_serial_get_numbits(void);  // get the number of data bits
   16.43 +uint8_t usb_serial_get_control(void);  // get the RTS and DTR signal state
   16.44 +int8_t usb_serial_set_control(uint8_t signals); // set DSR, DCD, RI, etc
   16.45 +
   16.46 +// constants corresponding to the various serial parameters
   16.47 +#define USB_SERIAL_DTR           0x01
   16.48 +#define USB_SERIAL_RTS           0x02
   16.49 +#define USB_SERIAL_1_STOP        0
   16.50 +#define USB_SERIAL_1_5_STOP      1
   16.51 +#define USB_SERIAL_2_STOP        2
   16.52 +#define USB_SERIAL_PARITY_NONE   0
   16.53 +#define USB_SERIAL_PARITY_ODD    1
   16.54 +#define USB_SERIAL_PARITY_EVEN   2
   16.55 +#define USB_SERIAL_PARITY_MARK   3
   16.56 +#define USB_SERIAL_PARITY_SPACE  4
   16.57 +#define USB_SERIAL_DCD           0x01
   16.58 +#define USB_SERIAL_DSR           0x02
   16.59 +#define USB_SERIAL_BREAK         0x04
   16.60 +#define USB_SERIAL_RI            0x08
   16.61 +#define USB_SERIAL_FRAME_ERR     0x10
   16.62 +#define USB_SERIAL_PARITY_ERR    0x20
   16.63 +#define USB_SERIAL_OVERRUN_ERR   0x40
   16.64 +
   16.65 +// This file does not include the HID debug functions, so these empty
   16.66 +// macros replace them with nothing, so users can compile code that
   16.67 +// has calls to these functions.
   16.68 +#define usb_debug_putchar(c)
   16.69 +#define usb_debug_flush_output()
   16.70 +
   16.71 +// Everything below this point is only intended for usb_serial.c
   16.72 +#ifdef USB_SERIAL_PRIVATE_INCLUDE
   16.73 +   #include <avr/io.h>
   16.74 +   #include <avr/pgmspace.h>
   16.75 +   #include <avr/interrupt.h>
   16.76 +
   16.77 +   #define EP_TYPE_CONTROL          0x00
   16.78 +   #define EP_TYPE_BULK_IN          0x81
   16.79 +   #define EP_TYPE_BULK_OUT         0x80
   16.80 +   #define EP_TYPE_INTERRUPT_IN     0xC1
   16.81 +   #define EP_TYPE_INTERRUPT_OUT    0xC0
   16.82 +   #define EP_TYPE_ISOCHRONOUS_IN   0x41
   16.83 +   #define EP_TYPE_ISOCHRONOUS_OUT  0x40
   16.84 +   #define EP_SINGLE_BUFFER         0x02
   16.85 +   #define EP_DOUBLE_BUFFER         0x06
   16.86 +   #define EP_SIZE(s)               ((s) == 64 ? 0x30 : ((s) == 32 ? 0x20 : ((s) == 16 ? 0x10 : 0x00)))
   16.87 +
   16.88 +   #define MAX_ENDPOINT    4
   16.89 +
   16.90 +   #define LSB(n) (n & 255)
   16.91 +   #define MSB(n) ((n >> 8) & 255)
   16.92 +
   16.93 +   #if defined(__AVR_AT90USB162__)
   16.94 +      #define HW_CONFIG()
   16.95 +      #define PLL_CONFIG()  (PLLCSR = ((1<<PLLE)|(1<<PLLP0)))
   16.96 +      #define USB_CONFIG()  (USBCON = (1<<USBE))
   16.97 +      #define USB_FREEZE()  (USBCON = ((1<<USBE)|(1<<FRZCLK)))
   16.98 +   #elif defined(__AVR_ATmega32U4__)
   16.99 +      #define HW_CONFIG()   (UHWCON = 0x01)
  16.100 +      #define PLL_CONFIG()  (PLLCSR = 0x12)
  16.101 +      #define USB_CONFIG()  (USBCON = ((1<<USBE)|(1<<OTGPADE)))
  16.102 +      #define USB_FREEZE()  (USBCON = ((1<<USBE)|(1<<FRZCLK)))
  16.103 +   #elif defined(__AVR_AT90USB646__)
  16.104 +      #define HW_CONFIG()   (UHWCON = 0x81)
  16.105 +      #define PLL_CONFIG()  (PLLCSR = 0x1A)
  16.106 +      #define USB_CONFIG()  (USBCON = ((1<<USBE)|(1<<OTGPADE)))
  16.107 +      #define USB_FREEZE()  (USBCON = ((1<<USBE)|(1<<FRZCLK)))
  16.108 +   #elif defined(__AVR_AT90USB1286__)
  16.109 +      #define HW_CONFIG()   (UHWCON = 0x81)
  16.110 +      #define PLL_CONFIG()  (PLLCSR = 0x16)
  16.111 +      #define USB_CONFIG()  (USBCON = ((1<<USBE)|(1<<OTGPADE)))
  16.112 +      #define USB_FREEZE()  (USBCON = ((1<<USBE)|(1<<FRZCLK)))
  16.113 +   #endif
  16.114 +
  16.115 +   // standard control endpoint request types
  16.116 +   #define GET_STATUS                  0
  16.117 +   #define CLEAR_FEATURE               1
  16.118 +   #define SET_FEATURE                 3
  16.119 +   #define SET_ADDRESS                 5
  16.120 +   #define GET_DESCRIPTOR              6
  16.121 +   #define GET_CONFIGURATION           8
  16.122 +   #define SET_CONFIGURATION           9
  16.123 +   #define GET_INTERFACE               10
  16.124 +   #define SET_INTERFACE               11
  16.125 +   // HID (human interface device)
  16.126 +   #define HID_GET_REPORT              1
  16.127 +   #define HID_GET_PROTOCOL            3
  16.128 +   #define HID_SET_REPORT              9
  16.129 +   #define HID_SET_IDLE                10
  16.130 +   #define HID_SET_PROTOCOL            11
  16.131 +   // CDC (communication class device)
  16.132 +   #define CDC_SET_LINE_CODING         0x20
  16.133 +   #define CDC_GET_LINE_CODING         0x21
  16.134 +   #define CDC_SET_CONTROL_LINE_STATE  0x22
  16.135 +#endif
  16.136 +
  16.137 +#ifdef __cplusplus
  16.138 +} // extern "C"
  16.139 +
  16.140 +class UsbSerial:public Formatting<UsbSerial>
  16.141 +{
  16.142 +public:
  16.143 +   static void Initialize()
  16.144 +   {
  16.145 +      usb_init();
  16.146 +   }
  16.147 +
  16.148 +   static __attribute__((noinline)) void Send_(char c)
  16.149 +   {  usb_serial_putchar(c);
  16.150 +   }
  16.151 +
  16.152 +   // immediately transmit any buffered output
  16.153 +   static void Flush()
  16.154 +   {
  16.155 +      usb_serial_flush_output();
  16.156 +   }
  16.157 +};
  16.158 +extern const UsbSerial USB;
  16.159 +
  16.160 +#endif
  16.161 +
  16.162 +#endif // usb_serial_h__