Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

import source from http://blog.hodgepig.org/busninja/bus-ninja-1.0.ta…

  • Loading branch information...
commit 882079fb03943d58fe8abe864bd00c50a8006c01 0 parents
@tobyjaffey authored
Showing with 28,322 additions and 0 deletions.
  1. +358 −0 README.html
  2. +4 −0 hardware/README
  3. BIN  hardware/ninja.brd
  4. BIN  hardware/ninja.sch
  5. +322 −0 precompiled/ninja-arduino-diecemilia-atmega168.hex
  6. +81 −0 src/Makefile
  7. +106 −0 src/bus.c
  8. +55 −0 src/bus.h
  9. +33 −0 src/bus_commands.c
  10. +236 −0 src/bus_i2c.c
  11. +9 −0 src/bus_i2c.h
  12. +66 −0 src/bus_spi.c
  13. +9 −0 src/bus_spi.h
  14. +33 −0 src/command_bitbang.c
  15. +6 −0 src/command_bitbang.h
  16. +191 −0 src/commands.c
  17. +7 −0 src/commands.h
  18. +19 −0 src/config-arduino.mk
  19. +28 −0 src/config-dev.mk
  20. +19 −0 src/config-teensy.mk
  21. +45 −0 src/config.mk
  22. +260 −0 src/console.c
  23. +43 −0 src/console.h
  24. +18 −0 src/cpu.c
  25. +13 −0 src/cpu.h
  26. +307 −0 src/global_commands.c
  27. +33 −0 src/global_commands.h
  28. +395 −0 src/hw_i2c.c
  29. +113 −0 src/hw_i2c.h
  30. +37 −0 src/hw_led.c
  31. +16 −0 src/hw_led.h
  32. +39 −0 src/hw_spi.c
  33. +34 −0 src/hw_spi.h
  34. +61 −0 src/hw_uart.c
  35. +9 −0 src/hw_uart.h
  36. +347 −0 src/jtag.c
  37. +92 −0 src/jtag.h
  38. +156 −0 src/led.c
  39. +23 −0 src/led.h
  40. +109 −0 src/menu.c
  41. +10 −0 src/menu.h
  42. +78 −0 src/ninja.c
  43. +25 −0 src/ninja.h
  44. +129 −0 src/parse.c
  45. +17 −0 src/parse.h
  46. +144 −0 src/rules.mk
  47. +29 −0 src/tick.c
  48. +15 −0 src/tick.h
  49. +258 −0 src/usbdev.c
  50. +25 −0 src/usbdev.h
  51. BIN  src/usbdev.o
  52. +344 −0 src/usbdev_avrisp.c
  53. +16 −0 src/usbdev_avrisp.h
  54. BIN  src/usbdev_avrisp.o
  55. +313 −0 src/usbdev_cdc.c
  56. +25 −0 src/usbdev_cdc.h
  57. BIN  src/usbdev_cdc.o
  58. +317 −0 src/usbdev_jtag.c
  59. +16 −0 src/usbdev_jtag.h
  60. +24 −0 src/watchdog.c
  61. +8 −0 src/watchdog.h
  62. BIN  test/i2c/24LC16B-breadboard.jpg
  63. BIN  test/i2c/24LC16B-pinout.png
  64. +12 −0 test/i2c/24LC16B.txt
  65. BIN  test/spi/._MCP23S17-pinout.png
  66. BIN  test/spi/MCP23S17-breadboard.jpg
  67. BIN  test/spi/MCP23S17-pinout.png
  68. +20 −0 test/spi/MCP23S17.txt
  69. +576 −0 third-party/LUFA100513/Bootloaders/CDC/BootloaderCDC.c
  70. +130 −0 third-party/LUFA100513/Bootloaders/CDC/BootloaderCDC.h
  71. +72 −0 third-party/LUFA100513/Bootloaders/CDC/BootloaderCDC.txt
  72. +239 −0 third-party/LUFA100513/Bootloaders/CDC/Descriptors.c
  73. +146 −0 third-party/LUFA100513/Bootloaders/CDC/Descriptors.h
  74. +1,564 −0 third-party/LUFA100513/Bootloaders/CDC/Doxygen.conf
  75. +106 −0 third-party/LUFA100513/Bootloaders/CDC/LUFA CDC Bootloader.inf
  76. +713 −0 third-party/LUFA100513/Bootloaders/CDC/makefile
  77. +699 −0 third-party/LUFA100513/Bootloaders/DFU/BootloaderDFU.c
  78. +207 −0 third-party/LUFA100513/Bootloaders/DFU/BootloaderDFU.h
  79. +90 −0 third-party/LUFA100513/Bootloaders/DFU/BootloaderDFU.txt
  80. +181 −0 third-party/LUFA100513/Bootloaders/DFU/Descriptors.c
  81. +172 −0 third-party/LUFA100513/Bootloaders/DFU/Descriptors.h
  82. +1,564 −0 third-party/LUFA100513/Bootloaders/DFU/Doxygen.conf
  83. +715 −0 third-party/LUFA100513/Bootloaders/DFU/makefile
  84. +25 −0 third-party/LUFA100513/Bootloaders/makefile
  85. +148 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioInput/AudioInput.c
  86. +87 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioInput/AudioInput.h
  87. +83 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioInput/AudioInput.txt
  88. +314 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioInput/Descriptors.c
  89. +82 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioInput/Descriptors.h
  90. +1,564 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioInput/Doxygen.conf
  91. +737 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioInput/makefile
  92. +201 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioOutput/AudioOutput.c
  93. +75 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioOutput/AudioOutput.h
  94. +96 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioOutput/AudioOutput.txt
  95. +314 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioOutput/Descriptors.c
  96. +82 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioOutput/Descriptors.h
  97. +1,564 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioOutput/Doxygen.conf
  98. +738 −0 third-party/LUFA100513/Demos/Device/ClassDriver/AudioOutput/makefile
  99. +381 −0 third-party/LUFA100513/Demos/Device/ClassDriver/DualVirtualSerial/Descriptors.c
  100. +102 −0 third-party/LUFA100513/Demos/Device/ClassDriver/DualVirtualSerial/Descriptors.h
  101. +1,564 −0 third-party/LUFA100513/Demos/Device/ClassDriver/DualVirtualSerial/Doxygen.conf
  102. +192 −0 third-party/LUFA100513/Demos/Device/ClassDriver/DualVirtualSerial/DualVirtualSerial.c
  103. +76 −0 third-party/LUFA100513/Demos/Device/ClassDriver/DualVirtualSerial/DualVirtualSerial.h
  104. +85 −0 third-party/LUFA100513/Demos/Device/ClassDriver/DualVirtualSerial/DualVirtualSerial.txt
  105. +106 −0 third-party/LUFA100513/Demos/Device/ClassDriver/DualVirtualSerial/LUFA DualVirtualSerial.inf
  106. +738 −0 third-party/LUFA100513/Demos/Device/ClassDriver/DualVirtualSerial/makefile
  107. +240 −0 third-party/LUFA100513/Demos/Device/ClassDriver/GenericHID/Descriptors.c
  108. +72 −0 third-party/LUFA100513/Demos/Device/ClassDriver/GenericHID/Descriptors.h
  109. +1,564 −0 third-party/LUFA100513/Demos/Device/ClassDriver/GenericHID/Doxygen.conf
  110. +172 −0 third-party/LUFA100513/Demos/Device/ClassDriver/GenericHID/GenericHID.c
  111. +80 −0 third-party/LUFA100513/Demos/Device/ClassDriver/GenericHID/GenericHID.h
  112. +75 −0 third-party/LUFA100513/Demos/Device/ClassDriver/GenericHID/GenericHID.txt
  113. +739 −0 third-party/LUFA100513/Demos/Device/ClassDriver/GenericHID/makefile
  114. +250 −0 third-party/LUFA100513/Demos/Device/ClassDriver/Joystick/Descriptors.c
  115. +69 −0 third-party/LUFA100513/Demos/Device/ClassDriver/Joystick/Descriptors.h
  116. +1,564 −0 third-party/LUFA100513/Demos/Device/ClassDriver/Joystick/Doxygen.conf
  117. +180 −0 third-party/LUFA100513/Demos/Device/ClassDriver/Joystick/Joystick.c
  118. +93 −0 third-party/LUFA100513/Demos/Device/ClassDriver/Joystick/Joystick.h
  119. +73 −0 third-party/LUFA100513/Demos/Device/ClassDriver/Joystick/Joystick.txt
  120. +739 −0 third-party/LUFA100513/Demos/Device/ClassDriver/Joystick/makefile
  121. +257 −0 third-party/LUFA100513/Demos/Device/ClassDriver/Keyboard/Descriptors.c
  122. +70 −0 third-party/LUFA100513/Demos/Device/ClassDriver/Keyboard/Descriptors.h
Sorry, we could not display the entire diff because too many files (942) changed.
358 README.html
@@ -0,0 +1,358 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+
+<head>
+<style type="text/css"><!--
+body,td,a,p{font-family:Optima,Verdana,arial,sans-serif;text-align:justify}
+/*body,td,a,p{text-align:justify}*/
+body{line-height:1.5;margin-left:3.5em;margin-right:2em; max-width:50em;
+ background-color: #ffffff; color: #000000}
+h1,h2,h3,h4{font-family:helvetica,sans-serif;text-align:left}
+#box{float:right;border:thin solid #000000;
+ margin:1em;padding:1em;width:20em}
+#box li{display:block}
+#box p{text-align:center}
+.littler{ font-size: smaller; }
+.little{ font-size: small; }
+
+table { border-collapse:collapse; margin:1em}
+td { border:thin solid #000000; padding:4px; font-family:monospace}
+th { background-color:#BBBBBB; color:white; border:thin solid #000000; padding:4px; }
+//-->
+</style>
+<title>Bus Ninja</title>
+</head>
+
+<body>
+
+<div id="box">
+<p>
+<b><a href="../busninja-1.0.tar.gz">Download bus-ninja-1.0.tar.gz</a><br></b>
+<b><a href="precompiled/ninja-arduino-diecemilia-atmega168.hex">Download .HEX file for Arduino Diecemilia</a><br></b>
+<a href="src">Browse source</a><br>
+<a href="hardware">Example AT90USB162 Schematic + PCB</a><br>
+</p>
+</div>
+
+<h1>Bus Ninja</h1>
+<p>
+A <a href="http://code.google.com/p/the-bus-pirate/">Bus Pirate</a> clone for Atmel AVR microcontrollers, including the <a href="http://www.arduino.cc/">Arduino</a> and <a href="http://www.pjrc.com/teensy/">Teensy</a>. Featuring a serial console, I2C, SPI and more. On the USB enabled AVRs (AT90USBxxxx and ATMEGAxxUx) USB over serial is used, allowing for single chip Bus Ninja hardware.
+</p>
+<p>
+Bus Ninja lets you quickly protoype with I2C and SPI devices without writing any code. Just wire up a device to your board and start talking to it directly from the Bus Ninja console.
+</p>
+
+<h3>Features</h3>
+
+<ul>
+<li>Interactive shell with Bus Pirate like syntax
+<li>I2C (soft i2c driver from userial)
+<ul>
+<li>I2C address scanner ('s' command from i2c mode)
+</ul>
+<li>SPI
+<li>Flow controlled USB CDC (serial) (AT90USBxxxx/ATMEGAxxUx only)
+<li>Modular software making it straightforward to add
+<ul>
+ <li>New commands
+ <li>New buses
+ <li>New USB gadgets - mass storage EEPROM interface, HID devices, etc. (AT90USBxxxx/ATMEGAxxUx only)
+</ul>
+</ul>
+
+<h3>Core commands</h3>
+<p>
+<pre>&gt; help</pre>
+Print list of available commands
+</p>
+
+<p>
+<pre>&gt; version</pre>
+Print build string
+</p>
+
+<p>
+<pre>&gt; reset</pre>
+Reset board
+</p>
+
+<p>
+<pre>&gt; spi</pre>
+Enter SPI bus mode
+</p>
+
+<p>
+<pre>&gt; i2c</pre>
+Enter i2c bus mode
+</p>
+
+<p>
+<pre>&gt; led &lt;0-6&gt;</pre>
+Set LED pattern
+</p>
+
+
+<h3>Wiring</h3>
+<p>
+When connecting up I2C and SPI devices, signals should be connected the pins below. For Teensy, use the AT90USBxxxx variants.
+</p>
+
+<p>
+<table>
+<tr><th>Function</th><th>Arduino pin</th><th>AT90USBxxxx/ATMEGAxxUx pin</th</tr>
+<tr><td>I2C SDA</td><td>Analog 4 (PORTC4)</td><td>PORTB2</td></tr>
+<tr><td>I2C SCL</td><td>Analog 5 (PORTC5)</td><td>PORTB1</td></tr>
+<tr><td>SPI CLK</td><td>Digital 13 (PORTB5)</td><td>PORTB1</td></tr>
+<tr><td>SPI MISO</td><td>Digital 12 (PORTB4)</td><td>PORTB3</td></tr>
+<tr><td>SPI MOSI</td><td>Digital 11 (PORTB3)</td><td>PORTB2</td></tr>
+<tr><td>SPI CS</td><td>Digital 9 (PORTB1)</td><td>PORTB4</td></tr>
+<tr><td>LED</td><td>Digital 2 (PORTD2)</td><td>PORTD4</td></tr>
+</table>
+</p>
+
+
+<h3>Bus commands</h3>
+Once a bus mode is selected (i2c/spi), bus commands can be sent. See the <a href="http://dangerousprototypes.com/bus-pirate-manual/#syntax">Bus Pirate manuals</a> for more details:
+
+Eg.
+
+<pre>
+&gt; spi
+&gt; [0x40 0x0A 0x28]
+CS ENABLED
+WRITE: 0x40
+WRITE: 0x0A
+WRITE: 0x28
+CS DISABLED
+</pre>
+
+(see also the command examples in the <a href="test">test/</a> directory)
+
+
+<h3>Arduino Examples</h3>
+
+<h4>Controlling an LED</h4>
+To prove that the Bus Ninja software is working on your Arduino, start by controlling an LED. Connect the anode of your LED to digital pin 2 and the cathode to ground (it would be wise to also add a current limiting resistor in series, say 220R).
+
+Connect to the Arduino's serial port with your favourite terminal emulator at 8-N-1 9600bps.
+
+<pre>
+screen /dev/ttyUSB0 9600
+</pre>
+
+Type <cite>led</cite> followed by an integer from 0-6 to set the LED fade pattern.
+
+<h4>Controlling a Microchip MCP23S17 SPI 16-bit I/O expander</h4>
+<p>
+<img src="test/spi/MCP23S17-breadboard.jpg">
+&nbsp;
+<img src="test/spi/MCP23S17-pinout.png">
+</p>
+<p>
+Wire the chip to the Arduino like this:
+
+<table>
+<tr><th>MCP23S17</th><th>Arduino</th></tr>
+<tr><td>VDD</td><td>5V</td></tr>
+<tr><td>VSS</td><td>GND</td></tr>
+<tr><td>SO</td><td>SPI MISO (Digital 12)</td></tr>
+<tr><td>SI</td><td>SPI MOSI (Digital 11)</td></tr>
+<tr><td>CS</td><td>SPI CS (Digital 9)</td></tr>
+<tr><td>SCK</td><td>SPI CLK (Digital 13)</td></tr>
+<tr><td>Reset</td><td>5V</td></tr>
+</table>
+
+<p>
+Connect an LED, voltmeter or oscilloscope to GPA0. Then, open the Bus Ninja serial console and enter commands.
+</p>
+
+Enter SPI mode<br>
+<pre>
+spi
+</pre>
+
+Initialise the chip for non-sequential access<br>
+<pre>
+[0x40 0x0A 0x28] # WR_REG(0) IOCONA SEQ_OFF|HAEN
+</pre>
+
+Set all of PORTA as outputs<br>
+<pre>
+[0x40 0x00 0x00] # WR_REG(0) GPIOADIR ALL_OUTPUT
+</pre>
+
+Set GPIOA-0 high<br>
+<pre>
+[0x40 0x12 0x01] # WR_REG(0) GPIOA GPIOA-0
+</pre>
+
+Set GPIOA-0 low<br>
+<pre>
+[0x40 0x12 0x00] # WR_REG(0) GPIOA GPIOA-0
+</pre>
+</p>
+
+
+<h4>Controlling a Microchip 24LC16B I2C EEPROM</h4>
+<p>
+<img src="test/i2c/24LC16B-breadboard.jpg">
+&nbsp;
+<img src="test/i2c/24LC16B-pinout.png">
+</p>
+<p>
+Wire the chip to the Arduino like this:
+
+<table>
+<tr><th>24LC16B</th><th>Arduino</th></tr>
+<tr><td>VCC</td><td>5V</td></tr>
+<tr><td>VSS</td><td>GND</td></tr>
+<tr><td>SDA</td><td>I2C SDA (Analog 4)</td></tr>
+<tr><td>SI</td><td>I2C SCL (Analog 5)</td></tr>
+<tr><td>Reset</td><td>5V</td></tr>
+</table>
+
+<p>
+<b>For I2C to properly function you must add two pullup resistors. One from SDA to 5V, one from SCL to 5V.</b>
+</p>
+
+Enter I2C mode<br>
+<pre>
+i2c
+</pre>
+
+Write {0x10, 0x20, 0x30, 0x40} at address 0x0000<br>
+<pre>
+[0xA6 0 0 0x10 0x20 0x30 0x40]
+</pre>
+
+Set the read pointer to address 0x0000<br>
+<pre>
+[0xA6 0 0]
+</pre>
+
+Read back your 4 bytes<br>
+<pre>
+[0xA7 r:4]
+</pre>
+
+
+<h3>Building the code</h3>
+Edit config.mk and change PROGRAM_CMD for your system.
+<br>
+To build and flash to Arduino Diecemilia (atmega168):<br>
+<pre>
+ cd src &amp;&amp; make BOARD=ARDUINO clean &amp;&amp; make BOARD=ARDUINO &amp;&amp; make BOARD=ARDUINO program
+</pre>
+<br>
+To build for Teensy 1.0 (at90usb162):<br>
+<pre>
+ cd src &amp;&amp; make BOARD=TEENSY clean &amp;&amp; make BOARD=TEENSY &amp;&amp; make BOARD=TEENSY program
+</pre>
+
+
+<h3>Supported Hardware</h3>
+<b>Known working:</b>
+<p>
+<a href="http://www.arduino.cc/en/Main/ArduinoBoardDiecimila">Arduino Diecemilia</a><br>
+<a href="http://www.pjrc.com/teensy/schematic.html">Teensy 1.0</a><br>
+<a href="http://blog.hodgepig.org/articles/000006-flatworm/index.html">Flatworm</a><br>
+</p>
+
+<b>Very likely to work:</b>
+(even more likely if you donate hardware...)
+<p>
+<a href="http://www.arduino.cc/en/Main/ArduinoBoardDuemilanove">Arduino Duemilanove</a><br>
+Arduino Mega<br>
+<a href="http://www.pjrc.com/store/teensy.html">Teensy 2.0</a><br>
+<a href="http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3879">AT90USBKEY</a><br>
+<a href="http://code.google.com/p/micropendous/">Micropendous</a><br>
+<a href="http://fletchtronics.net/bumble-b">Bumble-b</a><br>
+</p>
+
+
+<h3>FAQ</h3>
+
+<p>
+Q. Why is it called Bus Ninja?
+<br>
+A. Because Ninjas are better than Pirates and Yarrrrrduino sounds silly.
+</p>
+
+<p>
+Q. What hardware does Bus Ninja run on?
+<br>
+A. It was originally developed on Teensy1 (AT90USB162), then later ported to Arduino (ATMega168). Adding support for other AVRs should just be a matter of changing the definitions in config.mk.
+</p>
+
+<p>
+Q. Why do I lose characters when I paste to the Arduino?
+<br>
+A. The Arduino serial port isn't flow controlled, use the USB version of Bus Ninja
+</p>
+
+<p>
+Q. How do I port Bus Ninja to my custom AVR/Arduino board?
+<br>
+A. Edit config*.mk, setup FCPU, MCU, LED PORT/PIN and desired features.
+</p>
+
+<p>
+Q. Why aren't you using LUFA's scheduler/task framework?
+<br>
+A. Bus Ninja needs to remain portable to other stacks and processors, so it doesn't use LUFA's application framework.
+</p>
+
+<p>
+Q. How do I add a new command?
+<br>
+A. Use the macros DECLARE_COMMAND(mycmd), ADD_COMMAND(mycmd) and DEFINE_COMMAND(mycmd) in global_commands.c
+</p>
+
+<p>
+Q. How do I add a new bus?
+<br>
+A. Declare a bus_interface_t, provide handlers for the methods, enable it with bus_init(&my_bus). See bus_spi.[ch]. The buses are enabled by a command in global_commands.c
+</p>
+
+<p>
+Q. How do I disable a feature?
+<br>
+A. Edit config.mk, comment out unused features.
+</p>
+
+<p>
+Q. Why isn't the LED command hooked up to the on-board LED on Arduino?
+<br>
+A. The LED is on the SPI CLK line, so is needed for SPI.
+</p>
+
+<p>
+Q. Why clone the Bus Pirate?
+<br>
+A. To get to a single chip Bus Pirate work-a-like with a free software toolchain.
+</p>
+
+
+<h3>License and acknowledgements</h3>
+<p>
+Unless otherwise stated, everything is licensed under <a href="http://creativecommons.org/publicdomain/zero/1.0/">CC-0</a>.
+</p>
+<p>
+Bus Ninja also contains code from:<br>
+LUFA (Dean Camera)<br>
+userial (Thomas Pircher)<br>
+estick-jtag/opendous-jtag (Cahya Wirawan, Vladimir Fonov, Dean Camera, Denver Gingerich)
+</p>
+
+<p>
+Although Bus Ninja shares no code with the Bus Pirate project, it wouldn't exist without it. Thanks.
+</p>
+
+<hr>
+For suggestions, hardware donations and patches, contact:<br>
+Joby Taffey &lt;jrt@hodgepig.org&gt;
+
+</body>
+
+
+</html>
4 hardware/README
@@ -0,0 +1,4 @@
+Schematic and board layout for a surface mount AT90USB162 board to fit a breadboard.
+
+Use at your own risk.
+
BIN  hardware/ninja.brd
Binary file not shown
BIN  hardware/ninja.sch
Binary file not shown
322 precompiled/ninja-arduino-diecemilia-atmega168.hex
@@ -0,0 +1,322 @@
+:1000000012C100002CC100002AC1000028C100005C
+:1000100026C1000024C1000022C1000020C1000050
+:100020001EC100001CC100001AC1000018C1000060
+:1000300016C1000014C1000012C1000010C1000070
+:1000400071C500000CC100000AC1000008C1000019
+:1000500006C1000004C1000002C1000000C1000090
+:10006000FEC00000FCC000004E4F00493243205249
+:100070004541443A200049324320535441525420D0
+:10008000434F4E444954494F4E004E41434B004E5E
+:100090004F005945530020474F542041434B3A20CD
+:1000A000004932432057524954453A20005945539C
+:1000B000004E4F0020474F542041434B3A20004907
+:1000C00032432057524954453A2000493243205385
+:1000D0005441525420434F4E444954494F4E0049D5
+:1000E00032432053544F5020434F4E444954494FBC
+:1000F0004E004E4F0049324320524541443A2000C1
+:100100004932432053544F5020434F4E44495449A1
+:100110004F4E004E4F005945530020474F54204149
+:10012000434B3A20004932432057524954453A2024
+:10013000004932432053544F5020434F4E444954BA
+:10014000494F4E004F4B004E41434B004932432034
+:100150004F50454E00524541443A203078005752A6
+:100160004954453A20307800435320444953414292
+:100170004C454400435320454E41424C4544008D7C
+:1001800001910195019C01A301AA01C30101FF0096
+:100190000001FFFFFF02FF0000FFFFFF0220000041
+:1001A00020FFFF02FF000010FFFF081080D910D9C8
+:1001B000FF10FFD910D980108027102700100027CA
+:1001C0001027800240FF804080FF3E200042616493
+:1001D000436D64004572726F720076657273696F69
+:1001E0006E0068656C70006C6564007265736574A0
+:1001F000007370690069326300DA011B09E201E3F0
+:1002000008E701B508EB01B208F101AD08F501A856
+:1002100008000000003037303731304032313A3298
+:10022000392D74726A0011241FBECFEFD4E0DEBFF7
+:10023000CDBF11E0A0E0B1E0E4EEF3E102C0059033
+:100240000D92A032B107D9F711E0A0E2B1E001C0F0
+:100250001D92A038B107E1F77AD20C94F009D0CE04
+:10026000FB01DC0104C08D910590801921F44150FF
+:100270005040C8F7881B990B0895FB01DC0102C0B0
+:1002800005900D9241505040D8F70895FC0105901B
+:100290000020E9F7809590958E0F9F1F089587E6BF
+:1002A00090E09093C5008093C40088E18093C100E2
+:1002B00008951F93182F01C03CD38091C00085FF83
+:1002C000FBCF1093C6001F9108958091C00087FF57
+:1002D00003C08091C60043C508953C983D9844985A
+:1002E00045981092200108950895F89485E3982F79
+:1002F0009A95F1F73D9A3C9A982F9A95F1F73D9887
+:100300008A95F1F73C9810922001789480EA9FE05A
+:100310000197F1F70895F89420E035E3932F9A952B
+:10032000F1F787FF02C03C9801C03C9A3D98932F9B
+:100330009A95F1F73D9A2F5F283011F0880FEECF94
+:10034000789408951F93F89485E38A95F1F73C9883
+:100350003D9815E3812F8A95F1F7EBD2359BFACFC3
+:1003600086B195E39A95F1F73D9A789490E024E070
+:10037000969587952A95E1F781701F910895AF9220
+:10038000BF92CF92DF92EF92FF920F931F93CF9382
+:10039000DF937C01D62EF894B42EAA2435E3C32E25
+:1003A00022C08B2D9A2DEC0110E000E0CBDF110F65
+:1003B000182B0F5F0830D1F7F70110838C2D8A9529
+:1003C000F1F7CC2311F03C9A01C03C980894E11C51
+:1003D000F11C8C2D8A95F1F73D988C2D8A95F1F7BB
+:1003E0003D9A3C98DA94DD2031F0F1E0FD15C8F635
+:1003F000C1E0D0E0D9CF789481E0DF91CF911F9117
+:100400000F91FF90EF90DF90CF90BF90AF90089545
+:100410001F93CF93DF93EC01162FF89490E007C061
+:10042000899179DF8FDF811181E0982F115011239D
+:1004300011F09923A9F3789481E08927DF91CF9176
+:100440001F910895282FF89495E3892F8A95F1F745
+:1004500080912001882341F03C98892F8A95F1F7FB
+:100460003D98892F8A95F1F73C9A85E38A95F1F7B3
+:100470003D9A81E0809320012E7F862F822B4BDFD7
+:1004800061DF90E0882309F491E0892F089580E0EE
+:1004900061E0D8DF2ACF81E08093210108951F9386
+:1004A000FC016130710519F58081833701F51FEF7B
+:1004B000612F6170812FC6DF882391F0812FECD6E8
+:1004C00088E2FAD6812F8695E7D680E2F5D610FF2E
+:1004D00002C082E501C087E5EFD689E2EDD6CED62F
+:1004E000D6DF112311F01150E3CF81E001C080E08D
+:1004F0001F910895DF93CF930F92CDB7DEB7809110
+:100500002101823019F0843039F510C06091220148
+:10051000862F617097DF882321F4B9DF8AE890E0A5
+:1005200015C086E790E0B0D684E012C08BE690E07C
+:10053000ABD6CE01019661E041E021DF882319F0BE
+:100540008981C2D607C0A3DF88E690E09DD685E00A
+:100550008093210193D604C09ADF85E08093210126
+:100560000F90CF91DF9108951F93182F8091210153
+:10057000823049F0833031F1813009F041C010936D
+:10058000220182E03FC08BEC90E07ED677D68FEBE5
+:1005900090E07AD6809122017FD684EB90E074D6E9
+:1005A00060912201862F61704DDF882321F46FDF77
+:1005B00081EB90E01FC08DEA90E066D61093220197
+:1005C00083E01AC081EA90E05FD68091220164D670
+:1005D00086E990E059D682E291E061E019DF882354
+:1005E00031F082E990E050D61093220107C04FDF2E
+:1005F0008FE890E049D685E0809321013FD604C082
+:1006000046DF85E0809321011F910895DF93CF930A
+:100610000F92CDB7DEB7809121018330B9F08430DD
+:1006200079F1823009F042C060912201862F617019
+:1006300009DF882319F487E491E002C084E491E0A3
+:1006400023D61CD652DE81E391E02EC085E291E0F4
+:100650001BD68091220120D68AE191E015D682E254
+:1006600091E061E0D5DE882319F086E191E002C0D7
+:1006700083E191E009D602D638DE80E091E014C033
+:1006800085EF90E001D6CE01019661E040E077DE93
+:10069000882319F0898118D603C082EF90E0F4D541
+:1006A000EDD523DE8FED90E0EFD5E8D51092210156
+:1006B0000F90CF91DF91089517CE08958CE491E0CB
+:1006C000E3D5DCD51092210108DEE1CE219A299AEA
+:1006D00084B18C6284B92C9A83E58CBD8DB58EB5BE
+:1006E00008958CB58F7B8CBD08958EBD0DB407FE2B
+:1006F000FDCF8EB5089580E008951F938FEFF5DF4D
+:10070000182F85E591E0C0D5812FDED5B7D51F9193
+:100710000895299A88E691E0B7D5B0C5299884E76D
+:1007200091E0B2D5ABC51F93182FDFDF8EE591E0C6
+:10073000ABD5812FB9D5A2D51F910895D2CF0895F9
+:10074000C5CF0895F6D0C1DD4DD3E1D187C10ED01C
+:10075000E1D0529AA4DDD0D17ED131D285E06CD1E6
+:1007600080E090E06ED57894EDDFFECF80E090E001
+:1007700020E80FB6F89420936100809361000FBECB
+:10078000089528E088E190E00FB6F894A89580934A
+:1007900060000FBE20936000FFCFCF92DF92EF92F8
+:1007A000FF920F931F93CF93DF93C62E7A01FA0126
+:1007B0001082118212821382EC012AE0D22E00E014
+:1007C00049C09881F70120813181428153812115EF
+:1007D000310541055105D1F40230C0F4923631F4AF
+:1007E000F1E0FC15E0F592E0D92E32C0002331F49F
+:1007F000983661F481E08C1548F131C0013031F454
+:10080000983721F4E2E0EC1508F129C0913610F098
+:1008100087E509C0913410F087E305C09A3310F0E2
+:1008200080E001C080E3192F181B1D15C0F46D2D49
+:1008300070E080E090E06CD5610F711D811D911D0D
+:10084000F701608371838283938302C080E1D82E95
+:100850000F5F21960C1508F4B4CF81E001C080E051
+:10086000DF91CF911F910F91FF90EF90DF90CF908C
+:100870000895CF93DF93EC01DB0108C080818032C3
+:1008800011F0893079F43196F983E883E881F981B0
+:10089000E417F50799F706C08081803261F089304E
+:1008A00051F031961196FC93EE93ED91FC911197D6
+:1008B000E417F50789F720E088819981E817F9079F
+:1008C00009F021E0822FDF91CF910895EF92FF92FE
+:1008D0000F931F93CF93DF93EC018B017901C9DF55
+:1008E000882381F08881F8016081681B9981A701C4
+:1008F00054DF882339F0F8018081918199838883BE
+:1009000081E001C080E0DF91CF911F910F91FF90B6
+:10091000EF90089584B7886084BF29E088E190E073
+:100920000FB6F894A895809360000FBE20936000E6
+:100930000895A89508958093000108959B01AC0146
+:10094000307040705070283031054105510579F103
+:10095000293031054105510580F42130310541052B
+:100960005105B0F1233031054105510500F1243026
+:1009700031054105510561F51AC0203231054105A7
+:100980005105A9F0213231054105510530F42031DE
+:10099000310541055105E1F40AC020343105410516
+:1009A000510529F0203831054105510589F4809120
+:1009B000000190E0A0E0B0E0282339234A235B2324
+:1009C000211531054105510511F05A9A08955A989B
+:1009D000089510922A014091280150912901FA01AD
+:1009E00064918091270190E09C01220F331F280F12
+:1009F000391FF9013196E40FF51FE491E0932F01BF
+:100A0000109230012E5F3F4FFA01E20FF31FE49185
+:100A1000E0932B0110922C012F5F3F4F420F531F89
+:100A2000FA01249120932D0110922E01019670E07D
+:100A3000A2D4809327010895E82FF0E0EE0FFF1F66
+:100A4000E158FE4F8591949190932901809328015C
+:100A500010922701BECF80E0EFDFBBCF20912301B2
+:100A60003091240140912501509126012617370726
+:100A70004807590708F03FC080912A01482F50E0ED
+:100A800060912F01709130014617570710F0A1DFD8
+:100A900025C09B01241B350B80912B0190912C01CB
+:100AA000FC012E9FC0012F9F900D3E9F900D1124A1
+:100AB00020912D0130912E01F9014E9F90014F9F01
+:100AC000300D5E9F300D1124820F931F40D4862F6E
+:100AD00032DF80912A018F5F80932A0118D06C50F9
+:100AE0007F4F8F4F9F4F609323017093240180931A
+:100AF000250190932601089585B5816085BDA89A4A
+:100B000016BCEEE6F0E0808181608083089520913C
+:100B10003101309132014091330150913401B901DA
+:100B2000CA0108951F920F920FB60F9211242F93AE
+:100B30003F934F935F936F937F938F939F93AF9365
+:100B4000BF93EF93FF938091310190913201A09177
+:100B50003301B09134010196A11DB11D8093310183
+:100B600090933201A0933301B0933401609131012D
+:100B7000709132018091330190913401DFDEFF9159
+:100B8000EF91BF91AF919F918F917F916F915F9105
+:100B90004F913F912F910F900FBE0F901F9018957E
+:100BA00080933B01882319F0813041F405C01092F5
+:100BB0003C0110923801089510923901089580E0A7
+:100BC000EFCF8A3010F4805D0895895C08951F93FB
+:100BD000182F80913501882351F4812F6ADBE09131
+:100BE0003601F0913701309711F0812F09951F914F
+:100BF00008951F93182F82E6EADF17FF02C081E3F2
+:100C000001C080E3E4DF16FF02C081E301C080E39E
+:100C1000DEDF15FF02C081E301C080E3D8DF14FFEF
+:100C200002C081E301C080E3D2DF13FF02C081E391
+:100C300001C080E3CCDF12FF02C081E301C080E38A
+:100C4000C6DF11FF02C081E301C080E3C0DF10FFF7
+:100C500002C081E301C080E3BADF1F9108959F9233
+:100C6000AF92BF92CF92DF92EF92FF920F931F93BA
+:100C7000CF93DF93D62EA72EB82EC92EE12C8AEC67
+:100C8000F82E8AE9082F8BE3182F99249394C0E05B
+:100C9000D0E06D2D7A2D8B2D9C2DA80197017ED350
+:100CA000C901DA010097A105B10511F0992402C02C
+:100CB000992011F486DF8BDF6D2D7A2D8B2D9C2DE5
+:100CC000A80197016BD3D62EA72EB82EC92EC80126
+:100CD000B7012AE030E040E050E060D3C901DA011A
+:100CE0007C018D012196C930D10599F68D2D69DFE2
+:100CF0006EDFDF91CF911F910F91FF90EF90DF900A
+:100D0000CF90BF90AF909F9008951F93182F82951A
+:100D10008F7057DF5CDF812F8F7053DF58DF1F919B
+:100D200008951F93182F80E352DF88E750DF812F4B
+:100D3000ECDF1F910895CF93DF93EC0104C021965F
+:100D4000F901849144DF9E01FE0184918823B9F763
+:100D5000DF91CF9108958DE03ADF8AE038CF1F937D
+:100D6000182F80913B01882339F08130C9F5809399
+:100D7000390110933A0134C080913801882381F5FC
+:100D80001D3029F01F3741F0183099F405C081E07B
+:100D900080933801E0DF24C080913C01882301F179
+:100DA000815080933C0188E012DF80E210DF88E010
+:100DB00016C080913C018F3388F480910101882313
+:100DC00011F0812F04DF80913C01E82FF0E0E35C1B
+:100DD000FE4F10838F5F80933C0102C087E0F7DEF7
+:100DE0001F91089580913B01882399F480913801E7
+:100DF000882379F060913C01662321F08DE391E036
+:100E000070E025D110923C018AEC91E094DF1092C1
+:100E1000380108954F925F926F927F928F929F92C6
+:100E2000AF92BF92CF92DF92EF92FF920F931F93F8
+:100E3000DF93CF93CDB7DEB72C970FB6F894DEBF14
+:100E40000FBECDBF6C014B01A42E290181E090E0C3
+:100E5000A0E0B0E08D839E83AF83B8870894C11C67
+:100E6000D11CB62EBC180894C108D108760100E048
+:100E700010E095E0692E712C6C0E7D1E18C0F701F4
+:100E800080818A3371F4101611065CF4C701019653
+:100E90006B2DA30182DC882369F41D821E821F82D0
+:100EA00018860894E11CF11C0F5F1F4FBA94E814D8
+:100EB000F90429F76E2D6C19C601AE014F5F5F4F23
+:100EC0006CDC882339F1E0917D01F0917E0130974F
+:100ED00009F4A1C080859185892B91F49CC0E09193
+:100EE0007D01F0917E010084F185E02D8981215002
+:100EF0003040404050402D833E834F8358870995B2
+:100F00002D813E814F8158852115310541055105BF
+:100F100031F785C047018C189D08F1E08F169104C8
+:100F200051F5F6018081823711F0823521F5E0918B
+:100F30007D01F0917E01309709F46DC08285938523
+:100F4000892B81F468C0E0917D01F0917E010284DB
+:100F5000F385E02D0197A109B1098D839E83AF83AD
+:100F6000B88709958D819E81AF81B8850097A105CD
+:100F7000B10549F754C0AA2009F439C08E01075FB2
+:100F80001F4FC80169EF71E044E050E076D989EF66
+:100F9000A82E81E0B82E702E012F24C0C601B70103
+:100FA000A4015ED9892BA1F4C70170D988169906CE
+:100FB00078F0EB85FC85C601880D991DB201099575
+:100FC000882321F484ED91E0B6DEC5DE81E028C0FF
+:100FD00084E090E0A80EB91E872D902FB50144E063
+:100FE00050E04BD9E984FA84E114F104B9F6E091B8
+:100FF0007D01F0917E01309771F00484F585E02D3C
+:10100000309749F02D813E814F815885C601B4014A
+:101010000995882321F48DEC91E08DDE9CDE80E043
+:101020002C960FB6F894DEBF0FBECDBFCF91DF91E7
+:101030001F910F91FF90EF90DF90CF90BF90AF90F6
+:101040009F908F907F906F905F904F900895DF9268
+:10105000EF92FF920F931F93CF93DF93EC018B01DD
+:10106000080F191FD82EED2EFF2441E05CC0FF2091
+:1010700021F091E0F916D9F735C08B35D9F08C35D0
+:1010800070F4833209F45CC0843230F4893009F49E
+:1010900049C0803251F446C08C3239F443C08B379A
+:1010A00049F08D3789F08D3579F0DC2EED2EFF2457
+:1010B000F39438C0E0917D01F0917E01309781F08A
+:1010C0000480F581E02D09C0E0917D01F0917E0161
+:1010D000309731F00680F781E02D309709F00995BF
+:1010E00040E020C08B35A1F08C3560F4833281F074
+:1010F000843228F4893061F08032A1F409C08C3246
+:1011000089F406C08B3721F08D3711F08D3551F4FD
+:101110008D2D9E2DBE0198017DDE882389F4FF244C
+:1011200040E001C02196C017D10711F088819FCF00
+:1011300081E0F81629F48D2D9E2DBE019E016ADEF8
+:10114000DF91CF911F910F91FF90EF90DF90089565
+:1011500083E091E076D081E0089581E191E071D063
+:1011600081E008950EDB81E00895DF93CF93CDB742
+:10117000DEB728970FB6F894DEBF0FBECDBF9887B5
+:101180008F83AB01CE010796BE016F5F7F4F9E013B
+:101190002D5F3F4F9BDB882361F08B819C81AD816C
+:1011A000BE8187309105A105B10518F445DC81E0C9
+:1011B00001C080E028960FB6F894DEBF0FBECDBF09
+:1011C000CF91DF910895DF92EF92FF920F931F93DB
+:1011D000DF93CF9300D000D0CDB7DEB78E010F5F85
+:1011E0001F4FC80169EF71E044E050E046D889EF35
+:1011F000E82E81E0F82ED02E012F0CC09CDDABDD57
+:1012000084E090E0E80EF91E8D2D902FB70144E0A8
+:1012100050E033D889819A81009781F781E00F905F
+:101220000F900F900F90CF91DF911F910F91FF9032
+:10123000EF90DF90089585E192E07DDD8CDD81E027
+:101240000895CF93DF93EC01E0917D01F0917E0151
+:10125000309731F00280F381E02D309709F0099545
+:10126000D0937E01C0937D01209729F0E881F98118
+:10127000309709F00995DF91CF910895809102018F
+:10128000882309F068CD08959C018091020188238C
+:1012900011F0C90150CD0895982F80910201882343
+:1012A00011F0892F3ECD0895982F80910201882357
+:1012B00011F0892F2ACD0895982F8091020188235B
+:1012C00011F0892F84CC089520917F01223071F094
+:1012D000233028F42223A1F0213099F405C02330D3
+:1012E00039F0243071F40AC072DC0BC082DC09C012
+:1012F000682F70E080E090E0B2DC03C006DD01C042
+:1013000010DD80910201882311F480E260CC089501
+:10131000629FD001739FF001829FE00DF11D649FD9
+:10132000E00DF11D929FF00D839FF00D749FF00D65
+:10133000659FF00D9927729FB00DE11DF91F639F06
+:10134000B00DE11DF91FBD01CF0111240895AA1BA5
+:10135000BB1B51E107C0AA1FBB1FA617B70710F0A0
+:10136000A61BB70B881F991F5A95A9F780959095D2
+:10137000BC01CD01089597FB092E07260AD077FD01
+:1013800004D0E5DF06D000201AF4709561957F4FF8
+:101390000895F6F7909581959F4F0895A1E21A2E32
+:1013A000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1F09
+:1013B000A217B307E407F50720F0A21BB30BE40B59
+:1013C000F50B661F771F881F991F1A9469F76095A0
+:1013D0007095809590959B01AC01BD01CF0108955A
+:0413E000F894FFCFAF
+:1013E400FF01015E035C034B020603B4027A024F61
+:1013F40002A0039E038E03890393037D037B0300F2
+:00000001FF
81 src/Makefile
@@ -0,0 +1,81 @@
+ifeq ($(BOARD),ARDUINO)
+include config-arduino.mk
+else
+ifeq ($(BOARD),TEENSY)
+include config-teensy.mk
+else
+# Default to arduino
+include config-arduino.mk
+endif
+endif
+
+include rules.mk
+
+TARGET=ninja
+
+CC=avr-gcc
+SIZE=avr-size
+OBJCOPY=avr-objcopy
+
+F_CLOCK = $(F_CPU)
+
+CFLAGS += -DVERSION_STR="\"$(shell date +"%d%m%y@%H:%M")-$(shell whoami)\""
+
+SRCS += $(TARGET).c \
+ cpu.c \
+ parse.c \
+ watchdog.c \
+ hw_led.c \
+ led.c \
+ tick.c \
+ console.c \
+ commands.c \
+ global_commands.c \
+ bus.c \
+ menu.c \
+
+LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
+LDFLAGS += -Wl,--relax
+LDFLAGS += -Wl,--gc-sections
+
+CFLAGS += -Os -mmcu=$(MCU) -Wall -DF_CPU=$(F_CPU) -DF_CLOCK=$(F_CLOCK)
+CFLAGS += -funsigned-char
+CFLAGS += -funsigned-bitfields
+CFLAGS += -ffunction-sections
+CFLAGS += -fdata-sections
+CFLAGS += -fpack-struct
+CFLAGS += -fshort-enums
+CFLAGS += --param inline-call-cost=2
+CFLAGS += -finline-limit=3
+CFLAGS += -fno-inline-small-functions
+CFLAGS += -Wall -Werror
+
+CFLAGS += -DUSBMODE_DEFAULT=USBMODE_CDC
+
+OBJ = $(SRCS:%.c=$(OBJDIR)/%.o)
+
+OBJDIR= .
+
+MCU_FLAG = $(shell $(SIZE) --help | grep -- --mcu > /dev/null && echo --mcu=$(MCU) )
+FORMAT_FLAG = $(shell $(SIZE) --help | grep -- --format=.*avr > /dev/null && echo --format=avr )
+
+$(TARGET).hex: $(TARGET).elf
+ $(OBJCOPY) -O ihex -R .eeprom $(TARGET).elf $(TARGET).hex
+ $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O ihex $(TARGET).elf $(TARGET).eep || exit 0
+
+$(OBJDIR)/%.o : %.c
+ $(CC) -c $(CFLAGS) $< -o $@
+
+
+$(TARGET).elf: $(OBJ)
+ $(CC) $(CFLAGS) $^ --output $@ $(LDFLAGS)
+ $(SIZE) $@
+ $(SIZE) $(MCU_FLAG) $(FORMAT_FLAG) $(TARGET).elf
+
+program: $(TARGET).hex
+ $(PROGRAM_CMD)
+
+clean:
+ rm -f $(TARGET).hex $(TARGET).elf $(TARGET).eep $(TARGET).map $(OBJ)
+
+
106 src/bus.c
@@ -0,0 +1,106 @@
+#include "ninja.h"
+#include "bus.h"
+#include "console.h"
+
+const bus_interface_t *current_bus = NULL;
+static uint8_t outmode = OUTMODE_0x8; // output formatting for bus data
+static BOOL log_enabled = TRUE;
+
+/****************************************************************/
+
+void bus_init(const bus_interface_t *bus)
+{
+ if (NULL != current_bus && NULL != current_bus->close)
+ current_bus->close();
+
+ current_bus = bus;
+
+ if (NULL != bus && NULL != bus->open)
+ bus->open();
+}
+
+/****************************************************************/
+
+void bus_enable_log(BOOL enable)
+{
+ log_enabled = enable;
+}
+
+/****************************************************************/
+
+void bus_set_outmode(outmode_t mode)
+{
+ outmode = mode;
+}
+
+/****************************************************************/
+
+void bus_out(uint8_t c)
+{
+ switch(outmode)
+ {
+ case OUTMODE_ASCII:
+ console_putc(c);
+ break;
+ case OUTMODE_BIN:
+ console_putbin(c);
+ break;
+ case OUTMODE_DEC:
+ console_putdec(c);
+ break;
+ case OUTMODE_HEX8:
+ console_puthex8(c);
+ break;
+ case OUTMODE_0x8:
+ console_put0x8(c);
+ break;
+ }
+ // put a separator between bytes
+ if (!log_enabled)
+ console_putc(' ');
+}
+
+/****************************************************************/
+
+void bus_log_putc(uint8_t c)
+{
+ if (log_enabled)
+ console_putc(c);
+}
+
+void bus_log_puthex8(uint8_t c)
+{
+ if (log_enabled)
+ console_puthex8(c);
+}
+
+void bus_log_put0x8(uint8_t c)
+{
+ if (log_enabled)
+ console_put0x8(c);
+}
+
+void bus_log_puts(uint8_t *str)
+{
+ if (log_enabled)
+ console_puts(str);
+}
+
+void bus_log_puts_P(PGM_P str)
+{
+ if (log_enabled)
+ console_puts_P(str);
+}
+
+void bus_log_newline(void)
+{
+ if (log_enabled)
+ console_newline();
+}
+
+void bus_log_putdec(uint32_t i)
+{
+ if (log_enabled)
+ console_putdec(i);
+}
+
55 src/bus.h
@@ -0,0 +1,55 @@
+#ifndef BUS_H
+#define BUS_H 1
+
+#include "ninja.h"
+
+typedef struct
+{
+ void (*open)(void);
+ void (*close)(void);
+ void (*start)(void);
+ void (*stop)(void);
+ void (*write)(uint8_t c);
+ void (*read)(void);
+ BOOL (*command)(const uint8_t *start, size_t len, uint32_t repeat);
+} bus_interface_t;
+
+/*****************************************************************************/
+
+// Formatting mode for bus_out()
+typedef enum
+{
+ OUTMODE_0x8, // 2 byte hex, with 0x prefix
+ OUTMODE_ASCII, // ascii char
+ OUTMODE_BIN, // binary
+ OUTMODE_DEC, // decimal
+ OUTMODE_HEX8, // 2 byte hex
+ OUTMODE_SILENT // silent
+} outmode_t;
+
+/*****************************************************************************/
+
+extern const bus_interface_t *current_bus;
+
+/*****************************************************************************/
+
+void bus_init(const bus_interface_t *bus);
+
+/*****************************************************************************/
+
+void bus_set_outmode(outmode_t mode);
+void bus_out(uint8_t c);
+
+/*****************************************************************************/
+
+void bus_enable_log(BOOL enable);
+void bus_log_putc(uint8_t c);
+void bus_log_puthex8(uint8_t c);
+void bus_log_put0x8(uint8_t c);
+void bus_log_puts(uint8_t *str);
+void bus_log_puts_P(PGM_P str);
+void bus_log_newline(void);
+void bus_log_putdec(uint32_t i);
+
+#endif
+
33 src/bus_commands.c
@@ -0,0 +1,33 @@
+#include "ninja.h"
+#include "console.h"
+#include "bus.h"
+
+#include "bus_commands.h"
+
+need triggers for cmdline start and end
+but, that's an ugly hack
+
+static void bus_commands_write(uint8_t c)
+{
+ console_puts_P(PSTR("WRITE "));
+ console_puthex8(c);
+ console_newline();
+}
+
+static void bus_commands_command(uint8_t *start, size_t len)
+{
+ console_puts_P(PSTR("COMMAND: "));
+ while(0 != len--)
+ console_putc(*start++);
+ console_newline();
+}
+
+const bus_interface_t bus_commands =
+{
+ .start = NULL,
+ .stop = NULL,
+ .write = bus_commands_write,
+ .read = NULL,
+ .command = bus_commands_command
+};
+
236 src/bus_i2c.c
@@ -0,0 +1,236 @@
+#include "ninja.h"
+#include "console.h"
+#include "bus.h"
+#include "hw_i2c.h"
+
+#include "bus_i2c.h"
+
+/*
+ * Because all buy the last rx must have an ACK, we delay each transaction by storing the state and data
+ */
+
+enum
+{
+ STATE_INIT, // starting state
+ STATE_ADDR_PENDING, // waiting for address byte
+ STATE_START_PENDING, // send address byte, waiting for data byte
+ STATE_WRITE_DATA_PENDING, // send data byte, waiting for data byte
+ STATE_READ_DATA_PENDING, // receive data, waiting for more data
+ STATE_ERROR // null state, to stop any more bus traffic until state is reset
+};
+
+static uint8_t state;
+static uint8_t pending_data;
+
+static void bus_i2c_open(void)
+{
+ bus_log_puts_P(PSTR("I2C OPEN"));
+ bus_log_newline();
+
+ state = STATE_INIT;
+
+ hw_i2c_init();
+ hw_i2c_bus_clear();
+}
+
+static void bus_i2c_close(void)
+{
+ hw_i2c_shutdown();
+}
+
+static void bus_i2c_start(void)
+{
+ state = STATE_ADDR_PENDING;
+}
+
+static void bus_i2c_stop(void)
+{
+ uint8_t c;
+
+ switch(state)
+ {
+ case STATE_START_PENDING:
+ if (!hw_i2c_master_start(pending_data, pending_data & 0x1 ? hw_i2c_rd : hw_i2c_wr))
+ bus_log_puts_P(PSTR("NACK"));
+ else
+ bus_log_puts_P(PSTR("OK"));
+
+ bus_log_newline();
+ hw_i2c_master_stop();
+ bus_log_puts_P(PSTR("I2C STOP CONDITION"));
+ bus_log_newline();
+ break;
+
+ case STATE_WRITE_DATA_PENDING:
+ bus_log_puts_P(PSTR("I2C WRITE: "));
+ bus_log_put0x8(pending_data);
+ bus_log_puts_P(PSTR(" GOT ACK: "));
+
+ if (hw_i2c_master_tx(&pending_data, 1)) // write the last byte
+ bus_log_puts_P(PSTR("YES"));
+ else
+ bus_log_puts_P(PSTR("NO"));
+
+ bus_log_newline();
+ hw_i2c_master_stop();
+ bus_log_puts_P(PSTR("I2C STOP CONDITION"));
+ bus_log_newline();
+ break;
+
+ case STATE_READ_DATA_PENDING:
+ bus_log_puts_P(PSTR("I2C READ: "));
+ if (hw_i2c_master_rx(&c, 1, FALSE)) // last read
+ bus_out(c);
+ else
+ bus_log_puts_P(PSTR("NO"));
+ bus_log_newline();
+ hw_i2c_master_stop();
+ bus_log_puts_P(PSTR("I2C STOP CONDITION"));
+ bus_log_newline();
+ break;
+ }
+
+ state = STATE_INIT;
+}
+
+static void bus_i2c_write(uint8_t c)
+{
+ switch(state)
+ {
+ case STATE_ADDR_PENDING:
+ pending_data = c; // store address for later
+ state = STATE_START_PENDING;
+ break;
+
+ case STATE_START_PENDING:
+ bus_log_puts_P(PSTR("I2C START CONDITION"));
+ bus_log_newline();
+ bus_log_puts_P(PSTR("I2C WRITE: "));
+ bus_log_put0x8(pending_data);
+ bus_log_puts_P(PSTR(" GOT ACK: "));
+
+ if (!hw_i2c_master_start(pending_data, pending_data & 0x1 ? hw_i2c_rd : hw_i2c_wr))
+ {
+ hw_i2c_bus_clear();
+ bus_log_puts_P(PSTR("NO"));
+ state = STATE_ERROR;
+ }
+ else
+ {
+ bus_log_puts_P(PSTR("YES"));
+
+ pending_data = c;
+ state = STATE_WRITE_DATA_PENDING;
+ }
+ bus_log_newline();
+ break;
+
+ case STATE_WRITE_DATA_PENDING:
+ bus_log_puts_P(PSTR("I2C WRITE: "));
+ bus_log_put0x8(pending_data);
+ bus_log_puts_P(PSTR(" GOT ACK: "));
+
+ if (hw_i2c_master_tx(&pending_data, 1)) // more data to come
+ {
+ bus_log_puts_P(PSTR("YES"));
+ pending_data = c;
+ }
+ else
+ {
+ hw_i2c_bus_clear();
+ bus_log_puts_P(PSTR("NO"));
+ state = STATE_ERROR;
+ }
+ bus_log_newline();
+ break;
+
+ default:
+ hw_i2c_bus_clear();
+ state = STATE_ERROR;
+ break;
+ }
+}
+
+static void bus_i2c_read(void)
+{
+ uint8_t c;
+
+ switch(state)
+ {
+ case STATE_START_PENDING:
+ if (!hw_i2c_master_start(pending_data, pending_data & 0x1 ? hw_i2c_rd : hw_i2c_wr))
+ {
+ hw_i2c_bus_clear();
+ bus_log_puts_P(PSTR("NACK"));
+ state = STATE_ERROR;
+ }
+ else
+ {
+ bus_log_puts_P(PSTR("I2C START CONDITION"));
+ state = STATE_READ_DATA_PENDING;
+ }
+ bus_log_newline();
+ break;
+
+ case STATE_READ_DATA_PENDING:
+ bus_log_puts_P(PSTR("I2C READ: "));
+ if (hw_i2c_master_rx(&c, 1, TRUE)) // more data to come
+ bus_out(c);
+ else
+ {
+ hw_i2c_bus_clear();
+ bus_log_puts_P(PSTR("NO"));
+ state = STATE_ERROR;
+ }
+ bus_log_newline();
+ break;
+
+ default:
+ hw_i2c_bus_clear();
+ state = STATE_ERROR;
+ break;
+ }
+}
+
+static BOOL bus_i2c_command(const uint8_t *start, size_t len, uint32_t repeat)
+{
+ uint8_t i;
+ // address scanner
+ if (len == 1 && *start == 's') // FIXME
+ {
+ i = 0xFF;
+ do
+ {
+ if (hw_i2c_master_start(i, i & 0x1))
+ {
+ bus_log_put0x8(i);
+ bus_log_putc('(');
+ bus_log_put0x8(i>>1);
+ bus_log_putc(' ');
+ if (i & 0x1)
+ bus_log_putc('R');
+ else
+ bus_log_putc('W');
+ bus_log_putc(')');
+
+ bus_log_newline();
+ }
+ hw_i2c_bus_clear();
+ }
+ while(i-- > 0);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+const bus_interface_t bus_i2c =
+{
+ .open = bus_i2c_open,
+ .close = bus_i2c_close,
+ .start = bus_i2c_start,
+ .stop = bus_i2c_stop,
+ .write = bus_i2c_write,
+ .read = bus_i2c_read,
+ .command = bus_i2c_command
+};
+
9 src/bus_i2c.h
@@ -0,0 +1,9 @@
+#ifndef BUS_I2C_H
+#define BUS_I2C_H 1
+
+#include "bus.h"
+
+extern const bus_interface_t bus_i2c;
+
+#endif
+
66 src/bus_spi.c
@@ -0,0 +1,66 @@
+#include "ninja.h"
+#include "console.h"
+#include "bus.h"
+#include "hw_spi.h"
+
+#include "bus_spi.h"
+
+static void bus_spi_open(void)
+{
+ hw_spi_init();
+}
+
+static void bus_spi_close(void)
+{
+ hw_spi_shutdown();
+}
+
+static void bus_spi_start(void)
+{
+ hw_spi_cs_assert();
+
+ bus_log_puts_P(PSTR("CS ENABLED"));
+ bus_log_newline();
+}
+
+static void bus_spi_stop(void)
+{
+ hw_spi_cs_deassert();
+
+ bus_log_puts_P(PSTR("CS DISABLED"));
+ bus_log_newline();
+}
+
+static void bus_spi_write(uint8_t c)
+{
+ hw_spi_write8(c);
+ bus_log_puts_P(PSTR("WRITE: 0x"));
+ bus_log_puthex8(c);
+ bus_log_newline();
+}
+
+static void bus_spi_read(void)
+{
+ uint8_t c;
+ c = hw_spi_write8(0xFF);
+ bus_log_puts_P(PSTR("READ: 0x"));
+ bus_out(c);
+ bus_log_newline();
+}
+
+static BOOL bus_spi_command(const uint8_t *start, size_t len, uint32_t repeat)
+{
+ return FALSE;
+}
+
+const bus_interface_t bus_spi =
+{
+ .open = bus_spi_open,
+ .close = bus_spi_close,
+ .start = bus_spi_start,
+ .stop = bus_spi_stop,
+ .write = bus_spi_write,
+ .read = bus_spi_read,
+ .command = bus_spi_command
+};
+
9 src/bus_spi.h
@@ -0,0 +1,9 @@
+#ifndef BUS_SPI_H
+#define BUS_SPI_H 1
+
+#include "bus.h"
+
+extern const bus_interface_t bus_spi;
+
+#endif
+
33 src/command_bitbang.c
@@ -0,0 +1,33 @@
+#include "ninja.h"
+#include "console.h"
+#include "command_bitbang.h"
+
+void command_bitbang(void)
+{
+ uint8_t c;
+ uint8_t exitCount = 0;
+
+ console_puts_P(PSTR("Entering binary bitbang mode, +++ to exit"));
+ console_set_mode(CONSOLE_MODE_KEY);
+
+ do
+ {
+ DDRB = 0x00;
+
+ while(!console_key_poll(&c))
+ {
+ driver_tick();
+
+ if (c == '+')
+ exitCount++;
+ else
+ exitCount = 0;
+console_putc(PINB);
+// console_puthex8(PINB);
+// console_newline();
+ }
+ }
+ while(exitCount < 3);
+
+ console_set_mode(CONSOLE_MODE_LINE);
+}
6 src/command_bitbang.h
@@ -0,0 +1,6 @@
+#ifndef COMMAND_BITBANG_H
+#define COMMAND_BITBANG_H 1
+
+void command_bitbang(void);
+
+#endif
191 src/commands.c
@@ -0,0 +1,191 @@
+#include <avr/pgmspace.h>
+#include "ninja.h"
+#include "parse.h"
+#include "commands.h"
+#include "global_commands.h"
+#include "console.h"
+#include "bus.h"
+
+/*****************************************************************************/
+
+enum
+{
+ STATE_SEARCHING,
+ STATE_IN_TOKEN,
+};
+
+/*****************************************************************************/
+
+// "mycommand ... .... ..."
+// ^ ^ ^
+// cmdname | |
+// cmdname+len |
+// line_end
+static BOOL handle_global_command(const uint8_t *cmdname, size_t len, const uint8_t *line_end)
+{
+ const global_command_t *cmd_ptr = global_command_table;
+ global_command_t cmd;
+
+ memcpy_P(&cmd, cmd_ptr, sizeof(global_command_t));
+ while(NULL != cmd.name)
+ {
+ if (memcmp_P(cmdname, cmd.name, len)==0 && strlen_P(cmd.name) <= len)
+ {
+ if (!(*cmd.handler)(cmdname+len, line_end))
+ {
+ console_puts_P(PSTR("Error"));
+ console_newline();
+ }
+ return TRUE;
+ }
+ memcpy_P(&cmd, ++cmd_ptr, sizeof(global_command_t));
+ }
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+// returns TRUE if rest of line should be ignored
+static BOOL handle_command(const uint8_t *start, const uint8_t *end, BOOL firstToken, const uint8_t *line_end)
+{
+ uint32_t num;
+ const uint8_t *ptr = start;
+ uint32_t repeat = 1;
+
+ // handle repeat commands, A:5
+ while(ptr != end)
+ {
+ if (*ptr == ':' && ptr-start > 0) // found at least one character followed by ':'
+ {
+ if (parse_number(ptr+1, end - (ptr+1), &repeat))
+ {
+ end = ptr; // discard the ":X" part
+ break;
+ }
+ else
+ repeat = 0; // parse_number is destructive
+ }
+ ptr++;
+ }
+
+ // handle write command (a number)
+ if (parse_number(start, end-start, &num))
+ {
+ if (NULL != current_bus && NULL != current_bus->write)
+ {
+ while(repeat--)
+ current_bus->write((uint8_t)num);
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (end-start == 1 && (start[0] == 'r' || start[0] == 'R'))
+ { // handle read command
+ if (NULL != current_bus && NULL != current_bus->read)
+ {
+ while(repeat--)
+ current_bus->read();
+ return FALSE;
+ }
+ }
+ else
+ { // handle other commands
+ if (firstToken)
+ {
+ if (handle_global_command(start, end-start, line_end))
+ return TRUE;
+ }
+ if (NULL != current_bus && NULL != current_bus->command)
+ {
+ if (current_bus->command(start, end-start, repeat))
+ return FALSE;
+ // else, nosuch command
+ }
+ }
+ }
+
+ console_puts_P(PSTR("BadCmd"));
+ console_newline();
+
+ return FALSE;
+}
+
+void execute_command_line(const uint8_t *str, size_t len)
+{
+ uint8_t state = STATE_SEARCHING;
+ uint8_t c;
+ const uint8_t *end = str+len;
+ const uint8_t *token_start = str;
+ BOOL firstToken = TRUE;
+
+ while(str != end)
+ {
+ c = *str;
+
+ switch(state)
+ {
+ case STATE_SEARCHING:
+ switch(c)
+ {
+ case '#': // comment
+ return; // ignore the rest of the line
+
+ case ' ': // whitespace
+ case '\t':
+ case ',':
+ break;
+
+ case '[':
+ case '{':
+ firstToken = FALSE;
+ if (NULL != current_bus && NULL != current_bus->start)
+ current_bus->start();
+ break;
+
+ case ']':
+ case '}':
+ firstToken = FALSE;
+ if (NULL != current_bus && NULL != current_bus->stop)
+ current_bus->stop();
+ break;
+
+ default: // start of token
+ state = STATE_IN_TOKEN;
+ token_start = str;
+ break;
+ }
+ str++; // next character
+ break; // end of case STATE_SEARCHING
+
+ case STATE_IN_TOKEN:
+ switch(c)
+ {
+ case ' ': // end of token
+ case '\t':
+ case ',':
+ case '[':
+ case '{':
+ case ']':
+ case '}':
+ case '#':
+ if (handle_command(token_start, str, firstToken, end))
+ return;
+ firstToken = FALSE;
+ state = STATE_SEARCHING;
+ break;
+
+ default:
+ // keep scanning token
+ str++;
+ break;
+ }
+ }
+ }
+
+ if (STATE_IN_TOKEN == state)
+ handle_command(token_start, end, firstToken, end);
+}
+
+
+
7 src/commands.h
@@ -0,0 +1,7 @@
+#ifndef COMMANDS_H
+#define COMMANDS_H 1
+
+void execute_command_line(const uint8_t *str, size_t len);
+
+#endif
+
19 src/config-arduino.mk
@@ -0,0 +1,19 @@
+#
+# CONFIG FOR ARDUINO DIECEMILIA
+#
+MCU=atmega168
+F_CPU = 16000000UL
+CFLAGS += -DLED0_PORT=PORTD -DLED0_PIN=PD2 -DLED0_DDR=DDRD
+# Hardware watchdog
+CONFIG_WATCHDOG=y
+# I2C support
+CONFIG_BUS_I2C=y
+# SPI support
+CONFIG_BUS_SPI=y
+# Hardware UART driver
+CONFIG_HW_UART=y
+# Console on hw_uart
+CONFIG_HW_UART_CONSOLE=y
+PROGRAM_CMD=/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avrdude -C /Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/etc/avrdude.conf -pm168 -cstk500v1 -P/dev/tty.usbserial-A1001MTD -b19200 -D -Uflash:w:$(TARGET).hex
+
+
28 src/config-dev.mk
@@ -0,0 +1,28 @@
+#
+# CONFIG OPTIONS for features in development (use at your own risk)
+#
+
+# USB eStick-ish driver + JTAG PORTB driver + app
+# eStick OpenOCD support, BEWARE buffer size in openocd/estick.c needs shrinking
+#CONFIG_USBDEV_JTAG=y
+#CONFIG_JTAG=y
+
+# USBasp compatible AVR in-system-programmer
+# FIXME TBD needs to be hooked into hw_spi and protocol completed
+#CONFIG_USBDEV_AVRISP=y
+
+# Hardware UART driver
+#CONFIG_HW_UART=y
+
+# Console on hw_uart
+#CONFIG_HW_UART_CONSOLE=y
+
+# Dump key codes
+#CONFIG_COMMAND_DUMPKEYS=y
+
+# FIXME TBD Bus Pirate like bitbang mode
+#CONFIG_COMMAND_BITBANG=y
+
+# Interactive menu example
+#CONFIG_COMMAND_MENUTEST=y
+
19 src/config-teensy.mk
@@ -0,0 +1,19 @@
+#
+# CONFIG FOR TEENSY/MICROPENDOUS/AT90USBxxx etc
+#
+MCU=at90usb162
+F_CPU = 16000000UL
+CFLAGS += -DLED0_PORT=PORTD -DLED0_PIN=PD4 -DLED0_DDR=DDRD
+# Hardware watchdog
+CONFIG_WATCHDOG=y
+# I2C support
+CONFIG_BUS_I2C=y
+# SPI support
+CONFIG_BUS_SPI=y
+# USB CDC serial driver
+CONFIG_USBDEV_CDC=y
+# Console on CDC serial
+CONFIG_USBDEV_CDC_CONSOLE=y
+PROGRAM_CMD=avrdude -F -p usb162 -c avrusb500 -P /dev/tty.usbserial-A300* -U flash:w:$(TARGET).hex -U lfuse:w:0xCE:m -U hfuse:w:0xD8:m -U efuse:w:0xFF:m
+
+
45 src/config.mk
@@ -0,0 +1,45 @@
+#################################################################
+# Config options
+# See rules.mk for the makefile fragments enabled by each option
+
+#
+# CONFIG FOR ARDUINO
+#
+MCU=atmega168
+F_CPU = 16000000UL
+CFLAGS += -DLED0_PORT=PORTB -DLED0_PIN=PB5 -DLED0_DDR=DDRB
+# Hardware watchdog
+CONFIG_WATCHDOG=y
+# I2C support
+CONFIG_BUS_I2C=y
+# SPI support
+CONFIG_BUS_SPI=y
+# Hardware UART driver
+CONFIG_HW_UART=y
+# Console on hw_uart
+CONFIG_HW_UART_CONSOLE=y
+PROGRAM_CMD=/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/avrdude -C /Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/etc/avrdude.conf -pm168 -cstk500v1 -P/dev/tty.usbserial-A1001MTD -b19200 -D -Uflash:w:$(TARGET).hex
+
+
+##
+## CONFIG FOR TEENSY/MICROPENDOUS/AT90USBxxx etc
+##
+#MCU=at90usb162
+#F_CPU = 16000000UL
+#CFLAGS += -DLED0_PORT=PORTD -DLED0_PIN=PD4 -DLED0_DDR=DDRD
+## Hardware watchdog
+#CONFIG_WATCHDOG=y
+## I2C support
+#CONFIG_BUS_I2C=y
+## SPI support
+#CONFIG_BUS_SPI=y
+## USB CDC serial driver
+#CONFIG_USBDEV_CDC=y
+## Console on CDC serial
+#CONFIG_USBDEV_CDC_CONSOLE=y
+#PROGRAM_CMD=avrdude -F -p usb162 -c avrusb500 -P /dev/tty.usbserial-A300* -U flash:w:$(TARGET).hex -U lfuse:w:0xCE:m -U hfuse:w:0xD8:m -U efuse:w:0xFF:m
+
+
+
+##################################################################
+
260 src/console.c
@@ -0,0 +1,260 @@
+#include "ninja.h"
+#include "console.h"
+#ifdef CONFIG_HW_UART
+#include "hw_uart.h"
+#endif
+#include "commands.h"
+
+#define CMDBUF_SIZ 64
+
+#if CMDBUF_SIZ > 255
+#error Commands over 255 bytes not supported, change type of cmdbuf_len
+#endif
+
+/**************************************************************/
+
+static putcfunc_t putcf = NULL;
+
+/**************************************************************/
+
+static console_mode_t console_mode;
+
+/**************************************************************/ // FIXME, TODO, union'ise these to save RAM?
+// CONSOLE_MODE_LINE
+static uint8_t cmdbuf_len; // number of bytes in command buf
+static uint8_t cmdbuf[CMDBUF_SIZ];
+static BOOL got_line = FALSE;
+static BOOL echo = TRUE;
+static BOOL silent = FALSE;
+
+/**************************************************************/
+// CONSOLE_MODE_KEY
+static BOOL got_key = FALSE;
+static uint8_t last_key = 0x00; // last character received
+/**************************************************************/
+
+static void prompt(void)
+{
+ console_puts_P(PSTR("> "));
+}
+
+void console_init(void)
+{
+ console_set_mode(CONSOLE_MODE_LINE);
+}
+
+void console_set_mode(console_mode_t mode)
+{
+ console_mode = mode;
+
+ switch(mode)
+ {
+ case CONSOLE_MODE_LINE:
+ cmdbuf_len = 0;
+ got_line = FALSE;
+ break;
+ case CONSOLE_MODE_KEY:
+ got_key = FALSE;
+ break;
+ }
+}
+
+BOOL console_key_poll(uint8_t *c)
+{
+ if (got_key)
+ {
+ *c = last_key;
+ got_key = FALSE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL console_rx_ready_callback(void)
+{
+ switch(console_mode)
+ {
+ case CONSOLE_MODE_LINE:
+ return !got_line;
+
+ default:
+ case CONSOLE_MODE_KEY:
+ return TRUE;
+ }
+}
+
+void console_rx_callback(uint8_t c)
+{
+ switch(console_mode)
+ {
+ case CONSOLE_MODE_KEY:
+ got_key = TRUE;
+ last_key = c;
+ break;
+
+ case CONSOLE_MODE_LINE:
+ if (got_line) // throw away chars until the line is handled
+ return;
+
+ switch(c)
+ {
+ case 0x0D:
+ //case '\r':
+ got_line = TRUE;
+ console_newline();
+ break;
+ case '\b': // backspace
+ case 0x7F: // del
+ if (cmdbuf_len > 0)
+ {
+ cmdbuf_len--;
+ console_putc('\b');
+ console_putc(' ');
+ console_putc('\b');
+ }
+ break;
+ default:
+ if (cmdbuf_len < sizeof(cmdbuf)-1)
+ {
+ if (echo)
+ console_putc(c);
+ cmdbuf[cmdbuf_len++] = c;
+ }
+ else
+ console_putc('\a'); // bell
+ break;
+ }
+ break;
+ }
+}
+
+void console_tick(void)
+{
+ switch(console_mode)
+ {
+ case CONSOLE_MODE_LINE:
+ if (got_line)
+ {
+ if (cmdbuf_len > 0)
+ execute_command_line(cmdbuf, cmdbuf_len);
+ cmdbuf_len = 0;
+ prompt();
+ got_line = FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void console_set_putc(putcfunc_t f)
+{
+ putcf = f;
+}
+
+void console_putc(uint8_t c)
+{
+ if (!silent)
+ {
+#ifdef CONFIG_HW_UART_CONSOLE
+ hw_uart_putc(c);
+#endif
+ if (NULL != putcf)
+ (*putcf)(c);
+ }
+}
+
+void console_set_echo(BOOL newecho)
+{
+ echo = newecho;
+}
+
+void console_set_silent(BOOL newsilent)
+{
+ silent = newsilent;
+}
+
+void console_newline(void)
+{
+ console_putc('\r');
+ console_putc('\n');
+}
+
+void console_puts(uint8_t *str)
+{
+ while(*str!=0)
+ console_putc(*str++);
+}
+
+void console_puts_P(PGM_P str)
+{
+ while(pgm_read_byte(str)!=0)
+ console_putc(pgm_read_byte(str++));
+}
+
+
+static char nibble_to_char(uint8_t nibble)
+{
+ if (nibble < 0xA)
+ return nibble + '0';
+ return nibble - 0xA + 'A';
+}
+
+void console_puthex8(uint8_t h)
+{
+ console_putc(nibble_to_char((h & 0xF0)>>4));
+ console_putc(nibble_to_char(h & 0x0F));
+}
+
+void console_puthex16(uint16_t h)
+{
+ console_puthex8((h & 0xFF00) >> 8);
+ console_puthex8(h & 0xFF);
+}
+
+void console_put0x8(uint8_t h)
+{
+ console_putc('0');
+ console_putc('x');
+ console_puthex8(h);
+}
+
+void console_putsmem(const uint8_t *a, const uint8_t *b)
+{
+ while(a != b)
+ {
+ console_putc(*a);
+ a++;
+ }
+}
+
+
+void console_putdec(uint32_t n)
+{
+ uint32_t m;
+ BOOL in_leading_zeroes = TRUE;
+
+ for (m = 1000000000; m != 1; m/=10)
+ {
+ if ((n / m) != 0)
+ in_leading_zeroes = FALSE;
+ if (!in_leading_zeroes)
+ console_putc(nibble_to_char(n / m));
+ n = n % m;
+ }
+ console_putc(nibble_to_char(n));
+}
+
+void console_putbin(uint8_t b)
+{
+ console_putc('b');
+ (b & 0x80) ? console_putc('1') : console_putc('0');
+ (b & 0x40) ? console_putc('1') : console_putc('0');
+ (b & 0x20) ? console_putc('1') : console_putc('0');
+ (b & 0x10) ? console_putc('1') : console_putc('0');
+ (b & 0x08) ? console_putc('1') : console_putc('0');
+ (b & 0x04) ? console_putc('1') : console_putc('0');
+ (b & 0x02) ? console_putc('1') : console_putc('0');
+ (b & 0x01) ? console_putc('1') : console_putc('0');
+}
+
43 src/console.h
@@ -0,0 +1,43 @@
+#ifndef CONSOLE_H
+#define CONSOLE_H 1
+
+#include <avr/pgmspace.h>
+
+typedef void (*putcfunc_t)(uint8_t c);
+typedef BOOL (*getcfunc_t)(uint8_t *c);
+
+void console_init(void);
+void console_tick(void);
+
+typedef enum
+{
+ CONSOLE_MODE_LINE,
+ CONSOLE_MODE_KEY
+} console_mode_t;
+
+void console_set_mode(console_mode_t mode);
+
+void console_set_echo(BOOL newecho);
+void console_set_silent(BOOL newsilent);
+
+void console_set_putc(putcfunc_t f);
+
+void console_putc(uint8_t c);
+BOOL console_getc(uint8_t *c);
+BOOL console_key_poll(uint8_t *c);
+
+void console_newline(void);
+void console_puts(uint8_t *str);
+void console_puts_P(PGM_P str);
+void console_puthex8(uint8_t h);
+void console_puthex16(uint16_t h);
+void console_put0x8(uint8_t h);
+void console_putdec(uint32_t i);
+void console_putbin(uint8_t b);
+void console_putsmem(const uint8_t *a, const uint8_t *b);
+
+void console_rx_callback(uint8_t c);
+BOOL console_rx_ready_callback(void);
+
+#endif
+
18 src/cpu.c
@@ -0,0 +1,18 @@
+#include "ninja.h"
+#include "cpu.h"
+
+#include <avr/power.h>
+#include <avr/wdt.h>
+
+void cpu_init(void)
+{
+ /* Disable clock division */
+ clock_prescale_set(clock_div_1);
+}
+
+void cpu_reset(void)
+{
+ wdt_enable(WDTO_15MS);
+ while(1);
+}
+
13 src/cpu.h
@@ -0,0 +1,13 @@
+#ifndef CPU_H
+#define CPU_H 1
+
+#include <avr/interrupt.h>
+
+void cpu_init(void);
+void cpu_reset(void);
+
+#define cpu_enable_int() sei()
+#define cpu_disable_int() cli()
+
+#endif
+
307 src/global_commands.c
@@ -0,0 +1,307 @@
+#include "ninja.h"
+#include "global_commands.h"
+#include "parse.h"
+#include "console.h"
+#include "cpu.h"
+#include "led.h"
+
+#include "bus.h"
+
+#ifdef CONFIG_BUS_SPI
+#include "bus_spi.h"
+#endif
+
+#ifdef CONFIG_BUS_I2C
+#include "bus_i2c.h"
+#endif
+
+#ifdef CONFIG_USBDEV
+#include "usbdev.h"
+#endif
+
+#ifdef CONFIG_COMMAND_BITBANG
+#include "command_bitbang.h"
+#endif
+
+#ifdef CONFIG_COMMAND_MENUTEST
+#include "menu.h"
+#endif
+
+/****************************************************************************************/
+// Declare function names and prototypes
+
+DECLARE_COMMAND(version)
+#ifdef CONFIG_COMMAND_MENUTEST
+DECLARE_COMMAND(menutest)
+#endif
+#ifdef CONFIG_COMMAND_DUMPKEYS
+DECLARE_COMMAND(dumpkeys)
+#endif
+#ifdef CONFIG_COMMAND_BITBANG
+DECLARE_COMMAND(bitbang)
+#endif
+#ifdef CONFIG_COMMAND_TEST
+DECLARE_COMMAND(test)
+#endif
+DECLARE_COMMAND(help)
+DECLARE_COMMAND(led)
+#ifdef COMMAND_ECHO
+DECLARE_COMMAND(echo)
+#endif
+#ifdef COMMAND_SILENT
+DECLARE_COMMAND(silent)
+#endif
+#ifdef COMMAND_LOG
+DECLARE_COMMAND(log)
+#endif
+DECLARE_COMMAND(reset)
+#ifdef CONFIG_BUS_SPI
+DECLARE_COMMAND(spi)
+#endif
+#ifdef CONFIG_BUS_I2C
+DECLARE_COMMAND(i2c)
+#endif
+#ifdef CONFIG_USBDEV_JTAG
+DECLARE_COMMAND(jtag)
+#endif
+#ifdef CONFIG_USBDEV_AVRISP
+DECLARE_COMMAND(avrisp)
+#endif
+
+/****************************************************************************************/
+// Create table of names and function pointers
+
+const global_command_t global_command_table[] PROGMEM =
+{
+ ADD_COMMAND(version)
+#ifdef CONFIG_COMMAND_MENUTEST
+ ADD_COMMAND(menutest)
+#endif
+#ifdef CONFIG_COMMAND_DUMPKEYS
+ ADD_COMMAND(dumpkeys)
+#endif
+#ifdef CONFIG_COMMAND_BITBANG
+ ADD_COMMAND(bitbang)
+#endif
+#ifdef CONFIG_COMMAND_TEST
+ ADD_COMMAND(test)
+#endif
+ ADD_COMMAND(help)
+#ifdef COMMAND_LOG
+ ADD_COMMAND(log)
+#endif
+ ADD_COMMAND(led)
+#ifdef COMMAND_ECHO
+ ADD_COMMAND(echo)
+#endif
+#ifdef COMMAND_SILENT
+ ADD_COMMAND(silent)
+#endif
+ ADD_COMMAND(reset)
+#ifdef CONFIG_BUS_SPI
+ ADD_COMMAND(spi)
+#endif
+#ifdef CONFIG_BUS_I2C
+ ADD_COMMAND(i2c)
+#endif
+#ifdef CONFIG_USBDEV_AVRISP
+ ADD_COMMAND(avrisp)
+#endif
+ {NULL, NULL},
+};
+
+
+/****************************************************************************************/
+// Define command handlers
+
+#define TOK_NUM(p_tokend, p_num) tok_num(&tok_start, p_tokend, line_end, p_num)
+
+#ifdef CONFIG_COMMAND_TEST
+// read all available tokens, converting to numbers as possible
+// TODO, basis for custom parsers in bus_modules
+DEFINE_COMMAND(test)
+{
+ const uint8_t *tok_end;
+ uint32_t num;
+
+ while(tok_start != line_end)
+ {
+ if (TOK_NUM(&tok_end, &num))
+ {
+ console_puts_P(PSTR("number: "));
+ console_putdec(num);
+ console_newline();
+ }
+ else
+ {
+ console_puts_P(PSTR("string: "));
+ console_putsmem(tok_start, tok_end);
+ console_newline();
+ tok_start = tok_end;
+ }
+ }
+
+ return TRUE;
+}
+#endif
+
+
+DEFINE_COMMAND(version)
+{
+ console_puts_P(PSTR(VERSION_STR));
+ console_newline();
+ return TRUE;
+}
+
+#ifdef CONFIG_COMMAND_MENUTEST
+DEFINE_COMMAND(menutest)
+{
+ mymenu();
+ return TRUE;
+}
+#endif
+
+#ifdef CONFIG_COMMAND_BITBANG
+DEFINE_COMMAND(bitbang)
+{
+ command_bitbang();
+ return TRUE;
+}
+#endif
+
+#ifdef CONFIG_COMMAND_DUMPKEYS
+DEFINE_COMMAND(dumpkeys)
+{
+ uint8_t c;
+
+ console_set_mode(CONSOLE_MODE_KEY);
+ console_puts_P(PSTR("Space to quit"));
+ console_newline();
+
+ do
+ {
+ while(!console_key_poll(&c))
+ driver_tick();
+
+ console_puthex8(c);
+ console_newline();
+ }
+ while(c != ' ');
+
+ console_set_mode(CONSOLE_MODE_LINE);
+
+ return TRUE;
+}
+#endif
+
+DEFINE_COMMAND(led)
+{
+ const uint8_t *tokp;
+ uint32_t num;
+
+ if (!TOK_NUM(&tokp, &num))
+ return FALSE;
+
+ if (num >= LED_SEQ_MAX)
+ return FALSE;
+
+ led_set_seq(num);
+ return TRUE;
+}
+
+#ifdef COMMAND_SILENT
+DEFINE_COMMAND(silent)
+{
+ const uint8_t *tokp;
+ uint32_t num;
+
+ if (!TOK_NUM(&tokp, &num))
+ return FALSE;
+
+ console_set_silent(num == 1);
+ return TRUE;
+}
+#endif
+
+#ifdef COMMAND_ECHO
+DEFINE_COMMAND(echo)
+{
+ const uint8_t *tokp;
+ uint32_t num;
+
+ if (!TOK_NUM(&tokp, &num))
+ return FALSE;
+
+ console_set_echo(num == 1);
+ return TRUE;
+}
+#endif
+
+#ifdef COMMAND_LOG
+DEFINE_COMMAND(log)
+{
+ const uint8_t *tokp;
+ uint32_t num;
+
+ if (!TOK_NUM(&tokp, &num))
+ return FALSE;
+
+ bus_enable_log(num == 1);
+ return TRUE;
+}
+#endif
+
+DEFINE_COMMAND(help)
+{
+ const global_command_t *cmd_ptr = global_command_table;
+ global_command_t cmd;
+
+ memcpy_P(&cmd, cmd_ptr, sizeof(global_command_t));
+ while(NULL != cmd.name)
+ {
+ console_puts_P(cmd.name);
+ console_newline();
+ memcpy_P(&cmd, ++cmd_ptr, sizeof(global_command_t));
+ }
+ return TRUE;
+}
+
+DEFINE_COMMAND(reset)
+{
+ cpu_reset();
+ return TRUE;
+}
+
+#ifdef CONFIG_BUS_SPI
+DEFINE_COMMAND(spi)
+{
+ bus_init(&bus_spi);
+ return TRUE;
+}
+#endif
+
+#ifdef CONFIG_BUS_I2C
+DEFINE_COMMAND(i2c)
+{
+ bus_init(&bus_i2c);
+ return TRUE;
+}
+#endif
+
+#ifdef CONFIG_USBDEV_JTAG
+DEFINE_COMMAND(jtag)
+{
+ usbdev_init(USBMODE_JTAG);
+ return TRUE;
+}
+#endif
+
+#ifdef CONFIG_USBDEV_AVRISP
+DEFINE_COMMAND(avrisp)
+{
+ usbdev_init(USBMODE_AVRISP);
+ return TRUE;
+}
+#endif
+
+
33 src/global_commands.h
@@ -0,0 +1,33 @@
+#ifndef GLOBAL_COMMANDS_H
+#define GLOBAL_COMMANDS_H 1
+
+#include "ninja.h"
+#include <avr/pgmspace.h>
+
+typedef BOOL (*global_command_func_t)(const uint8_t *tok_start, const uint8_t *line_end);
+
+typedef struct
+{
+ const prog_char *name;
+ global_command_func_t handler;
+} global_command_t;
+
+extern const global_command_t global_command_table[] PROGMEM;
+
+/****************************************************************************************/
+/* FIXME these macros will only work for command names which are valid C function names */
+
+#define DECLARE_COMMAND(X) \
+ const char X##Str[] PROGMEM = #X; \
+ static BOOL global_command_##X(const uint8_t *tok_start, const uint8_t *line_end);
+
+#define DEFINE_COMMAND(X) \
+ static BOOL global_command_##X(const uint8_t *tok_start, const uint8_t *line_end)
+
+#define ADD_COMMAND(X) \
+ { X##Str, global_command_##X },
+
+/****************************************************************************************/
+
+#endif
+
395 src/hw_i2c.c
@@ -0,0 +1,395 @@
+/*
+ * userial -- a USB to I2C converter
+ *
+ * Copyright (c) 2008-2010, Thomas Pircher <tehpeh@gmx.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *****************************************************************************/
+#include "ninja.h"
+#include "hw_i2c.h"
+#include "watchdog.h"
+#include "cpu.h"
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <util/twi.h>
+#include <util/delay_basic.h>
+#include <util/delay.h>
+
+#define I2C_INIT_FREQ 100 // 100kHz
+
+//#define USE_HARDWARE_I2C 1
+
+#if USE_HARDWARE_I2C
+//***************************************************************************
+// TWI control register values
+//***************************************************************************
+#define TWICR_TWEN (_BV(TWEN)) //!< TWI enable
+#define TWICR_TWIE (_BV(TWIE)) //!< interrupts enabled
+#define TWICR_TWEA (_BV(TWEA)) //!< next I2C activity will be acknowledged
+#define TWICR_TWSTA (_BV(TWSTA)) //!< set the start bit
+#define TWICR_TWSTO (_BV(TWSTO)) //!< set the stop bit
+#define TWICR_TWINT (_BV(TWINT)) //!< clear onlythe TWINT bit
+//#define TWICR_TWINT_TWEA (_BV(TWINT)|_BV(TWEA)) //!< TWCR_TWINT and TWCR_TWEA
+
+#else
+
+#if __AVR_ATmega168__
+#define SDA PC4 // SDA pin
+#define SCL PC5 // SCL pin
+#define SDA_DDR DDRC
+#define SCL_DDR DDRC
+#define SDA_OUT PORTC
+#define SCL_OUT PORTC
+#define SDA_IN PINC
+#define SCL_IN PINC
+#elif __AVR_AT90USB162__
+#define SDA PB2 // SDA pin
+#define SCL PB1 // SCL pin
+#define SDA_DDR DDRB
+#define SCL_DDR DDRB
+#define SDA_OUT PORTB
+#define SCL_OUT PORTB
+#define SDA_IN PINB
+#define SCL_IN PINB
+#else
+#error Unsupported processor
+#endif
+
+#define sda_low() (SDA_DDR |= _BV(SDA))
+#define scl_low() (SCL_DDR |= _BV(SCL))
+#define sda_hi() (SDA_DDR &= ~_BV(SDA))
+#define scl_hi() (SCL_DDR &= ~_BV(SCL))
+
+#define T2_TICKS (F_CPU/(I2C_INIT_FREQ * 1000UL * 3UL))
+#define delay_T2() (_delay_loop_1(T2_TICKS > 0 ? T2_TICKS : 1))
+
+static BOOL hold_bus;
+
+static void hw_i2c_write_byte(uint8_t data);
+static uint8_t hw_i2c_read_bit(void);
+#endif // USE_HARDWARE_I2C
+
+
+
+#if USE_HARDWARE_I2C
+#error UNTESTED, DRAGONS BE HERE
+/**
+ * Get the TWPS (prescaler) bits for the TWI
+ *
+ * \param freq I2C master frequency in kHz.
+ *****************************************************************************/
+static inline uint8_t hw_i2c_get_twps(uint16_t freq) __attribute__((const));
+
+
+/**
+ * Calculates the TWBR (baudrate) bits for the TWI
+ *
+ * \param freq I2C master frequency in kHz.
+ * \param twps the selected prescaler bits.
+ *****************************************************************************/
+static inline uint8_t hw_i2c_get_twbr(uint16_t freq, uint8_t twps) __attribute__((const));
+
+
+uint8_t hw_i2c_get_twps(uint16_t freq)
+{
+ uint8_t ps;
+ uint16_t val = F_CPU / (0xffUL * 2000UL);
+
+ ps = 0;
+ while (freq <= val) {
+ ps++;
+ val /= 4;
+ }
+ return ps;
+}
+
+
+uint8_t hw_i2c_get_twbr(uint16_t freq, uint8_t twps)
+{
+ return (((F_CPU / 2000) / freq) - 8) / (1 << (twps *2));
+}
+#endif // USE_HARDWARE_I2C
+
+
+void hw_i2c_init(void)
+{
+#if USE_HARDWARE_I2C
+ TWCR = 0;
+ hw_i2c_config(I2C_INIT_FREQ);
+ TWDR = 0xFF;
+ TWCR = TWICR_TWEN;
+#else
+ SDA_DDR &= ~_BV(SDA); // release SDA
+ SCL_DDR &= ~_BV(SCL); // release SCL
+ SDA_OUT &= ~_BV(SDA);
+ SCL_OUT &= ~_BV(SCL);
+
+ hold_bus = FALSE;
+#endif
+}
+
+void hw_i2c_shutdown(void)
+{
+#if USE_HARDWARE_I2C
+#warning untested code
+ TWCR &= ~TWICR_TWEN;
+#endif
+}
+
+
+void hw_i2c_bus_clear(void)
+{
+ hw_i2c_master_start(0, hw_i2c_rd);
+ hw_i2c_master_stop();
+}
+
+
+void hw_i2c_config(uint16_t freq)
+{
+#if USE_HARDWARE_I2C
+ uint8_t twps;
+
+ twps = hw_i2c_get_twps(freq);
+ TWBR = hw_i2c_get_twbr(freq, twps);
+ TWSR = twps & 0x03;
+#else
+ (void)freq; // frequency not used
+#endif
+}
+
+
+uint16_t hw_i2c_get_freq(void)
+{
+#if USE_HARDWARE_I2C
+ uint8_t twps = 1 << (2 * (TWSR & 0x03));