OSDN Git Service

Update lejos_osek to nxtOSEK_v205b0.zip similar-to-nxtOSEK_v205b0
authorMasaki Muranaka <monaka@monami-software.com>
Thu, 15 Apr 2010 06:31:07 +0000 (15:31 +0900)
committerMasaki Muranaka <monaka@monami-software.com>
Thu, 15 Apr 2010 06:31:07 +0000 (15:31 +0900)
27 files changed:
nxtOSEK/lejos_nxj/README.html
nxtOSEK/lejos_nxj/src/nxtvm/javavm/classes.h
nxtOSEK/lejos_nxj/src/nxtvm/javavm/constants.h
nxtOSEK/lejos_nxj/src/nxtvm/javavm/poll.h
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/bt.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/bt.h
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/data_abort.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/display.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/display.h
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/flashprog.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/flashprog.h
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/i2c.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/init.s
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/nxt_avr.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/nxt_lcd.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/nxt_lcd.h
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/nxt_motors.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/nxt_spi.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/nxt_spi.h
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/sensors.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/sound.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/sound.h
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/systick.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/systick.h
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/twi.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/udp.c
nxtOSEK/lejos_nxj/src/nxtvm/platform/nxt/udp.h

index fc5cb2d..5a98454 100644 (file)
@@ -1,35 +1,36 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
 <html>\r
 <head>\r
-  <title>leJOS NXT, a Java system for the Lego Mindstorms NXT</title>\r
+  <title>leJOS NXJ, a Java system for the Lego Mindstorms NXT</title>\r
 </head>\r
 <body style="background-color: rgb(255, 255, 255);">\r
 <ul>\r
-  <li><a href="#what_is_lejos">What is leJOS?</a></li>\r
+  <li><a href="#what_is_lejos">What is leJOS NXJ?</a></li>\r
   <li><a href="#preliminiaries">Preliminiaries</a></li>\r
   <li><a href="#installation_and_set_up">Installation and Set Up</a></li>
-  <li><a href="#using-lejos">Using lejos on the NXT</a></li>\r
-  <li><a href="#limitations">Known limitations</a></li>\r
-  <li><a href="#bugs">Known bugs</a></li>\r
+  <li><a href="#using-lejos">Using leJOS NXJ</a></li>
+  <li><a href="#compiling">Compiling and running your first code</a></li>\r
+  <li><a href="#tools">LeJOS NXJ Tools</a></li>\r
+  <li><a href="#limitations">Known limitations in leJOS</a></li>\r
+  <li><a href="#bugs">Known bugs in leJOS</a></li>\r
+  <li><a href="#nxjbugs">Known bugs and limitations in leJOS NXJ</a></li>\r
   <li><a href="#documentation">Documentation</a></li>\r
   <li><a href="#license">License</a></li>\r
   <li><a href="#questions">Questions and Problems</a></li>\r
 </ul>\r
-<a href="#questions"> </a>\r
-<h1><a name="what_is_lejos">What is leJOS?</a></h1>\r
-leJOS (pronounced like the Spanish word "lejos" for "far") is a 
-tiny Java-based operating system that\r
-has been ported to the following platforms: </a>\r
+<h1><a name="what_is_lejos">What is leJOS NXJ?</a></h1>\r
+<p>leJOS (pronounced like the Spanish word "lejos" for "far") is a 
+tiny Java-based operating system that has been ported to the following platforms:</p>\r
 <ul>\r
-  <li>Lego Mindstorms NXT</li>
-  <li>Lego Mindstorms RCX</li>\r
-  <li>Unix (for emulation of lejos programs only)</li>\r
+  <li>LEGO Mindstorms NXT</li>
+  <li>LEGO Mindstorms RCX</li>\r
+  <li>Unix (for emulation of leJOS programs only)</li>\r
   </a>\r
 </ul>\r
-leJOS was originally forked out of the </a><a\r
+<p>leJOS was originally forked out of the </a><a\r
  href="http://tinyvm.sourceforge.net">TinyVM project</a>. <br>\r
 It contains a VM for Java bytecodes and additional software to load and\r
-run Java programs. <br/><br/>
+run Java programs.</p>
 
 These are some of the features offered:\r
 <ul>\r
@@ -43,59 +44,174 @@ These are some of the features offered:
   <li>Math class</li>
   <li>Well-documented Robotics API</li>\r
 </ul>\r
+\r
+<p>leJOS NXJ is the version of leJOS for the LEGO Mindstorms NXT. \r
+It uses the same Java VM as the RCX version, but has new drivers for the NXT hardware.\r
+</p>\r
+<p>leJOS NXJ adds lots of new capability to leJOS including a file system, a menu system,\r
+and support for I2C sensors, including those from third parties. The built-in tachometers in\r
+the NXT motors have enabled much improved control over speed, steering and navigation.\r
+</p>\r
+<p>Bluetooth and USB communications are a great improvement over the infra-red link used by the RCX.</p>\r
+\r
 <h1><a name="preliminiaries">Preliminaries</a></h1>\r
 <ul>\r
-  <li>You need a Java Development Kit (JDK), preferably 1.5</li>\r
-  <li>Your PATH must contain the JDK's bin directory</li>\r
+  <li>You need a Java Development Kit (JDK), preferably 1.5 or later.</li>\r
+  <li>Your PATH must contain the JDK's bin directory.</li>\r
   <li>Make sure you have set JAVA_HOME properly to the root directory\r
-of the JDK</li>\r
-  <li>In case you want to build the distribution, your PATH must\r
-contain the ant binary (ant 1.6 or above)</li>
-  <li>You need libusb installed. On Windows you should use the libusb-Win32 filter driver</li>
-  <li>On Windows you will need the Lego Mindstorms NXT software installed, as its USB drivers are used</li>\r
-</ul>\r
-<h1><a name="installation_and_set_up">Installation and Set Up</a></h1>\r
-Please download the leJOS\r
-documentation from the same location you downloaded this distribution.\r
+of the JDK.</li>\r
+  <li>On systems other than Microsoft Windows, you will need to build the distribution, so your PATH must\r
+contain the ant binary (ant 1.7 or above).</li>
+  <li>You need libusb installed. On Microsoft Windows you should use the libusb-Win32 filter driver.</li>
+  <li>On Microsoft Windows and MAC OS X you will need the LEGO Mindstorms NXT software installed, as its USB drivers are used.</li>
+  <li>On MAC OS X systems, you will need the OS X developer tools installed.</li>
+  \r
+</ul>
+
+The libusb filter driver for Microsoft Windows can be obtained from <a href="http://libusb-win32.sourceforge.net/#downloads">http://libusb-win32.sourceforge.net/#downloads</a>. \r
+This does not currently work under Windows Vista - see "Known Bugs and Limitations in leJOS NXJ" below.\r
+However, it works if you install on Vista under Windows XP compatibility mode:<br/>\r
 <ol>\r
-  <li>Set your environment variable <em>LEJOS_HOME</em> to the\r
-directory you installed this distribution into</li>
-  <li>Add leJOS's bin directory to your PATH</li>\r
-  <li>On Linux, depending on the privilege settings you might need to\r
-adjust the execution permissions in the <em>bin</em> folder</li>\r
+<li>Download libusb-win32-filter-bin-0.1.12.1.exe (the version current @ 27/09/07)\r
+<li>Right click on this file. Select Properties | Compatibility Click the "Run this program in compatibility mode" box and select "Windows XP (Service Pack2)" from the drop down list.\r
+<li>Right click again and select "Run as Administrator". Follow the installation instructions. Run the test program will list the usb devices plugged into your computer, but not new devices.\r
 </ol>\r
-On Linux, you will have to build the distribution first. To do so,\r
-switch to the <em>build</em> folder and run <code>ant</code>.\r
-Note that depending on the privilege settings you might need to adjust\r
-the the execution permissions in the <em>release</em> folder.
-<h1><a name="using-lejos">Using lejos on the NXT</a></h1>
-<ul>
-  <li>Compile using <em>lejosjc</em> instead of <em>javac</em></li>
-  <li>Link programs using <em>lejoslink</em></li>
-  <li>Download and run programs using <em>lejosdl</em>
-  <li>Emulate leJOS programs on the host using <em>emu-lejosrun</em> (currently Linux only)</li>
-  <li>Exceptions: Use <em>lejoslink --verbose</em>. Exceptions are shown in the NXT as Method:XXXX, CLASS:YY, where XXXX = method_signature and YY = exception_class_index</li>
-</ul>
+<br/>
+
+libusb for other systems can be obtained from <a href="http://libusb.sourceforge.net">http://libusb.sourceforge.net</a>.<br/><br/>
+
+On Linux systems, if you are running leJOS NXJ from a non-root user, you will need to ensure that you have read and write access the NXT USB device in /dev/bus/usb.
+If you can identify the device in /dev/bus/usb, you can do this by:<br/><br/>
+
+<em>sudo chmod a+w /dev/bus/usb/xxx/yyy</em><br/><br/>
+
+However, the yyy number will count up each time the NXT is disconnected and reconnected.<br/><br/>
+
+A better solution is to use udev rules or pamcomsole. How to do this varies with different Linux systems. A pamconsole solution that works on Fedora Core 5, is to create a file /etc/security/console.perms.d/60-libusb.perms with the two lines:<br/><br/>
 
-Your NXT must be plugged into the USB, switched on, and in firmware update mode to run lejosdl. 
+<code>\r
+&lt;usbdevices&gt;=/dev/bus/usb/*/*<br/>
+&lt;console&gt; 0600 &lt;usbdevices&gt; 0644 root
+</code>\r
 <br/><br/>
+\r
+To use udev rules, set up a file such as  /etc/udev/rules.d/70-lego.rules and populate it with the following lines: <br/><br/>\r
+\r
+<code>\r
+# Lego NXT<br/>\r
+BUS=="usb", SYSFS{idVendor}=="03eb", GROUP="lego", MODE="0660" <br/>\r
+BUS=="usb", SYSFS{idVendor}=="0694", GROUP="lego", MODE="0660" <br/>\r
+</code>\r
+</br>\r
+\r
+This relies on the username you are using being in the <em>lego</em> group. You can modify the file to your\r
+requirements. The two vendors are LEGO and Atmel (for the samba driver used in firmware update mode).\r
+You may need to restart udev.\r
+\r
+<h1><a name="installation_and_set_up">Installation and Set Up</a></h1>\r
+\r
+<ol>
+  <li>Extract the files from the distribution. A lejos_nxj subdirectory will be created.</li>\r
+  <li>Set the environment variable <em>NXJ_HOME</em> to the full path of the lejos_nxj\r
+directory.</li>
+  <li>Add the lejos_nxj/bin directory to your PATH.</li>\r
+  <li>On Linux and Unix systems, depending on your privilege settings you might need to\r
+adjust the execution permissions in the <em>bin</em> directory.</li>\r
+</ol>\r
+On Linux and Unix systems, you will have to build the distribution first. To do so,\r
+switch to the <em>build</em> folder and run <code>ant</code>. You  will need to ensure that the\r
+packages that leJOS NXJ is dependent on are on your system. These include libusb-dev,\r
+gcj and libbluetooth-dev.\r
+
+<h1><a name="using-lejos">Using leJOS NXJ</a></h1>
+<ul>\r
+  <li>Flash the leJOS NXJ firmware using <em>nxjflash</em>.</li>
+  <li>Compile using <em>nxjc</em> instead of <em>javac</em>.</li>
+  <li>Link, upload and run programs using <em>nxj</em>.</li>
+  <li>Exceptions: Use <em>nxj --verbose</em> to get information on methods and special classes used by your program. Exceptions are shown on the NXT as Method:XXXX, CLASS:YY, where XXXX = method_signature and YY = exception_class_index</li>
+</ul>
+
+<p>Your NXT must be plugged into the USB, switched on, and in firmware update mode to run nxjflash. Note that the standard LEGO firmware will be overwritten and all existing data lost. You can reinstall the LEGO firmware using the LEGO Mindstorms software.
+</p>
 To go into firmware update mode press the reset button (at the back of the NXT , upper left corner) for more than 4 seconds. 
-Your NXT will audibly tick when it is firmware update mode, but is not running a lejos program.
-<br/><br/>
-To switch your NXT on, just press the orange button. It will start to audibly tick.
-<br/><br/>
-When you use <em>lejosdl</em> your program will download and run. You can stop a program by pressing the ENTER and ESCAPE (orange and grey square) buttons together. 
-This powers down the NXT immediately. Press the ENTER (orange) button to wake it up again.
-<br/><br/>
-You can also power down the NXT with ENTER + ESCAPE, after an Exception occurs.
+Your NXT will audibly tick when it is firmware update mode.
+<br/><br/>\r
+\r
+<p>To run nxjflash, open a command window, and type <em>nxjflash</em></p>\r
 \r
+<p><em>nxjflash</em> will write the Java VM and the leJOS NXJ start-up menu to the flash memory of your NXT. It will create an empty user flash area. When the flash procedure has finished, leJOS NXJ will start up and an empty menu will be displayed.\r
+</p>
+<p>You can switch the NXT off at any time, including when a program is running, by pressing the orange and dark gray buttons (ENTER + ESCAPE) together.To switch it back on just press the orange button. The leJOS NXJ start-up menu will be displayed.
+</p>\r
+\r
+If your NXT freezes at any time, remove and re-insert a battery.
+
+<h1><a name="compiling">Compiling and running your first code</a></h1>
+
+To compile, link and download the Tune sample:
+
+<ul>
+  <li>Open a command window</li>
+  <li>Check that java and lejos_nxj are on your PATH</li>\r
+  <li>Check that the NXJ_HOME environment variable is defined</li>
+  <li>Change to the lejos_nxj\samples\Tune directory</li>
+  <li>Type <em>nxjc Tune.java</em></li>
+  <li>Check that your USB cable is connected</li>\r
+  <li>Check that the NXT is turned on</li>\r
+  <li>Type <em>nxj -r Tune</em></li>
+ </ul>
+<p>After a few seconds, you should hear an ascending tone sequence indicating that the program uploaded OK. You will then hear a tune play. When it has finished the leJOS NXJ menu will be displayed.</p>
+\r
+<p>When you switch your NXT back on, select "Files" and press ENTER and you will see "Tune.nxj" in the files menu</p>\r
+\r
+<p>You can navigate through the leJOS NXJ menus using the left and right buttons. You select a menu item by pressing ENTER, and exit from a menu by pressing ESCAPE. There are 3 menus: Files, Bluetooth ands System. To select a program, go to the Files menu, scroll down to your program and press the ENTER button. You will then see a sub-menu that lets you execute or delete the program.</p>\r
+\r
+<h1><a name="tools">LeJOS NXJ Tools</a></h1>\r
+<p>The following tools are available with leJOS NXJ:</p>\r
+\r
+<ul>\r
+<li><em>nxjflash</em> - flashes the firmware</li>\r
+<li><em>nxjc</em> - compiles a Java program for leJOS NXJ</li>\r
+<li><em>nxj</em> - links, uploads and optionally runs a leJOS NXJ program</li>\r
+<li><em>nxjlink</em> - links a program</li>\r
+<li><em>nxjupload</em> - uploads and optionally runs a program</li>\r
+<li><em>nxjbrowse</em> - explorer for NXJ files</li>\r
+<li><em>emu-lejosrun</em> - emulate a leJOS NXJ program on Unix</li>\r
+</ul>\r
+\r
+<p><em>nxj</em>, <em>nxjupload</em> and <em>nxjbrowse</em> can be used over Bluetooth or USB.\r
+By default they try to use USB first, and if this fails, they try Bluetooth</P>\r
+\r
+<p>Use the <em>--usb</em> flag to select usb only, or <em>--bluetooth</em> for Bluetooth only.</p>\r
+\r
+<p><em>nxjbrowse</em> displays a list of all the NXTs that it finds, and allows you to select one to connect to. \r
+<em>nxj</em> and <em>nxjupload</em>, try each NXT they find in turn until they successfully connect to one. \r
+To pick a specific NXT to connect to by name, use the <em>--name</em> flag.</p>\r
+\r
+<p>You can connect to a specific NXT by address, using the <em>--address</em> flag. If you specify the address, a Bluetooth inquiry will not be done,\r
+and the connection will be much faster. Use <em>nxjbrowse</em> to list the addresses of your NXT devices. An address is 12 hex digits with optional colons\r
+between the hex pairs.</p>\r
+\r
+<p>The leJOS NXJ tools can use different comms driver to connect to the NXT. The only driver available for USB is NXTCommLibnxt, \r
+which uses David Anderson's libnxt library and the libusb open source library. This works on all operating systems. \r
+For Bluetooth on Windows, NXTCommBluecove, which uses the Bluecove open source library, is used. \r
+On Linux and MAC OS X, NXTCommBluez, which uses the open source Bluez project, is used for Bluetooth.</p>\r
+\r
+<p>A future version of leJOS NXJ is expected to support the LEGO Fantom API, which should work for both USB abd Bluetooth.</p>\r
+\r
+<p>The properties file,lejos_nxt/bin/nxj.properties, can be modified to select different comms drivers,\r
+but for this release the defaults are the only available drivers.</p>\r
+\r
+<p><em>nxjbrowse</em> lists the files on the NXT and includes their size, and start and end pages. \r
+It can be used to delete, upload and download programs and other files. \r
+It can also run programs, change the name of the NXT and defrag the files,\r
+moving them all to the start of user flash memory. Changing the name of the NXT only works over USB.</p> \r
 <h1><a name="limitations">Known limitations</a></h1>\r
 Due to size constraints, some Java language\r
 features have been omitted. Others just haven't been implemented yet.\r
-Known limitations are: </a>\r
+Known limitations with all versions of leJOS are: </a>\r
 <ul>\r
-  <li>Garbage collection is not performed yet.\r
-Hence, the number of objects in your program should be limited</li>\r
   <li>Switch statements are not supported</li>\r
   <li>Arithmetic operations on variables of type long are not\r
 supported, although you can cast ints to longs and vice versa</li>\r
@@ -114,6 +230,7 @@ not supported by leJOS</li>
   </a>\r
 </ul>\r
 <h1><a name="bugs">Known Bugs</a></h1>\r
+<p>The following bugs apply to all versions of leJOS:</p>\r
 <ul>\r
  <li>MONITOREXIT ignores null objects (it assumes\r
 MONITORENTER has handled them). Furthermore, it doesn't check monitor\r
@@ -124,21 +241,68 @@ synchronized. This could lead to access of statics before they are
 initialized, when multiple threads use a class</li>\r
   </a>\r
 </ul>\r
+<h1><a name="nxjbugs">Known Bugs and Limitations in leJOS NXJ</a></h1>\r
+<p>The following bugs and limitations apply to the current version of leJOS NXJ:</p>\r
+\r
+<ul>\r
+<li>Occasionally, after flashing the firmware with with nxjflash, the battery level reads as 0.0 and buttons do not respond. If this happens, a battery must be removed and re-inserted. It is not necessary to repeat the nxjflash.\r
+</li>\r
+<li>leJOS NXJ does not work out of the box on Windows Vista systems. This is due to limitations in libusb-win32 that the leJOS  NXJ Windows USB tools, including nxjflash, rely on. Installing libusb in windows XP compatibility mode should cure the problem.\r
+</li>\r
+<li>Bluetooth does not work on MAC OS X systems, and the ant build files for MAC OS X are largely untested.  See the forums on the leJOS web site for the latest state of leJOS on MAC OS X.\r
+</li>\r
+<li>Occasionally, after pressing the orange (ENTER) button to start leJOS NXJ, the LCD remains blank. If this occurs, and is not due to low batteries, it is necessary to shut down leJOS, by pressing the orange and dark gray buttons (ENTER + ESCAPE), and try again.\r
+</li>\r
+<li>Only one file can be open at a time.\r
+</li>\r
+<li>leJOS NXJ only supports program upload and download, tools such as nxjbrowse, and LEGO communications Protocol commands when the start-up menu is running, not when a user program is running, unless a user program explicitly starts the LCPBTResponder thread.\r
+</li>\r
+<li>The number of files that can be uploaded to lejos NXJ is limited by the fact that the whole file table must fit into two 256-byte pages. If the average filename length is 15 characters, approximately 20 files are supported.\r
+</li>\r
+<li>The maximum filename length is 20 characters.\r
+</li>\r
+<li>Not all LEGO Communications Protocol command are supported, and the semantics of some of them are different from that of the standard LEGO firmware. In particular only one file can be open at a time and the file handle is always 0.\r
+</li>\r
+<li>The leJOS NXJ USB driver does not return a unique serial number for each NXT, in the way that the standard LEGO software does. The effects of this are not known, but it may be the cause of lejos NXJ not working with the LEGO fantom API over USB.\r
+</li>\r
+<li>Java streams over USB are never closed down, and are always open.\r
+</li>\r
+<li>Reading buttons is not very reliable unless your code takes steps to wait for button readings to stabilize. See the TextMenu code for how to do this.\r
+</li>\r
+<li>The RCX limitations of the Java VM also apply to NXJ.\r
+</li> \r
+<li>Sound volume cannot be controlled when playing tones.\r
+</li>\r
+<li>Support for sound sample files is limited to 8-bit WAV files with a sample rate of 11k.\r
+</li>\r
+<li>Data aborts occur if there is a failure in the NXJ VM. If a data abort occurs, it is necessary to remove and re-insert a battery.\r
+</li>\r
+<li>leJOS NXJ does not work with the LEGO Mindstorms PC software, or the LEGO Mindstorms Fantom API.\r
+</li>\r
+<li>On Windows, using the Bluecove library, NXTs that have been paired with the PC are in the list of available NXTs, even when they are not switched on. This does not happen with Bluez on Linux.\r
+</li>\r
+<li>Is usually necessary to pair your NXT using the Operating System before it can be connected to by the lejOS NXJ PC tools and libraries.\r
+</li>\r
+<li>Discovery of Bluetooth devices is slow, taking at least 10 seconds. It is slower still with Bluez on Linux. For Java streams connections from user programs, you can connect directly by Bluetooth address, which is much faster.\r
+</li>\r
+<li>To get permissions to the lejos NXJ usb devices from non-root users on Linux, you typically need to user pamconsole or udev rules. The instructions for doing this are not very explicit.\r
+</li>\r
+</ul>\r
 <h1><a name="documentation">Documentation</a></h1>\r
-Please download the leJOS documentation from\r
-the same location you downloaded this distribution from. The\r
-documentation contains the API docs. \r
+The API docs for leJOS NXJ is included in the download. You can also access them on the leJOS web site.\r
 <h1><a name="license">License</a></h1>\r
 We are continuing to release under the Mozilla Public License\r
-(see the LICENSE file). The runjava utility using David Anderson's libnxt
+(see the LICENSE file). The nxjflash utility using David Anderson's libnxt
 which is release under a GPL v2 license (see COPYING in the libnxt directory).\r
 <h1><a name="questions">Questions and Problems</a></h1>\r
 Please direct feedback to the lejos-discussion\r
 mailing list mailto:lejos-discussion@lists.sourceforge.net. <br>\r
 To subscribe, see </a><a\r
  href="http://lists.sourceforge.net/lists/listinfo/lejos-discussion">http://lists.sourceforge.net/lists/listinfo/lejos-discussion</a>.\r
-<p> Feel free to take a look at the <a href="http://www.lejos.org">Lejos\r
+<p> Feel free to take a look at the <a href="http://www.lejos.org">LeJOS\r
 website</a> or its <a href="http://sourceforge.net/projects/lejos">project\r
 page</a>. </p>\r
+\r
+<p>There are forums on the web site that can be used to ask questions, share information on projects, etc.</p>\r
 </body>\r
 </html>\r
index b9bb23b..6302ad4 100644 (file)
@@ -70,7 +70,7 @@ typedef struct S_Object
      }  __attribute__((packed)) freeBlock;
      struct _objects
      {
-       byte     class;
+       byte     _class;
        byte     padding:5;
        byte     mark:1;
        byte     isArray:1;
index 6a11bfc..7904134 100644 (file)
@@ -1,9 +1,17 @@
 #ifndef _CONSTANTS_H
 #define _CONSTANTS_H
 
+#ifndef null
 #define null ((void *) 0)
+#endif
+
+#ifndef true
 #define true (1)
+#endif
+
+#ifndef false
 #define false (0)
+#endif
 
 #define JNULL (0)
 
index e5db3b8..962eb8e 100644 (file)
@@ -27,7 +27,7 @@ extern byte throttle_count;
 
 static inline void init_poller()
 {
-  poller = null;
+  poller = (Poll *)null;
   throttle = 1;
   throttle_count = 1;
 }
index cd3918c..2a57247 100644 (file)
@@ -4,6 +4,8 @@
 #include "bt.h"
 #include "aic.h"
 #include  <string.h>
+#include "display.h"
+#include "systick.h"
 
 static U8 in_buf[2][128];
 static U8 in_buf_in_ptr, out_buf_ptr;
@@ -15,11 +17,12 @@ static int in_buf_idx = 0;
 
 #define BAUD_RATE 460800
 #define CLOCK_RATE 48054850
+
        
 void bt_init(void)
 {
   U8 trash;
-  
+  U32 trash2;
   in_buf_in_ptr = out_buf_ptr = 0; 
   in_buf_idx = 0;
   
@@ -62,8 +65,20 @@ void bt_init(void)
   *AT91C_PIOA_PER   = BT_ARM7_CMD_PIN; 
   *AT91C_PIOA_CODR  = BT_ARM7_CMD_PIN;
   *AT91C_PIOA_OER   = BT_ARM7_CMD_PIN; 
+  // Configure timer 01 as trigger for ADC, sample every 0.5ms
+  *AT91C_PMC_PCER = (1 << AT91C_PERIPHERAL_ID_TC1); 
+  *AT91C_TC1_CCR = AT91C_TC_CLKDIS;
+  *AT91C_TC1_IDR = ~0;
+  trash2 = *AT91C_TC1_SR;
+  *AT91C_TC1_CMR = AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_SET | AT91C_TC_ACPC_CLEAR | AT91C_TC_ASWTRG_SET; /* MCLK/2, wave mode 10 */
+  *AT91C_TC1_RC = (CLOCK_FREQUENCY/2)/(2000);
+  *AT91C_TC1_RA = (CLOCK_FREQUENCY/2)/(4000);
+  *AT91C_TC1_CCR = AT91C_TC_CLKEN;
+  *AT91C_TC1_CCR = AT91C_TC_SWTRG;
 
+  *AT91C_PMC_PCER = (1 << AT91C_PERIPHERAL_ID_ADC); 
   *AT91C_ADC_MR  = 0;
+  *AT91C_ADC_MR |= AT91C_ADC_TRGEN_EN | AT91C_ADC_TRGSEL_TIOA1;
   *AT91C_ADC_MR |= 0x00003F00;
   *AT91C_ADC_MR |= 0x00020000;
   *AT91C_ADC_MR |= 0x09000000;
@@ -74,18 +89,20 @@ void bt_init(void)
 
 void bt_start_ad_converter()
 {
-  *AT91C_ADC_CR = AT91C_ADC_START;
+  // This method is no longer required. The ADC is started automatically
+  // by the hardware timer.
 }
 
 U32 bt_get_mode()
 {
+  // return the bt4 mode value.
   return (U32) *AT91C_ADC_CDR6;
 }
 
 void bt_send(U8 *buf, U32 len)
 {
   if (*AT91C_US1_TNCR == 0)
-  {    
+  {
     memcpy(&(out_buf[out_buf_ptr][0]), buf, len);
     *AT91C_US1_TNPR = (unsigned int) &(out_buf[out_buf_ptr][0]);
     *AT91C_US1_TNCR = len;
@@ -93,6 +110,38 @@ void bt_send(U8 *buf, U32 len)
   }
 }
 
+U32 bt_write(U8 *buf, U32 off, U32 len)
+{
+  if (*AT91C_US1_TNCR == 0)
+  {    
+    if (len > 256) len = 256;  
+    memcpy(&(out_buf[out_buf_ptr][0]), buf+off, len);
+    *AT91C_US1_TNPR = (unsigned int) &(out_buf[out_buf_ptr][0]);
+    *AT91C_US1_TNCR = len;
+    out_buf_ptr = (out_buf_ptr+1) % 2;
+    return len;
+  }
+  else
+    return 0;
+}
+
+U32 bt_pending()
+{
+  // return the state of any pending i/o requests one bit for input one bit
+  // for output.
+  // First check for any input
+  int ret = 0;
+  int bytes_ready;
+  if (*AT91C_US1_RNCR == 0) 
+    bytes_ready = 256 - *AT91C_US1_RCR;
+  else 
+    bytes_ready = 128 - *AT91C_US1_RCR;
+  if (bytes_ready  > in_buf_idx) ret |= 1;
+  if ((*AT91C_US1_TCR != 0) || (*AT91C_US1_TNCR != 0)) ret |= 2;
+  return ret;
+}
+
+
 void bt_clear_arm7_cmd(void)
 {
   *AT91C_PIOA_CODR  = BT_ARM7_CMD_PIN;
@@ -175,8 +224,102 @@ void bt_receive(U8 * buf)
   }   
 }
 
+U32 bt_read(U8 * buf, U32 off, U32 len)
+{
+  int bytes_ready, total_bytes_ready;
+  int cmd_len, i;
+  U8* tmp_ptr;
+  
+  cmd_len = 0;
+  if (*AT91C_US1_RNCR == 0) {
+    bytes_ready = 128;
+    total_bytes_ready = 256 - *AT91C_US1_RCR;
+  }
+  else
+    total_bytes_ready = bytes_ready = 128 - *AT91C_US1_RCR;
+  
+  if (total_bytes_ready > in_buf_idx)
+  {
+    cmd_len = (int) (total_bytes_ready - in_buf_idx);
+    if (cmd_len > len) cmd_len = len;
+       
+    if (bytes_ready >= in_buf_idx + cmd_len)
+    {  
+      for(i=0;i<cmd_len;i++) buf[off+i] = buf_ptr[in_buf_idx++];
+    }
+    else
+    {
+      for(i=0;i<cmd_len && in_buf_idx < 128;i++) buf[off+i] = buf_ptr[in_buf_idx++];
+      in_buf_idx = 0;
+      tmp_ptr = &(in_buf[(in_buf_in_ptr+1)%2][0]);
+      for(;i<cmd_len;i++) buf[off+i] = tmp_ptr[in_buf_idx++];
+      in_buf_idx += 128;
+    } 
+  }
+  
+  // Current buffer full and fully processed
+  
+  if (in_buf_idx >= 128 && *AT91C_US1_RNCR == 0)
+  {    
+       // Switch current buffer, and set up next 
+       
+       in_buf_idx -= 128;
+       *AT91C_US1_RNPR = (unsigned int) buf_ptr;
+       *AT91C_US1_RNCR = 128;
+       in_buf_in_ptr = (in_buf_in_ptr+1) % 2;
+       buf_ptr = &(in_buf[in_buf_in_ptr][0]);
+  }
+  return cmd_len;   
+}
+
 void bt_set_reset_low(void)
 {
   *AT91C_PIOA_CODR = BT_RST_PIN;
 }
-       
+
+void bt_reset(void)
+{
+  // Perform hardware reset. This function has some relatively long
+  // delays in it and so should probably only be called during application
+  // initialisation and termination. Calling it at other times may cause
+  // problems for other real time tasks.
+
+  // If power is currently off to the BC4 do not reset it!
+  if ((*AT91C_PIOA_ODSR & BT_RST_PIN) == 0) return; 
+  //display_goto_xy(0, 1);
+  //display_string("BT Reset....");
+  //display_update();
+  //systick_wait_ms(10000);
+  // Ask for command mode
+  bt_clear_arm7_cmd();
+  // BC4 reset sequence. First take the reset line low for 100ms
+  bt_set_reset_low();
+  // Wait and discard any packets that may be around
+  int cnt = 100;
+  U8 *buf = out_buf[0];
+  while (cnt-- > 0)
+  {
+    bt_receive(buf);
+    systick_wait_ms(1);
+  }
+  bt_set_reset_high();
+  // Now wait either for 5000ms or for the BC4 chip to signal reset
+  // complete. Note we use the out buffer as a scratch area here
+  // this id safe since we are forcing a reset.
+  cnt = 5000;
+  while (cnt-- > 0)
+  {
+    bt_receive(buf);
+    // Look for the reset indication and the checksum
+    if ((buf[0] == 3) && (buf[1] == MSG_RESET_INDICATION) && 
+        (buf[2] == 0xff) && (buf[3] == 0xe9))
+        break;
+    systick_wait_ms(1);
+  }
+  // Force command mode
+  bt_clear_arm7_cmd();
+  //display_goto_xy(10, 1);
+  //display_int(cnt, 5);
+  //display_update();
+  //systick_wait_ms(10000);
+}
index b92b8d4..a53e4f9 100644 (file)
 #define MSG_SET_BRICK_STATUSBYTE_RESULT 50
 #define MSG_GET_BRICK_STATUSBYTE 51
 #define MSG_SET_BRICK_STATUSBYTE 52
+#define MSG_GET_OPERATING_MODE 53
+#define MSG_SET_OPERATING_MODE 54
+#define MSG_SET_OPERATING_MODE_RESULT 55
+#define MSG_GET_CONNECTION_STATUS 56
+#define MSG_CONNECTION_STATUS_RESULT 57
+#define MSG_GOTO_DFUMODE 58
+
+#define STREAM_BREAKING_MODE 0
+#define DONT_BREAK_STREAM_MODE 1
 
 #define   BT_RX_PIN  AT91C_PIO_PA21
 #define   BT_TX_PIN  AT91C_PIO_PA22
@@ -75,5 +84,9 @@ void bt_start_ad_converter(void);
 void bt_send(U8 *buf, U32 len);
 void bt_receive(U8 * buf);
 U32 bt_get_mode(void);
+void bt_reset(void);
+U32 bt_write(U8 *buf, U32 off, U32 len);
+U32 bt_read(U8 * buf, U32 off, U32 len);
+U32 bt_pending(void);
 
 #endif /*BT_H_*/
index ad6e32c..0e53c45 100644 (file)
@@ -19,7 +19,8 @@ data_abort_C(void)
   display_string("ASR  ");
   display_hex(*AT91C_MC_ASR, 8);
 
-  display_update();
+//  display_update();
+  display_force_update();
 
   while (1) {
   }
index 263084a..0a79950 100644 (file)
@@ -1,14 +1,27 @@
 #include "display.h"
 #include "nxt_lcd.h"
 #include "systick.h"
-
+#include "constants.h"
+#include "classes.h"
 #include <string.h>
 
 
 #define DISPLAY_WIDTH (NXT_LCD_WIDTH)
 #define DISPLAY_DEPTH (NXT_LCD_DEPTH)
 
-static U8 display_buffer[DISPLAY_DEPTH][DISPLAY_WIDTH];
+/* NOTE
+ * The following buffer is declared with one extra line (the +1).
+ * This is to allow fast dma update of the screen (see nxt_spi.c
+ * for details). The buffer is now created wrapped inside of a Java
+ * array. This allows the buffer to be shared with Java applications.
+ */
+//static U8 display_buffer[DISPLAY_DEPTH+1][DISPLAY_WIDTH];
+static struct
+{
+  Object hdr;
+  U8 display[DISPLAY_DEPTH+1][DISPLAY_WIDTH];
+} __attribute__((packed)) display_array;
+static U8 (*display_buffer)[DISPLAY_WIDTH] = display_array.display;
 
 /* Font table for a 5x8 font. 1 pixel spacing between chars */
 #define N_CHARS 128
@@ -148,19 +161,35 @@ static const U8 font[N_CHARS][FONT_WIDTH] = {
 /* 0x7F */ {0x3E, 0x36, 0x2A, 0x36, 0x3E},
 };
 
-
+int display_tick = 0;
+int display_auto_update = 1;
 
 void
 display_update(void)
 {
-  nxt_lcd_data((U8 *) display_buffer);
+  display_tick = 0;
+  nxt_lcd_update();
+}
+
+void display_set_auto_update(int mode)
+{
+  // Enable/disable automatic refresh of the display.
+  display_auto_update = mode;
+}
+  
+
+void display_force_update(void)
+{
+  // Force a display update even if interrupts are disabled
+  nxt_lcd_force_update();
 }
 
 
 void
 display_clear(U32 updateToo)
 {
-  memset(display_buffer, 0, sizeof(display_buffer));
+  //memset(display_buffer, 0, sizeof(display_buffer));
+  memset(display_buffer, 0, DISPLAY_WIDTH*DISPLAY_DEPTH);
   if (updateToo)
     display_update();
 }
@@ -318,14 +347,32 @@ display_bitmap_copy(const U8 *data, U32 width, U32 depth, U32 x, U32 y)
 U8 *
 display_get_buffer(void)
 {
-  return display_buffer;
+  return (U8 *)display_buffer;
+}
+
+STACKWORD
+display_get_array(void)
+{
+  return (STACKWORD)ptr2word(&display_array);
 }
 
 void
 display_init(void)
 {
-  nxt_lcd_init();
-  display_clear(1);
+  // Initialise the array parameters so that the display can
+  // be memory mapped into the Java address space
+  display_array.hdr.flags.arrays.isArray = 1;
+  // NOTE This object must always be marked, otherwise very, very bad
+  // things will happen!
+  display_array.hdr.flags.arrays.mark = 1;
+  display_array.hdr.flags.arrays.length = 200;
+  display_array.hdr.flags.arrays.isAllocated = 1;
+  display_array.hdr.flags.arrays.type = T_INT;
+  display_array.hdr.monitorCount = 0;
+  display_array.hdr.threadId = 0;
+  display_clear(0);
+  display_auto_update = 1;
+  nxt_lcd_init((U8 *)display_buffer);
 }
 
 void
@@ -333,7 +380,7 @@ display_test(void)
 {
   int iterator = 0;
 
-  nxt_lcd_init();
+  nxt_lcd_init((U8 *)display_buffer);
   while (1) {
     display_clear(0);
     display_goto_xy(iterator, 0);
index d5826be..fa32cb4 100644 (file)
@@ -7,6 +7,8 @@ void display_init(void);
 
 void display_update(void);
 
+void display_force_update(void);
+
 void display_clear(U32 updateToo);
 
 void display_goto_xy(int x, int y);
@@ -26,4 +28,9 @@ void display_test(void);
 
 U8 *display_get_buffer(void);
 
+void display_set_auto_update(int);
+
+extern int display_tick;
+extern int display_auto_update;
+
 #endif
index de1c039..39bdced 100644 (file)
@@ -1,6 +1,47 @@
 #include "flashprog.h"
 #include "interrupts.h"
+#include "twi.h"
+#include "systick.h"
+#include "nxt_avr.h"
 
+int
+flash_write_page(int start_page, U32 *page, int page_num)
+{
+  int i, istate;
+  
+  if (page_num + start_page > 1023) return 0;
+  
+  systick_suspend();
+       
+  systick_wait_ms(1);
+  nxt_avr_1kHz_update();
+  while (twi_busy());
+  
+  systick_wait_ms(1);
+  
+  istate = interrupts_get_and_disable();
+
+  while (!(FLASH_STATUS_REG & 0x1));
+
+  for (i = 0; i < 64; i++)
+    FLASH_BASE[(page_num*64)+i] = page[i];
+
+  FLASH_CMD_REG = (0x5A000001 + (((page_num + start_page) & 0x000003FF) << 8));
+
+  while (!(FLASH_STATUS_REG & 0x1));
+  
+  if (istate) interrupts_enable();
+  
+  systick_resume();
+  
+  return 1;
+}
+
+void flash_set_mode(U32 fmcn) {
+  FLASH_MODE_REG = ((fmcn << 16) | (1 << 8));
+}
 
 void
 flash_erase_range(U32 addr, U32 nBytes)
index 5ecb0b9..50404b6 100644 (file)
@@ -2,6 +2,20 @@
 #  define __FLASHPROG_H__
 #  include "mytypes.h"
 
+int flash_write_page(int start_page, U32 *buf, int page_num);
 void flash_erase_range(U32 addr, U32 nBytes);
 void flash_write(U32 addr, void *buffer, U32 nBytes);
+void flash_set_mode(U32 fmcn); 
+
+#define VINTPTR(addr) ((volatile unsigned int *)(addr))
+#define VINT(addr) (*(VINTPTR(addr)))
+
+
+#define FLASH_START_PAGE 128 /* 0x100000 + 32Kbyte(128*256) = 0x108000 */
+//#define FLASH_START_PAGE 320
+#define FLASH_BASE VINTPTR(0x00100000 + (FLASH_START_PAGE * 256))
+#define FLASH_MODE_REG VINT(0xFFFFFF60)
+#define FLASH_CMD_REG VINT(0xFFFFFF64)
+#define FLASH_STATUS_REG VINT(0xFFFFFF68)
+
 #endif
index 51d2e6f..54f2a18 100644 (file)
@@ -59,6 +59,19 @@ static const struct i2c_pin_pair i2c_pin[4] = {
 //
 // Note: It appears that the Lego ultrasonic sensor needs a 
 // stop and an extra clock before the restart.
+//
+// Additional changes made by Andy Shaw...
+//
+// Port 4 on the nxt is a little odd. It has extra hardware to implement
+// an RS485 interface. However this interacts with the digital I/O lines
+// which means that the original open collector driver used in this code
+// did not work. The code now uses a combination of open collector drive
+// on the clock lines (with pull up resistors enabled), plus a fully
+// driven ineterface on the data lines. This differs from the Lego
+// firmware which uses a fully driven clock inetrface. However doing so
+// means that it is hard (or impossible), to operate with the devices
+// that make use of clock stretching. It is hoped that the compromise
+// implemented here will work with all devices.
 
 
 struct i2c_partial_transaction {
@@ -156,6 +169,8 @@ i2c_timer_isr_C(void)
 
   U32 codr = 0;
   U32 sodr = 0;
+  U32 oer = 0;
+  U32 odr = 0;
   U32 inputs = *AT91C_PIOA_PDSR;
 
   struct i2c_port_struct *p = i2c_port;
@@ -177,6 +192,8 @@ i2c_timer_isr_C(void)
     case I2C_BEGIN:            
       // Start the current partial transaction
       p->pt_begun |= (1 << p->pt_num);
+      oer |= p->sda_pin;
+      oer |= p->scl_pin;
       
       if(p->current_pt && p->current_pt->nbytes){
         p->data = p->current_pt->data;
@@ -251,14 +268,18 @@ i2c_timer_isr_C(void)
         if(p->ack_slot) {
         
           if(p->transmitting)
-            sodr |= p->sda_pin;
+            odr |= p->sda_pin;
           else
+          {
+            oer |= p->sda_pin;
             codr |= p->sda_pin;
+          }
         
         } else if(!p->transmitting)
-          sodr |= p->sda_pin;
+          odr |= p->sda_pin;
         else {
           // Transmitting, and not an ack slot so send next bit
+          oer |= p->sda_pin;
           p->nbits--;
           if(((*(p->data)) >> (p->nbits & 7)) & 0x01)
             sodr |= p->sda_pin;
@@ -335,6 +356,7 @@ i2c_timer_isr_C(void)
       break;
     case I2C_STOP0:
       // Take SDA low (SCL is already low)
+      oer |= p->sda_pin;
       codr |= p->sda_pin;
       p->state = I2C_STOP1;
       break;  
@@ -366,6 +388,10 @@ i2c_timer_isr_C(void)
     *AT91C_PIOA_CODR = codr;
   if (sodr)
     *AT91C_PIOA_SODR = sodr;
+  if (oer)
+    *AT91C_PIOA_OER = oer;
+  if (odr)
+    *AT91C_PIOA_ODR = odr;
 }
 
 
@@ -389,10 +415,15 @@ i2c_enable(int port)
     struct i2c_port_struct *p = &i2c_port[port];
     U32 pinmask = p->scl_pin | p->sda_pin;
     p->state = I2C_IDLE;
-    /* Set pins for output, open collector driver */
+    /* Set clock pin for output, open collector driver, with
+     * pullups enabled. Set data to be enabled for output with
+     * pullups disabled.
+     */
     *AT91C_PIOA_SODR  = pinmask;
     *AT91C_PIOA_OER   = pinmask;
-    *AT91C_PIOA_MDER  = pinmask;
+    *AT91C_PIOA_MDER  = p->scl_pin;
+    *AT91C_PIOA_PPUDR = p->sda_pin;
+    *AT91C_PIOA_PPUER = p->scl_pin;
   }
 }
 
@@ -418,7 +449,7 @@ i2c_init(void)
   istate = interrupts_get_and_disable();
   
   /* Set up Timer Counter 0 */
-  *AT91C_PMC_PCER = (1 << AT91C_PERIPHERAL_ID_TC0);    /* Power enable */
+  *AT91C_PMC_PCER = (1 << AT91C_ID_TC0);    /* Power enable */
     
   *AT91C_TC0_CCR = 0x02; /* Disable */
   *AT91C_TC0_IDR = ~0;
@@ -428,9 +459,9 @@ i2c_init(void)
   *AT91C_TC0_IER = 0x10; /* Enable RC trigger interrupt */
   *AT91C_TC0_CCR = 1; /* Enable */
 
-  aic_mask_off(AT91C_PERIPHERAL_ID_TC0);
-  aic_set_vector(AT91C_PERIPHERAL_ID_TC0, AIC_INT_LEVEL_NORMAL, i2c_timer_isr_entry);
-  aic_mask_on(AT91C_PERIPHERAL_ID_TC0);
+  aic_mask_off(AT91C_ID_TC0);
+  aic_set_vector(AT91C_ID_TC0, AIC_INT_LEVEL_NORMAL, i2c_timer_isr_entry);
+  aic_mask_on(AT91C_ID_TC0);
   
   *AT91C_TC0_CCR = 0x04; /* Software trigger */
   
@@ -484,7 +515,8 @@ i2c_start_transaction(int port,
     // Set up first partial transaction: start address and internal address if required
 
     pt->start = 1;
-    pt->stop = 1;
+    // We add an extra stop for the odd Lego i2c sensor, but only on a read
+    pt->stop = (write ? 0 : 1);;
     pt->tx = 1;
     pt->data = p->addr_int;
     pt->nbytes = 2;
@@ -521,6 +553,7 @@ i2c_start_transaction(int port,
 
 // Test
 
+#if 0
 #include "nxt_avr.h"
 void i2c_test(void)
 { U8 xx[20];
@@ -535,3 +568,4 @@ void i2c_test(void)
     result = i2c_busy(0);
   }
 }
+#endif
index 6321136..c44ecc1 100644 (file)
@@ -87,7 +87,7 @@ continue_boot:
 @\r
 \r
        ldr r0,=0xFFFFFF60\r
-       ldr r1,=((50 << 16) | (1 << 8))\r
+       ldr r1,=((72 << 16) | (1 << 8))\r
        str r1,[r0]\r
 \r
 @\r
@@ -306,4 +306,3 @@ mif_16_loop:
        stmloia r0!,{r2-r5}\r
        blo   mif_16_loop\r
        bx    lr\r
-\r
index 9e1e872..6c2c258 100644 (file)
@@ -280,11 +280,19 @@ nxt_avr_set_motor(U32 n, int power_percent, int brake)
 void
 nxt_avr_set_input_power(U32 n, U32 power_type)
 {
-  // This does not correspond to the spec.
-  // It is unclear how to set power always on.
-  // Lego code has a bug in it.
-  if (n < NXT_AVR_N_INPUTS && power_type <= 1) {
-    io_to_avr.input_power &= ~(0x1 << (n));
-    io_to_avr.input_power |= (power_type << (n));
+  // The power to the sensor is controlled by a bit in
+  // each of the two nibbles of the byte. There is one
+  // bit for each of the four sensors. if the low nibble
+  // bit is set then the sensor is "ACTIVE" and 9v is
+  // supplied to it but it will be pulsed off to allow
+  // the sensor to be be read. A 1 in the high nibble
+  // indicates that it is a 9v always on sensor and
+  // 9v will be supplied constantly. If both bits are
+  // clear then 9v is not supplied to the sensor. 
+  // Having both bits set is currently not supported.
+  if (n < NXT_AVR_N_INPUTS && power_type <= 2) {
+    U8 val = (power_type & 0x2 ? 0x10 << n : 0) | ((power_type & 1) << n);
+    io_to_avr.input_power &= ~(0x11 << n);
+    io_to_avr.input_power |= val;
   }
 }
index 6d7b99b..4f6ced2 100644 (file)
@@ -3,7 +3,7 @@
 #include "systick.h"
 #include "string.h"
 
-
+static U8 *display = (U8 *)0;
 
 void
 nxt_lcd_command(U8 cmd)
@@ -117,21 +117,34 @@ nxt_lcd_set_cursor_update(U32 on)
   nxt_lcd_command(0xEE | ((on) ? 1 : 0));
 }
 
-
 void
-nxt_lcd_data(const U8 *data)
+nxt_lcd_force_update()
 {
+  // Update the screen the slow way. Works with interrupts disabled
   int i;
+  U8 *disp = display;
 
   for (i = 0; i < NXT_LCD_DEPTH; i++) {
     nxt_lcd_set_col(0);
     nxt_lcd_set_page_address(i);
 
-    nxt_spi_write(1, data, NXT_LCD_WIDTH);
-    data += NXT_LCD_WIDTH;
+    nxt_spi_write(1, disp, NXT_LCD_WIDTH);
+    disp += NXT_LCD_WIDTH;
   }
 }
 
+
+void
+nxt_lcd_update()
+{
+#define DMA_REFRESH
+#ifdef DMA_REFRESH
+  nxt_spi_refresh();
+#else
+  nxt_lcd_force_update();
+#endif
+}
+
 void
 nxt_lcd_power_up(void)
 {
@@ -143,17 +156,24 @@ nxt_lcd_power_up(void)
   nxt_lcd_set_bias_ratio(3);   // 1/9
   nxt_lcd_set_pot(0x60);       // ?? 9V??
 
-  nxt_lcd_set_ram_address_control(0);
-  nxt_lcd_set_map_control(0x02);
+  nxt_lcd_set_ram_address_control(1); // auto wrap
+  nxt_lcd_set_map_control(0x02); // mirror in y
 
+  nxt_spi_set_display(display);
   nxt_lcd_enable(1);
 
 }
 
 void
-nxt_lcd_init(void)
+nxt_lcd_power_down(void)
 {
+       nxt_lcd_reset();
+}
 
+void
+nxt_lcd_init(const U8 *disp)
+{
+  display = disp;
   nxt_spi_init();
 
   nxt_lcd_power_up();
index 76ff3b2..3b03d25 100644 (file)
@@ -6,10 +6,11 @@
 #  define NXT_LCD_WIDTH 100
 #  define NXT_LCD_DEPTH 8
 
-void nxt_lcd_init(void);
+void nxt_lcd_init(const U8 *disp);
 void nxt_lcd_power_up(void);
 void nxt_lcd_power_down(void);
-void nxt_lcd_data(const U8 *buffer);
+void nxt_lcd_update();
+void nxt_lcd_force_update();
 
 
 #endif
index 7414f04..e845bdd 100644 (file)
@@ -157,7 +157,7 @@ nxt_motor_init(void)
   /* Enable ISR */
   aic_mask_off(AT91C_PERIPHERAL_ID_PIOA);
   aic_set_vector(AT91C_PERIPHERAL_ID_PIOA, AIC_INT_LEVEL_NORMAL,
-                nxt_motor_isr_entry);
+                (U32) nxt_motor_isr_entry);
   aic_mask_on(AT91C_PERIPHERAL_ID_PIOA);
 
   *AT91C_PIOA_IER = MOTOR_INTERRUPT_PINS;
index 41c3f74..30044d8 100644 (file)
  *
  * Instead, the MISO pin is not used by the SPI
  * and is instead driven as a PIO pin for controlling CD.
+ *
+ * Addional notes from Andy Shaw
+ * The following code now contains the capability to perform display
+ * updates using dma, This code was inspired by the nxos lcd/spi code
+ * (Thanks guys). More details of nxos can be found at:
+ * http://nxt.natulte.net/nxos/trac
+ *
  */
 
 
 #define CS_PIN (1<<10)
 #define CD_PIN  (1<<12)
+const U8 *display = (U8 *) 0;
+volatile U8 dirty = 0;
+volatile U8 page = 0;
+volatile const U8 *data = (U8 *) 0;
+U8 mode = 0xff;
 
 extern void spi_isr_entry(void);
 
+static void spi_set_mode(U8 m)
+{
+  U32 status;
+
+  /* nothing to do if we are already in the correct mode */
+  if (m == mode) return;
+  
+  /* Wait until all bytes have been sent */
+  do {
+    status = *AT91C_SPI_SR;
+  } while (!(status & 0x200));
+  /* Set command or data mode */
+  if (m)
+    *AT91C_PIOA_SODR = CD_PIN;
+  else
+    *AT91C_PIOA_CODR = CD_PIN;
+  /* remember the current mode */
+  mode = m;
+}
+
+
 void
 spi_isr_C(void)
 {
+  if (page == 0)
+  {
+    /* Check to see if we have data to display */
+    if (dirty != 0)
+    {
+      data = display;
+      dirty = 0;
+    }
+    else
+    {
+      /* No so turn things off. It will get re-set if we ever have anything
+         to display
+      */
+      *AT91C_SPI_IDR = AT91C_SPI_ENDTX;
+      return;
+    }
+  }
+  /* Make sure we are in data mode */
+  spi_set_mode(1);
+  /* now do the transfer. We make use of the auto-wrap function so simply
+   * need to send 8*132 bytes to get back to where we started. However the
+   * display buffer is structured as series of 100 byte lines, so we need to
+   * get tricky. I've made the display one line longer (9 lines) and so when we
+   * send the data we send 100 bytes from the actual line plus 32 padding bytes
+   * (that are not actually seen), from the next line. The extra line means
+   * that this is safe to do. If we can redefine the display as a 8*132 then
+   * we could just use a single dma transfer (instead of 8, 132 byte ones).
+   * However I'm not sure if this would be safe.
+   */
+  *AT91C_SPI_TNPR = (U32) data;
+  *AT91C_SPI_TNCR = 132;
+  page = (page + 1) % 8;
+  data += 100;
 }
 
 
@@ -36,33 +102,58 @@ void
 nxt_spi_init(void)
 {
   int i_state = interrupts_get_and_disable();
-
-  /* Get clock */
-  *AT91C_PMC_PCER = (1 << AT91C_PERIPHERAL_ID_PIOA) |  /* Need PIO too */
-    (1 << AT91C_PERIPHERAL_ID_SPI);    /* SPI clock domain */
-  /* Get pins, oly MOSI and clock */
-  *AT91C_PIOA_PDR = /* (1<< 12) | */ (1 << 13) | (1 << 14);
-  *AT91C_PIOA_ASR = /* (1<< 12) | */ (1 << 13) | (1 << 14);
-
-
-  /* Set up MISO as an output to control CD.
-   * Set up CS pin
-   */
-  *AT91C_PIOA_SODR = CS_PIN | CD_PIN;
-  *AT91C_PIOA_PER = CS_PIN | CD_PIN;
-  *AT91C_PIOA_OER = CS_PIN | CD_PIN;
-
-
-  /* Set up SPI peripheral */
-  *AT91C_SPI_CR = 1;           /* Enable */
-  *AT91C_SPI_MR = 0x06000001;
-  *AT91C_SPI_IDR = ~0;         /* Disable all interrupts */
-  AT91C_SPI_CSR[0] = 0x18181801;
-  AT91C_SPI_CSR[1] = 0x18181801;
-  AT91C_SPI_CSR[2] = 0x18181801;
-  AT91C_SPI_CSR[3] = 0x18181801;
-
-  /* Todo set up interrupt */
+#define OSC 48054805
+#define SPI_BITRATE 2000000
+
+  *AT91C_PMC_PCER  =  (1L << AT91C_ID_SPI);       /* Enable MCK clock     */
+  *AT91C_PIOA_PER = AT91C_PIO_PA12;/*EnableA0onPA12*/
+  *AT91C_PIOA_OER = AT91C_PIO_PA12;
+  *AT91C_PIOA_CODR = AT91C_PIO_PA12;
+  *AT91C_PIOA_PDR = AT91C_PA14_SPCK;/*EnableSPCKonPA14*/
+  *AT91C_PIOA_ASR = AT91C_PA14_SPCK;
+  *AT91C_PIOA_ODR = AT91C_PA14_SPCK;
+  *AT91C_PIOA_OWER = AT91C_PA14_SPCK;
+  *AT91C_PIOA_MDDR = AT91C_PA14_SPCK;
+  *AT91C_PIOA_PPUDR = AT91C_PA14_SPCK;
+  *AT91C_PIOA_IFDR = AT91C_PA14_SPCK;
+  *AT91C_PIOA_CODR = AT91C_PA14_SPCK;
+  *AT91C_PIOA_IDR = AT91C_PA14_SPCK;
+  *AT91C_PIOA_PDR = AT91C_PA13_MOSI;/*EnablemosionPA13*/
+  *AT91C_PIOA_ASR = AT91C_PA13_MOSI;
+  *AT91C_PIOA_ODR = AT91C_PA13_MOSI;
+  *AT91C_PIOA_OWER = AT91C_PA13_MOSI;
+  *AT91C_PIOA_MDDR = AT91C_PA13_MOSI;
+  *AT91C_PIOA_PPUDR = AT91C_PA13_MOSI;
+  *AT91C_PIOA_IFDR = AT91C_PA13_MOSI;
+  *AT91C_PIOA_CODR = AT91C_PA13_MOSI;
+  *AT91C_PIOA_IDR = AT91C_PA13_MOSI;
+  *AT91C_PIOA_PDR = AT91C_PA10_NPCS2;/*Enablenpcs0onPA10*/
+  *AT91C_PIOA_BSR = AT91C_PA10_NPCS2;
+  *AT91C_PIOA_ODR = AT91C_PA10_NPCS2;
+  *AT91C_PIOA_OWER = AT91C_PA10_NPCS2;
+  *AT91C_PIOA_MDDR = AT91C_PA10_NPCS2;
+  *AT91C_PIOA_PPUDR = AT91C_PA10_NPCS2;
+  *AT91C_PIOA_IFDR = AT91C_PA10_NPCS2;
+  *AT91C_PIOA_CODR = AT91C_PA10_NPCS2;
+  *AT91C_PIOA_IDR = AT91C_PA10_NPCS2;
+  *AT91C_SPI_CR = AT91C_SPI_SWRST;/*Softreset*/
+  *AT91C_SPI_CR = AT91C_SPI_SPIEN;/*Enablespi*/
+  *AT91C_SPI_MR = AT91C_SPI_MSTR|AT91C_SPI_MODFDIS | (0xB<<16);
+  AT91C_SPI_CSR[2] = ((OSC/SPI_BITRATE)<<8) | AT91C_SPI_CPOL;
+
+  /* Set mode to unknown */
+  mode = 0xff;
+
+  /* Set up safe dma refresh state */
+  data = display = (U8 *) 0;
+  dirty = 0;
+  page = 0;
+
+  /* Install the interrupt handler */
+  aic_mask_off(AT91C_PERIPHERAL_ID_SPI);
+  aic_set_vector(AT91C_PERIPHERAL_ID_SPI, AIC_INT_LEVEL_NORMAL, (U32)spi_isr_entry);
+  aic_mask_on(AT91C_PERIPHERAL_ID_SPI);
+  *AT91C_SPI_PTCR = AT91C_PDC_TXTEN;
 
   if (i_state)
     interrupts_enable();
@@ -75,16 +166,7 @@ nxt_spi_write(U32 CD, const U8 *data, U32 nBytes)
   U32 status;
   U32 cd_mask = (CD ? 0x100 : 0);
 
-  *AT91C_PIOA_PER = CS_PIN;
-  *AT91C_PIOA_SODR = CS_PIN;   /* Set high */
-  *AT91C_PIOA_CODR = CS_PIN;   /* Set Low */
-
-  if (CD)
-    *AT91C_PIOA_SODR = CD_PIN;
-  else
-    *AT91C_PIOA_CODR = CD_PIN;
-
-
+  spi_set_mode(CD);
   while (nBytes) {
     *AT91C_SPI_TDR = (*data | cd_mask);
     data++;
@@ -95,6 +177,27 @@ nxt_spi_write(U32 CD, const U8 *data, U32 nBytes)
     } while (!(status & 0x200));
 
   }
-  *AT91C_PIOA_SODR = CS_PIN;   /* Set high */
+}
 
+void
+nxt_spi_set_display(const U8 *disp)
+{
+  /* Set the display buffer to be used for dma refresh.
+   * it is really only safe to set the display once. Should probably
+   * sort this out so that it is set separately from requesting a refresh
+   */
+  if (!display) display = disp;
+}
+
+void
+nxt_spi_refresh(void)
+{
+  /* Request the start of a dma refresh of the display 
+   */
+  // If the display is not set nothing to do.
+  if (!display) return;
+  // Say we have changes
+  dirty = 1;
+  // Start the DMA refresh
+  *AT91C_SPI_IER = AT91C_SPI_ENDTX;
 }
index 5807127..73dbf11 100644 (file)
@@ -17,5 +17,7 @@
 
 void nxt_spi_init(void);
 void nxt_spi_write(U32 CD, const U8 *data, U32 nBytes);
+void nxt_spi_set_display(const U8 *disp);
+void nxt_spi_refresh(void);
 
 #endif
index a8943ae..26a97ed 100644 (file)
@@ -29,6 +29,13 @@ init_sensors(void)
     unset_digi1(i);
     nxt_avr_set_input_power(i, 0);
   }
+  /* Ensure RS485 is inactive. Otherwise it can interfere with
+   * the operation of port 4.
+   */
+  *AT91C_PIOA_PER |= AT91C_PIO_PA5 | AT91C_PIO_PA6 | AT91C_PIO_PA7;
+  *AT91C_PIOA_PPUDR |= AT91C_PIO_PA5 | AT91C_PIO_PA6 | AT91C_PIO_PA7;
+  *AT91C_PIOA_OER |= AT91C_PIO_PA5 | AT91C_PIO_PA6 | AT91C_PIO_PA7;
+  *AT91C_PIOA_CODR |= AT91C_PIO_PA5 | AT91C_PIO_PA6 | AT91C_PIO_PA7;
 }
 
 /**
index 14e939e..9205ad0 100644 (file)
+/* leJOS Sound generation
+ * The module provides support for audio output. Two modes are supported, tone
+ * generation and the playback of PCM based audio samples. Both use pulse 
+ * density modulation to actually produce the output.
+ * To produce a tone a single pdm encoded cycle is created (having the 
+ * requested amplitude), this single cycle is then played repeatedly to
+ * generate the tone. The bit rate used to output the sample defines the
+ * frequency of the tone and the number of repeats represents then length.
+ * To play an encoded sample (only 8 bit PCM is currently supported), each PCM
+ * sample is turned into a 256 bit pdm block, which is then output (at the
+ * sample rate), to create the output. Again the amplitude of the samples may
+ * be controlled. 
+ * The actual output of the bits is performed using the built in Synchronous
+ * Serial Controller (SSC). This is capable of outputing a series of bits to
+ * port at fixed intervals and is used to output the pdm audio.
+ */
 #include "mytypes.h"
 #include "sound.h"
 #include "AT91SAM7.h"
 #include "aic.h"
+#include "nxt_avr.h"
+#include <string.h>
+#include "display.h"
+#include "systick.h"
+
+/* Buffer length must be a multiple of 8 and at most 64 (preferably as long as possible) */
+#define PDM_BUFFER_LENGTH 64
+/* Main clock frequency */
+#define OSC CLOCK_FREQUENCY
+/* Size of a sample block */
+#define SAMPBITS 256
+#define SAMPBYTES SAMPBITS/8
+#define SAMPWORDS SAMPBITS/32
+
+#define MAXRATE 22050
+#define MINRATE 2000
+#define DEFRATE 8000
 
 extern void sound_isr_entry(void);
 
-const U32 tone_pattern[16] = 
+enum {
+  SOUND_MODE_NONE,
+  SOUND_MODE_SILENCE,
+  SOUND_MODE_TONE,
+  SOUND_MODE_PCM
+};
+
+/* Numbers with 0-32 evenly spaced bits set */
+const U32 sample_pattern[33] =
   {
-    0xF0F0F0F0,0xF0F0F0F0,
-    0xFCFCFCFC,0xFCFCFDFD,
-    0xFFFFFFFF,0xFFFFFFFF,
-    0xFDFDFCFC,0xFCFCFCFC,
-    0xF0F0F0F0,0xF0F0F0F0,
-    0xC0C0C0C0,0xC0C08080,
-    0x00000000,0x00000000,
-    0x8080C0C0,0xC0C0C0C0
+    0x00000000, 0x80000000, 0x80008000, 0x80200400,
+    0x80808080, 0x82081040, 0x84208420, 0x88442210,
+    0x88888888, 0x91224488, 0x92489248, 0xa4924924,
+    0xa4a4a4a4, 0xa94a5294, 0xaa54aa54, 0xaaaa5554,
+    0xaaaaaaaa, 0xd555aaaa, 0xd5aad5aa, 0xd6b5ad6a,
+    0xdadadada, 0xdb6db6da, 0xedb6edb6, 0xeeddbb76,
+    0xeeeeeeee, 0xf7bbddee, 0xfbdefbde, 0xfdf7efbe,
+    0xfefefefe, 0xffdffbfe, 0xfffefffe, 0xfffffffe,
+    0xffffffff
   };
-  
-U32 tone_cycles;
+
+volatile U8 sound_mode = SOUND_MODE_NONE;
+
+// add volatile because GCC does over optimisations
+struct {
+  // pointer to the next sample
+  volatile U8 *ptr;
+  // The number of samples ahead
+  volatile S32 count;
+  // 0 or 1, identifies the current buffer
+  volatile U8 buf_id;
+  // Double buffer
+  volatile U32 buf[2][PDM_BUFFER_LENGTH];
+  // Amplification LUT
+  volatile U8 amp[257];
+  // Volume val used to create the amp LUT
+  volatile S32 cur_vol;
+  // Clock divisor to use to play the sample
+  volatile U32 clock_div;
+  // Size of the sample
+  volatile U32 len;
+} sample;
+
+/* The following tables provide input to the wave generation code. This
+ * code takes a set of points describing one half cycle of a symmetric waveform
+ * and from this creates a pdm encoded version of a single full cycle of the
+ * wave. 
+ *
+ * A number of sample wave shapes have been tried, an accurates sine wave, a
+ * square wave, triangular wave and a rough approximation of a sine wave.
+ * Currently the rough sine wave is used, the sqaure wave also works well.
+ * The purer shapes do not seem to work very well at frequencies below
+ * about 800Hz. It seems that a combination of the sounder and the Lego
+ * amplifier electronics mean that the response below this is very poor.
+ * However by using a waveform like a square wave that has a lot of harminics
+ * the ear can be fooled into hearing the lower frequencies. Using a pure wave
+ * form like the sine wave results in a very low volume. This rather surprising
+ * result has to some extent been validated using an audio spectrum analyzer
+ * which shows vertually no fundamental below 700Hz but lots of harmonics.
+ *
+ * The square wave also produces a higher volume than other wave shapes. 
+ * Higher volumes can be achieved when using the rough sine wave by allowing
+ * the volume setting to push the shape into distortion and effectively
+ * becomming a square wave!
+ */
+//const U8 sine[] =  {0xa8, 0xc0, 0xca, 0xd4, 0xe0, 0xe9, 0xff, 0xff, 0xff, 0xff, 0xe9, 0xe0, 0xd4, 0xca, 0xc0, 0xa8};
+//const U8 sine[] =  {0xb0, 0xc0, 0xca, 0xd4, 0xe0, 0xe9, 0xf2, 0xff, 0xff, 0xf2, 0xe9, 0xe0, 0xd4, 0xca, 0xc0, 0xb0};
+//const U8 sine[] =  {0xc0, 0xc8, 0xd0, 0xd8, 0xe0, 0xea, 0xf4, 0xff, 0xff, 0xf4, 0xea, 0xe0, 0xd8, 0xd0, 0xc8, 0xc0};
+const U8 sine[] =  {0xc0, 0xc8, 0xd0, 0xd8, 0xe0, 0xea, 0xf4, 0xff, 0xff, 0xf0, 0xe5, 0xdc, 0xd4, 0xcc, 0xc4, 0xbc};
+//const U8 sine[] =  {0x98, 0xb0, 0xc7, 0xda, 0xea, 0xf6, 0xfd, 0xff, 0xff, 0xfd, 0xf6, 0xea, 0xda, 0xc7, 0xb0, 0x98};
+// Time required to generate the tone and volume lookup table...
+#define TONE_OVERHEAD 1
+
+/* To minimise the number of cracks and pops when playing a series of tones
+ * and/or samples we output a shprt period of "silence" at the end of each
+ * sample. A small click is generated when turning off the sound system so
+ * by filling small gaps with explicit silence we can avoid this additonal
+ * noise.
+ */
+
+const U32 silence[16] = {
+0xaaaaaaaa, 0xaaaaaaaa,
+0xaaaaaaaa, 0xaaaaaaaa,
+0xaaaaaaaa, 0xaaaaaaaa,
+0xaaaaaaaa, 0xaaaaaaaa,
+0xaaaaaaaa, 0xaaaaaaaa,
+0xaaaaaaaa, 0xaaaaaaaa,
+0xaaaaaaaa, 0xaaaaaaaa,
+0xaaaaaaaa, 0xaaaaaaaa
+};
+#define SILENCE_CLK (OSC/(16*32*2) + 250/2)/250
+#define SILENCE_CNT 50
+
+// We use a volume law that approximates a log function. The values in the
+// table below have been hand tuned to try and provide a smooth change in
+// the loudness of both tones and samples.
+//const U8 logvol[] = {0, 4, 16, 28, 40, 52, 64, 78, 93, 109, 128, 196, 255, 255};
+//const U8 logvol[] = {0, 8, 24, 40, 56, 80, 104, 128, 160, 208, 255, 255};
+const U8 logvol[] = {0, 8, 24, 40, 56, 80, 104, 128, 162, 196, 255, 255};
+
+
 
 void sound_init()
 {
+  // Initialise the hardware. We make use of the SSC module.
   sound_interrupt_disable();
   sound_disable();
   
-  *AT91C_PMC_PCER = (1 << AT91C_PERIPHERAL_ID_SSC);
-
-  //*AT91C_PIOA_ODR = AT91C_PA17_TD;
-  //*AT91C_PIOA_OWDR = AT91C_PA17_TD;
-  //*AT91C_PIOA_MDDR = AT91C_PA17_TD;
-  //*AT91C_PIOA_PPUDR = AT91C_PA17_TD;
-  //*AT91C_PIOA_IFDR = AT91C_PA17_TD;
-  //*AT91C_PIOA_CODR = AT91C_PA17_TD;
+  *AT91C_PMC_PCER = (1 << AT91C_ID_SSC);
+
+  *AT91C_PIOA_ODR = AT91C_PA17_TD;
+  *AT91C_PIOA_OWDR = AT91C_PA17_TD;
+  *AT91C_PIOA_MDDR = AT91C_PA17_TD;
+  *AT91C_PIOA_PPUDR = AT91C_PA17_TD;
+  *AT91C_PIOA_IFDR = AT91C_PA17_TD;
+  *AT91C_PIOA_CODR = AT91C_PA17_TD;
+  *AT91C_PIOA_IDR = AT91C_PA17_TD;
   
   *AT91C_SSC_CR = AT91C_SSC_SWRST;
   *AT91C_SSC_TCMR = AT91C_SSC_CKS_DIV + AT91C_SSC_CKO_CONTINOUS + AT91C_SSC_START_CONTINOUS;
   *AT91C_SSC_TFMR = 31 + (7 << 8) + AT91C_SSC_MSBF; // 8 32-bit words
   *AT91C_SSC_CR = AT91C_SSC_TXEN;                                        
 
-  aic_mask_on(AT91C_PERIPHERAL_ID_SSC);
-  aic_clear(AT91C_PERIPHERAL_ID_SSC);
-  aic_set_vector(AT91C_PERIPHERAL_ID_SSC, AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED,
-                sound_isr_entry);
+  aic_mask_on(AT91C_ID_SSC);
+  aic_clear(AT91C_ID_SSC);
+  aic_set_vector(AT91C_ID_SSC, AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED,
+                (U32)sound_isr_entry); /*PG*/
+  sample.buf_id = 0;
+  sample.cur_vol = -1;
+}
+
+static void create_tone(const U8 *lookup, int lulen, U32 *pat, int len)
+{
+  // Fill the supplied buffer with len longs representing a pdm encoded
+  // wave. We use a pre-generated lookup table for the wave shape.
+  // The shape will be symmetric. The original code used interpolation as part
+  // of the lookup but this was too slow. 
+  int numsamples = len*32/2;
+  int step = numsamples/lulen;
+  int word = 0;
+  U32 bit = 0x80000000;
+  U32 bit2 = 0x00000001;
+  int i = numsamples/step;;
+  int error = 0;
+  int error2 = 0;
+  int out=0;
+  U32 bits = 0;
+  U32 bits2 = 0;
+  int entry = 0;
+  
+  while (i-- > 0)
+  {
+    int res = lookup[entry++];
+    res = sample.amp[res] - 128;
+    int j = step;
+    while (j-- > 0)
+    {
+      // Perform pdm conversion    
+      error = res - out + error;
+      error2 = error - out + error2;
+      if (error2 > 0)
+      {
+        out = 127;
+        bits |= bit;
+      }
+      else
+      {
+        out = -127;
+        bits2 |= bit2;
+      }
+      bit2 <<= 1;
+      bit >>= 1;
+      if (bit == 0)
+      {
+        bit = 0x80000000;
+        bit2 = 0x00000001;
+        pat[word++] = bits;
+        pat[len - word] = bits2;
+        bits2 = bits = 0;
+      }
+    }
+  }
+}
+
+static void set_vol(int vol)
+{
+  // Create the amplification control lookup table. We use a logartihmic
+  // volume system mapped into a range of 0 to 120. 0 is muted, 100 is
+  // full volume, 120 is driving into overload.
+  int i;
+  S32 output;
+
+  // Get into range and use log conversion
+  if (vol < 0) vol = 0;
+  if (vol > MAXVOL) vol = MAXVOL;
+  // Do we need to create a new LUT?
+  if (sample.cur_vol == vol) return;
+  output = logvol[vol/10];
+  output = output + ((logvol[vol/10 + 1]-output)*(vol%10))/10;
+
+  // Create the symmetric lookup table
+  for(i = 0; i <= 128; i++)
+  {
+    S32 a = (i*output)/128;
+    S32 b = a;
+    if (a > 127)
+    {
+      a = 127;
+      b = 128;
+    }
+    sample.amp[128-i] = 128 - b; 
+    sample.amp[i+128] = a + 128;
+  }
+  sample.cur_vol = vol;
 }
 
 void sound_freq(U32 freq, U32 ms)
 {
-  *AT91C_SSC_CMR = ((96109714 / 1024) / freq) + 1;
+       sound_freq_vol(freq, ms, 70);
+}
+
+void sound_freq_vol(U32 freq, U32 ms, int vol)
+{
+  // Set things up ready to go, note we avoid using anything that may
+  // be used by the interupt routine because ints may still be enabled
+  // at this point
+  int len;
+  // we use longer samples for lower frequencies
+  if (freq > 1000)
+    len = 16;
+  else if (freq < 500)
+    len = 64;
+  else
+    len = 32;
+  sound_mode = SOUND_MODE_TONE;
+  // Update the volume lookup table if we need to
+  set_vol(vol);
+  int buf = sample.buf_id^1;
+  create_tone(sine, sizeof(sine), sample.buf[buf], len); 
+  // The note gneration takes approx 1ms, to ensure that we do not get gaps
+  // when playing a series of tones we extend the requested period to cover
+  // this 1ms cost.
+  ms += TONE_OVERHEAD;
+  // Turn of ints while we update shared values
+  sound_interrupt_disable();
+  /* Genrate the pdm wave of the correct amplitude */
+  sample.clock_div = (OSC/(len*32*2) + freq/2)/freq;
+  // Calculate actual frequency and use this for length calc
+  freq = (OSC/(2*sample.clock_div))/(len*32);
+  if (ms <= TONE_OVERHEAD)
+    sample.count = 0;
+  else
+    sample.count = (freq*ms + 1000-1)/1000;
+  sample.len = len;
+  sample.ptr = (U8 *)sample.buf[buf];
+  sample.buf_id = buf;
   *AT91C_SSC_PTCR = AT91C_PDC_TXTEN;
-  tone_cycles = (freq * ms) / 2000 - 1;
-  sound_interrupt_enable();
+  sound_mode = SOUND_MODE_TONE;
+  sound_interrupt_enable(AT91C_SSC_TXBUFE);
 }
 
-void sound_interrupt_enable()
+void sound_interrupt_enable(U32 typ)
 {
-  *AT91C_SSC_IER = AT91C_SSC_ENDTX;
+  // Enable interrupt notification of either the end of the next buffer
+  // or the end of all output. Having both enabled does not seem to work
+  // the end notifaction seems to get lost.
+  *AT91C_SSC_IDR = AT91C_SSC_TXBUFE;
+  *AT91C_SSC_IDR = AT91C_SSC_ENDTX;
+  *AT91C_SSC_IDR = AT91C_SSC_TXEMPTY;
+  *AT91C_SSC_IER = typ;
 }
 
 void sound_interrupt_disable()
 {
+  *AT91C_SSC_IDR = AT91C_SSC_TXBUFE;
   *AT91C_SSC_IDR = AT91C_SSC_ENDTX;
+  *AT91C_SSC_IDR = AT91C_SSC_TXEMPTY;
 }
 
 void sound_enable()
@@ -72,17 +327,122 @@ void sound_disable()
   *AT91C_PIOA_PER = AT91C_PA17_TD;
 }
 
-void sound_isr_C()
+void sound_fill_sample_buffer() {
+  sample.buf_id ^= 1;
+  U32 *sbuf = sample.buf[sample.buf_id];
+  U8 i;
+  /* Each 8-bit sample is turned into 8 32-bit numbers, i.e. 256 bits altogether */
+  for (i = 0; i < PDM_BUFFER_LENGTH >> 3; i++) {
+    U8 smp = (sample.count > 0 ? sample.amp[*sample.ptr] : 128);
+    U8 msk = "\x00\x10\x22\x4a\x55\x6d\x77\x7f"[smp & 7];
+    U8 s3 = smp >> 3;
+    *sbuf++ = sample_pattern[s3 + (msk & 1)]; msk >>= 1;
+    *sbuf++ = sample_pattern[s3 + (msk & 1)]; msk >>= 1;
+    *sbuf++ = sample_pattern[s3 + (msk & 1)]; msk >>= 1;
+    *sbuf++ = sample_pattern[s3 + (msk & 1)]; msk >>= 1;
+    *sbuf++ = sample_pattern[s3 + (msk & 1)]; msk >>= 1;
+    *sbuf++ = sample_pattern[s3 + (msk & 1)]; msk >>= 1;
+    *sbuf++ = sample_pattern[s3 + (msk & 1)];
+    *sbuf++ = sample_pattern[s3];
+/*
+      //An alternative that doesn't need a sample_pattern array:
+      U32 msb = 0xffffffff << (32 - (smp >> 3));
+      *sbuf++ = msb | ((msk & 1) ? msb >> 1 : 0); msk >>= 1;
+      *sbuf++ = msb | ((msk & 1) ? msb >> 1 : 0); msk >>= 1;
+      *sbuf++ = msb | ((msk & 1) ? msb >> 1 : 0); msk >>= 1;
+      *sbuf++ = msb | ((msk & 1) ? msb >> 1 : 0); msk >>= 1;
+      *sbuf++ = msb | ((msk & 1) ? msb >> 1 : 0); msk >>= 1;
+      *sbuf++ = msb | ((msk & 1) ? msb >> 1 : 0); msk >>= 1;
+      *sbuf++ = msb | ((msk & 1) ? msb >> 1 : 0); 
+      *sbuf++ = msb;
+*/
+    sample.ptr++;
+    sample.count--;
+  }
+}
+
+void sound_play_sample(U8 *data, U32 length, U32 freq, int vol)
+{
+  if (data == (U8 *) 0 || length == 0) return;
+  // Calculate the clock divisor based upon the recorded sample frequency */
+  if (freq == 0) freq = DEFRATE;
+  if (freq > MAXRATE) freq = MAXRATE;
+  if (freq < MINRATE) freq = MINRATE;
+  U32 cdiv = (OSC/(2*SAMPBITS) + freq/2)/freq;
+  set_vol(vol);
+  // Turn off ints while we update shared values
+  sound_interrupt_disable();
+  sound_mode = SOUND_MODE_PCM;
+  sample.count = length;
+  sample.ptr = data;
+  sample.len = PDM_BUFFER_LENGTH;
+  sample.clock_div = cdiv;
+  // re-enable and wait for the current sample to complete
+  sound_interrupt_enable(AT91C_SSC_TXBUFE);
+  *AT91C_SSC_PTCR = AT91C_PDC_TXTEN;
+}
+
+int sound_get_time()
 {
-  if (tone_cycles--)
+  // Return the amount of time still to play for the current tone/sample
+  if (sound_mode > SOUND_MODE_SILENCE)
   {
-    *AT91C_SSC_TNPR = (unsigned int) tone_pattern;
-    *AT91C_SSC_TNCR = 16;
-    sound_enable();
+       // long long int is needed to avoid overflow (this is a bug in leJOS original code)
+    int ms = (int)(((long long int)sample.count*1000*sample.len*32)/(OSC/(2*sample.clock_div)));
+    // remove the extra time we added
+    if (sound_mode == SOUND_MODE_TONE && ms > 0) ms -= TONE_OVERHEAD;
+    return ms;
   }
   else
-  {
-       sound_disable();
-       sound_interrupt_disable();
-  }
+    return 0;
+}
+
+void sound_isr_C()
+{
+    if (sample.count > 0)
+    {
+      // refill the buffer, and adjust any clocks
+      *AT91C_SSC_CMR = sample.clock_div;
+      sound_enable();
+      if (*AT91C_SSC_TCR == 0)
+      {
+        if (sound_mode == SOUND_MODE_PCM)
+        {
+          sound_fill_sample_buffer();
+          *AT91C_SSC_TPR = (unsigned int)sample.buf[sample.buf_id];
+        }
+        else
+          *AT91C_SSC_TPR = (unsigned int)sample.ptr;
+        *AT91C_SSC_TCR = sample.len;
+        sample.count--;
+      }
+      if (sound_mode == SOUND_MODE_PCM)
+      {
+        sound_fill_sample_buffer();
+        *AT91C_SSC_TNPR = (unsigned int)sample.buf[sample.buf_id];
+      }
+      else
+        *AT91C_SSC_TNPR = (unsigned int)sample.ptr;
+      *AT91C_SSC_TNCR = sample.len;
+      sample.count--;
+      // If this is the last sample wait for it to complete, otherwise wait
+      // to switch buffers
+      sound_interrupt_enable(sample.count <= 0 ? (sound_mode == SOUND_MODE_SILENCE ? AT91C_SSC_TXEMPTY : AT91C_SSC_TXBUFE) : AT91C_SSC_ENDTX);
+    }
+    else if (sound_mode == SOUND_MODE_SILENCE)
+    {
+      sound_mode = SOUND_MODE_NONE;
+      sound_disable();
+      sound_interrupt_disable();
+    }
+    else
+    {
+      // Add a short section of silence after the sample/tone
+      sound_mode = SOUND_MODE_SILENCE;
+      sample.clock_div = SILENCE_CLK;
+      sample.ptr = (U8 *)silence;
+      sample.count = SILENCE_CNT;
+      sample.len = 16;
+      sound_isr_C();
+    }
 }
index 49061d9..d200e8b 100644 (file)
@@ -11,5 +11,12 @@ void sound_disable();
 void sound_isr_C();
 
 void sound_freq(U32 freq, U32 ms);
+void sound_freq_vol(U32 freq, U32 ms, int vol);
+void sound_play_sample(U8 *data, U32 length, U32 freq, int vol);
+void sound_set_volume(int vol);
+int sound_get_volume();
+int sound_get_time();
+
+#define MAXVOL 100
 
 #endif /*SOUND_H_*/
index 9a0c829..c97c979 100644 (file)
@@ -34,7 +34,7 @@ void
 systick_low_priority_C(void)
 {
   *AT91C_AIC_ICCR = (1 << LOW_PRIORITY_IRQ);
-  gMakeRequest = 1;            // trigger Java tick request
+//  gMakeRequest = 1;          // trigger Java tick request
   nxt_avr_1kHz_update();
   nxt_motor_1kHz_process();
 }
@@ -138,3 +138,14 @@ systick_test(void)
     systick_wait_ms(2000);
   }
 }
+
+void systick_suspend()
+{
+  aic_mask_off(LOW_PRIORITY_IRQ);
+}
+
+void systick_resume()
+{
+  aic_mask_on(LOW_PRIORITY_IRQ);
+}
+
index f547aeb..013c4a4 100644 (file)
@@ -15,4 +15,8 @@ void systick_wait_ns(U32 n);
 
 void systick_test(void);
 
+void systick_suspend(void);
+
+void systick_resume(void);
+
 #endif
index 0c4a856..38651cc 100644 (file)
 
 #include "aic.h"
 
-
+// added by takashic 2008-11-14
+// Calculate required clock divisor
+#define   I2CClk                        400000L
+#define   CLDIV                         (((CLOCK_FREQUENCY/I2CClk)/2)-3)
 
 extern void twi_isr_entry(void);
 
@@ -25,10 +28,10 @@ static enum {
   TWI_FAILED
 } twi_state;
 
-static U32 twi_pending;
-static U8 *twi_ptr;
+static volatile U32 twi_pending;
+static volatile U8 *twi_ptr;
 
-static struct {
+static volatile struct {
   U32 rx_done;
   U32 tx_done;
   U32 bytes_tx;
@@ -56,7 +59,7 @@ twi_ok(void)
 void
 twi_isr_C(void)
 {
-  U32 status = *AT91C_TWI_SR;
+  volatile U32 status = *AT91C_TWI_SR;
 
   if ((status & AT91C_TWI_RXRDY) && twi_state == TWI_RX_BUSY) {
 
@@ -99,6 +102,7 @@ twi_isr_C(void)
     }
   }
 
+#if 0
   if (status & AT91C_TWI_OVRE) {
     /* */
     twi_stats.ovre++;
@@ -107,13 +111,18 @@ twi_isr_C(void)
     twi_state = TWI_FAILED;
 
   }
+#else /* patch */
+#endif
 
+#if 0
   if (status & AT91C_TWI_UNRE) {
     /* */
     twi_stats.unre++;
     *AT91C_TWI_IDR = ~0;
     twi_state = TWI_FAILED;
   }
+#else /* patch */
+#endif
 
   if (status & AT91C_TWI_NACK) {
     /* */
@@ -128,7 +137,7 @@ twi_isr_C(void)
 void
 twi_reset(void)
 {
-  U32 clocks = 9;
+  volatile U32 clocks = 9;
 
   *AT91C_TWI_IDR = ~0;
 
@@ -155,14 +164,17 @@ twi_reset(void)
 
   *AT91C_TWI_CR = 0x88;                /* Disable & reset */
 
-  *AT91C_TWI_CWGR = 0x020f0f;  /* Set for 380kHz */
+// changed by takashic 2008-11-14
+//  *AT91C_TWI_CWGR = 0x020f0f;        /* Set for 380kHz */
+  *AT91C_TWI_CWGR = ((CLDIV << 8)|CLDIV);       /* Set for 400kHz */
+
   *AT91C_TWI_CR = 0x04;                /* Enable as master */
 }
 
 int
 twi_init(void)
 {
-  int i_state;
+  volatile int i_state;
 
   i_state = interrupts_get_and_disable();
 
@@ -170,7 +182,7 @@ twi_init(void)
   *AT91C_TWI_IDR = ~0;         /* Disable all interrupt sources */
   aic_mask_off(AT91C_PERIPHERAL_ID_TWI);
   aic_set_vector(AT91C_PERIPHERAL_ID_TWI, AIC_INT_LEVEL_ABOVE_NORMAL,
-                twi_isr_entry);
+                (U32) twi_isr_entry);
   aic_mask_on(AT91C_PERIPHERAL_ID_TWI);
 
 
@@ -192,9 +204,9 @@ void
 twi_start_read(U32 dev_addr, U32 int_addr_bytes, U32 int_addr, U8 *data,
               U32 nBytes)
 {
-  U32 mode =
+  volatile U32 mode =
     ((dev_addr & 0x7f) << 16) | ((int_addr_bytes & 3) << 8) | (1 << 12);
-  U32 dummy;
+  volatile U32 dummy;
 
   if (!twi_busy()) {
 
@@ -217,7 +229,7 @@ void
 twi_start_write(U32 dev_addr, U32 int_addr_bytes, U32 int_addr,
                const U8 *data, U32 nBytes)
 {
-  U32 mode = ((dev_addr & 0x7f) << 16) | ((int_addr_bytes & 3) << 8);
+  volatile U32 mode = ((dev_addr & 0x7f) << 16) | ((int_addr_bytes & 3) << 8);
 
   if (!twi_busy()) {
     twi_state = TWI_TX_BUSY;
index ee817de..7961ad1 100644 (file)
 #include "mytypes.h"
 #include "udp.h"
 #include "interrupts.h"
-#include "AT91SAM7.h"
+#include "at91sam7s256.h"
 
 #include "aic.h"
-
+#include "systick.h"
+#include "display.h"
 
 #define EP_OUT 1
 #define EP_IN  2
 
+#define AT91C_PERIPHERAL_ID_UDP                11
+
+#define AT91C_UDP_CSR0  ((AT91_REG *)   0xFFFB0030) 
+#define AT91C_UDP_CSR1  ((AT91_REG *)   0xFFFB0034) 
+#define AT91C_UDP_CSR2  ((AT91_REG *)   0xFFFB0038) 
+#define AT91C_UDP_CSR3  ((AT91_REG *)   0xFFFB003C)
 
-static unsigned currentConfig;
+#define AT91C_UDP_FDR0  ((AT91_REG *)   0xFFFB0050) 
+#define AT91C_UDP_FDR1  ((AT91_REG *)   0xFFFB0054) 
+#define AT91C_UDP_FDR2  ((AT91_REG *)   0xFFFB0058) 
+#define AT91C_UDP_FDR3  ((AT91_REG *)   0xFFFB005C) 
+
+static U8 currentConfig;
 static unsigned currentConnection;
 static unsigned currentRxBank;
+static unsigned usbTimeOut;
+
+// Device descriptor
+static const U8 dd[] = {
+  0x12, 
+  0x01,
+  0x00,
+  0x02,
+  0x00,
+  0x00,
+  0x00, 
+  0x08,
+  0x94,
+  0x06,
+  0x02,
+  0x00,
+  0x00,
+  0x00,
+  0x00, 
+  0x00, 
+  0x01,
+  0x01  
+};
+
+// Configuration descriptor
+static const U8 cfd[] = {
+  0x09,
+  0x02,
+  0x20,
+  0x00, 
+  0x01,
+  0x01, 
+  0x00,
+  0xC0,
+  0x00,
+  0x09,
+  0x04,
+  0x00,
+  0x00,
+  0x02,
+  0xFF, 
+  0xFF,
+  0xFF,
+  0x00,
+  0x07, 
+  0x05,
+  0x01,
+  0x02,
+  64,
+  0x00,
+  0x00, 
+  0x07,
+  0x05,
+  0x82,
+  0x02,
+  64,
+  0x00,
+  0x00};
+
+// Serial Number Descriptor
+static U8 snd[] =
+{
+      0x1A,
+      0x03, 
+      0x31, 0x00,     // MSD of Lap (Lap[2,3]) in UNICode
+      0x32, 0x00,     // Lap[4,5]
+      0x33, 0x00,     // Lap[6,7]
+      0x34, 0x00,     // Lap[8,9]
+      0x35, 0x00,     // Lap[10,11]
+      0x36, 0x00,     // Lap[12,13]
+      0x37, 0x00,     // Lap[14,15]
+      0x38, 0x00,     // LSD of Lap (Lap[16,17]) in UNICode
+      0x30, 0x00,     // MSD of Nap (Nap[18,19]) in UNICode
+      0x30, 0x00,     // LSD of Nap (Nap[20,21]) in UNICode
+      0x39, 0x00,     // MSD of Uap in UNICode
+      0x30, 0x00      // LSD of Uap in UNICode
+};
 
+static const U8 ld[] = {0x04,0x03,0x09,0x04}; // Language descriptor
+      
 extern void udp_isr_entry(void);
 
+static int configured = 0;
+
+//static char x4[5];
+//static char* hexchars = "0123456789abcdef";
+
+/*  supress a warning by GCC
+static char *
+hex4(int i)
+{
+  x4[0] = hexchars[(i >> 12) & 0xF];
+  x4[1] = hexchars[(i >> 8) & 0xF];
+  x4[2] = hexchars[(i >> 4) & 0xF];
+  x4[3] = hexchars[i & 0xF];
+  x4[4] = 0;
+  return x4;
+}
+*/
+
 void
 udp_isr_C(void)
 {
-
 }
 
+void
+udp_check_interrupt()
+{
+  if (*AT91C_UDP_ISR & END_OF_BUS_RESET) 
+  { 
+       //display_goto_xy(0,0);
+       //display_string("Bus Reset");
+       //display_update();
+       *AT91C_UDP_ICR = END_OF_BUS_RESET;          
+       *AT91C_UDP_ICR = SUSPEND_RESUME;      
+       *AT91C_UDP_ICR = WAKEUP;              
+       configured = 0;
+       currentConfig = 0;
+       *AT91C_UDP_RSTEP = 0xFFFFFFFF;
+       *AT91C_UDP_RSTEP = 0x0; 
+       currentRxBank = AT91C_UDP_RX_DATA_BK0;
+       *AT91C_UDP_FADDR = AT91C_UDP_FEN;    
+       *AT91C_UDP_CSR0 = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); 
+  }
+  else if (*AT91C_UDP_ISR & SUSPEND_INT)
+  {
+       //display_goto_xy(0,0);
+       //display_string("Suspend");
+       //display_update();
+    if (configured == 1) configured = 2;
+    else configured = 0;
+       *AT91C_UDP_ICR = SUSPEND_INT;
+       currentRxBank = AT91C_UDP_RX_DATA_BK0;
+  }
+  else if (*AT91C_UDP_ISR & SUSPEND_RESUME)
+  {
+       //display_goto_xy(0,0);
+       //display_string("Resume");
+       //display_update();
+    if (configured == 2) configured = 1;
+    else configured = 0;
+    *AT91C_UDP_ICR = WAKEUP;
+    *AT91C_UDP_ICR = SUSPEND_RESUME;
+  }
+  else if (*AT91C_UDP_ISR & AT91C_UDP_EPINT0)
+  {
+    *AT91C_UDP_ICR = AT91C_UDP_EPINT0; 
+       udp_enumerate();                                        
+  } 
+}
 
 int
 udp_init(void)
 {
-  int i_state;
+  //int i_state;
 
   /* Make sure the USB PLL and clock are set up */
   *AT91C_CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
@@ -43,20 +196,19 @@ udp_init(void)
 
   currentConfig = 0;
   currentConnection = 0;
-  currentRxBank = 0;
+  currentRxBank = AT91C_UDP_RX_DATA_BK0;
 
-  i_state = interrupts_get_and_disable();
+  /*i_state = interrupts_get_and_disable();
 
   aic_mask_off(AT91C_PERIPHERAL_ID_UDP);
   aic_set_vector(AT91C_PERIPHERAL_ID_UDP, AIC_INT_LEVEL_NORMAL,
                 (U32) udp_isr_entry);
   aic_mask_on(AT91C_PERIPHERAL_ID_UDP);
 
-
   if (i_state)
-    interrupts_enable();
+    interrupts_enable(); */
 
-  return 1;
+  return 1; 
 }
 
 void
@@ -64,3 +216,395 @@ udp_close(U32 u)
 {
   /* Nothing */
 }
+
+void
+udp_disable()
+{
+  *AT91C_PIOA_PER = (1 << 16);
+  *AT91C_PIOA_OER = (1 << 16);
+  *AT91C_PIOA_SODR = (1 << 16);
+}
+
+void 
+udp_reset()
+{
+  udp_disable();  
+  systick_wait_ms(1);
+  udp_init();
+}
+
+int
+udp_short_timed_out()
+{
+  return (USB_TIMEOUT < 
+     ((((*AT91C_PITC_PIIR) & AT91C_PITC_CPIV) 
+         - usbTimeOut) & AT91C_PITC_CPIV));
+}
+
+static int timeout_counter = 0;
+
+int
+udp_timed_out()
+{
+   if(udp_short_timed_out())
+   {
+      timeout_counter++;
+      udp_short_reset_timeout();
+   }
+   return (timeout_counter > 500);
+}
+
+void
+udp_reset_timeout()
+{
+  timeout_counter = 0;
+  udp_short_reset_timeout();  
+}
+
+void
+udp_short_reset_timeout()
+{
+  usbTimeOut = ((*AT91C_PITC_PIIR) & AT91C_PITC_CPIV);  
+}
+
+int
+udp_read(U8* buf, int len)
+{
+  int packetSize = 0, i;
+  
+  if (udp_configured() != 1) return 0;
+  
+  if ((*AT91C_UDP_CSR1) & currentRxBank) // data to read
+  {
+       packetSize = (*AT91C_UDP_CSR1) >> 16;
+       if (packetSize > len) packetSize = len;
+       
+       for(i=0;i<packetSize;i++) buf[i] = *AT91C_UDP_FDR1;
+       
+       *AT91C_UDP_CSR1 &= ~(currentRxBank);    
+
+    if (currentRxBank == AT91C_UDP_RX_DATA_BK0) {      
+      currentRxBank = AT91C_UDP_RX_DATA_BK1;
+    } else {
+      currentRxBank = AT91C_UDP_RX_DATA_BK0;
+    }
+  }
+  return packetSize;
+}
+
+void
+udp_write(U8* buf, int len)
+{
+  int i;
+  
+  if (configured != 1) return;
+  
+  for(i=0;i<len;i++) *AT91C_UDP_FDR2 = buf[i];
+  
+  *AT91C_UDP_CSR2 |= AT91C_UDP_TXPKTRDY;
+  
+  udp_reset_timeout();
+  
+  while ( !((*AT91C_UDP_CSR2) & AT91C_UDP_TXCOMP) )    
+     if (udp_configured() != 1 || udp_timed_out()) return;
+            
+ (*AT91C_UDP_CSR2) &= ~(AT91C_UDP_TXCOMP);
+
+  while ((*AT91C_UDP_CSR2) & AT91C_UDP_TXCOMP);
+}
+
+void 
+udp_send_null()
+{
+   (*AT91C_UDP_CSR0) |= AT91C_UDP_TXPKTRDY;
+
+   udp_reset_timeout();
+
+   while ( !((*AT91C_UDP_CSR0) & AT91C_UDP_TXCOMP) && !udp_timed_out());
+
+   (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_TXCOMP);
+   while ((*AT91C_UDP_CSR0) & AT91C_UDP_TXCOMP);
+}
+
+void udp_send_stall()
+{
+  (*AT91C_UDP_CSR0) |= AT91C_UDP_FORCESTALL;                           
+  while ( !((*AT91C_UDP_CSR0) & AT91C_UDP_ISOERROR) );                    
+
+  (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);
+  while ((*AT91C_UDP_CSR0) & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR));
+}
+
+void udp_send_control(U8* p, int len, int send_null)
+{
+  int i = 0, j, tmp;
+  
+  do
+  {
+       // send 8 bytes or less 
+
+       for(j=0;j<8 && i<len;j++)
+       {
+         *AT91C_UDP_FDR0 = p[i++];
+       }
+
+       // Packet ready to send 
+       
+       (*AT91C_UDP_CSR0) |= AT91C_UDP_TXPKTRDY;
+       udp_reset_timeout();    
+    
+       do 
+       {
+         tmp = (*AT91C_UDP_CSR0);
+
+         if (tmp & AT91C_UDP_RX_DATA_BK0)
+         {
+
+           (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_TXPKTRDY);
+
+               (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_RX_DATA_BK0);
+        return;
+         }
+       }
+       while (!(tmp & AT91C_UDP_TXCOMP) && !udp_timed_out());
+       
+       (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_TXCOMP);
+    
+       while ((*AT91C_UDP_CSR0) & AT91C_UDP_TXCOMP);
+
+  }
+  while (i < len);
+  // If needed send the null terminating data 
+  if (send_null) udp_send_null();
+  udp_reset_timeout();
+
+  while(!((*AT91C_UDP_CSR0) & AT91C_UDP_RX_DATA_BK0) && !udp_timed_out());
+
+  (*AT91C_UDP_CSR0) &= ~(AT91C_UDP_RX_DATA_BK0);
+
+}
+
+int
+udp_configured()
+{
+  udp_check_interrupt();
+  /*display_goto_xy(0,7);
+  display_int(configured,1);
+  display_update();*/
+  return configured;
+}
+
+void 
+udp_enumerate()
+{
+  U8 bt, br;
+  int req, len, ind, val; 
+  short status;
+  
+  if (!((*AT91C_UDP_CSR0) & AT91C_UDP_RXSETUP)) return;
+  
+  bt = *AT91C_UDP_FDR0;
+  br = *AT91C_UDP_FDR0;
+  
+  val = ((*AT91C_UDP_FDR0 & 0xFF) | (*AT91C_UDP_FDR0 << 8));
+  ind = ((*AT91C_UDP_FDR0 & 0xFF) | (*AT91C_UDP_FDR0 << 8));
+  len = ((*AT91C_UDP_FDR0 & 0xFF) | (*AT91C_UDP_FDR0 << 8));
+  
+  if (bt & 0x80)
+  {
+    *AT91C_UDP_CSR0 |= AT91C_UDP_DIR; 
+    while ( !((*AT91C_UDP_CSR0) & AT91C_UDP_DIR) );
+  }
+  
+  *AT91C_UDP_CSR0 &= ~AT91C_UDP_RXSETUP;
+  while ( ((*AT91C_UDP_CSR0)  & AT91C_UDP_RXSETUP)  );
+
+  req = br << 8 | bt;
+  
+  /*
+  if (1) {
+       display_goto_xy(0,0);
+    display_string(hex4(req));
+    display_goto_xy(4,0);
+    display_string(hex4(val));
+    display_goto_xy(8,0);
+    display_string(hex4(ind));
+    display_goto_xy(12,0);
+    display_string(hex4(len));
+    display_goto_xy(0,1);
+    display_string("   ");
+    display_update();
+  }
+  */
+    
+  switch(req)
+  {
+    case STD_GET_DESCRIPTOR: 
+      if (val == 0x100) // Get device descriptor
+      {
+        udp_send_control((U8 *)dd, sizeof(dd), 0);
+      }
+      else if (val == 0x200) // Configuration descriptor
+      {     
+        udp_send_control((U8 *)cfd, (len < sizeof(cfd) ? len : sizeof(cfd)), (len > sizeof(cfd) ? 1 : 0));
+        //if (len > sizeof(cfd)) udp_send_null();
+      }        
+      else if ((val & 0xF00) == 0x300)
+      {
+        switch(val & 0xFF)
+        {
+          case 0x00:
+               udp_send_control((U8 *)ld, sizeof(ld), 0);
+            break;
+          case 0x01:
+                   udp_send_control(snd, sizeof(snd), 0);
+            break;
+          default:
+                       udp_send_stall();
+        }
+      }  
+      else
+      {
+        udp_send_stall();
+      }
+      break;
+        
+    case STD_SET_ADDRESS:
+      
+      (*AT91C_UDP_CSR0) |= AT91C_UDP_TXPKTRDY;
+
+      udp_reset_timeout();
+
+      while(((*AT91C_UDP_CSR0) & AT91C_UDP_TXPKTRDY) && !udp_timed_out());
+        
+      *AT91C_UDP_FADDR = (AT91C_UDP_FEN | val);            
+                                                                   
+      *AT91C_UDP_GLBSTATE  = (val) ? AT91C_UDP_FADDEN : 0;
+      
+      break;
+        
+    case STD_SET_CONFIGURATION:
+
+      configured = 1;
+      currentConfig = val;
+      udp_send_null(); 
+      *AT91C_UDP_GLBSTATE  = (val) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;
+
+      *AT91C_UDP_CSR1 = (val) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0; 
+      *AT91C_UDP_CSR2 = (val) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN)  : 0;
+      *AT91C_UDP_CSR3 = (val) ? (AT91C_UDP_EPTYPE_INT_IN)   : 0;      
+      
+      break;
+      
+    case STD_SET_FEATURE_ENDPOINT:
+
+      ind &= 0x0F;
+
+      if ((val == 0) && ind && (ind <= 3))
+      {
+        switch (ind)
+        {
+          case 1:   
+            (*AT91C_UDP_CSR1) = 0;
+            break;
+          case 2:   
+            (*AT91C_UDP_CSR2) = 0;
+            break;
+          case 3:   
+            (*AT91C_UDP_CSR3) = 0;
+            break;
+        }
+        udp_send_null();
+      }
+      else udp_send_stall();
+      break;
+
+    case STD_CLEAR_FEATURE_ENDPOINT:
+      ind &= 0x0F;
+
+      if ((val == 0) && ind && (ind <= 3))
+      {                                             
+        if (ind == 1) {
+          (*AT91C_UDP_CSR1) = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT); 
+          (*AT91C_UDP_RSTEP) |= AT91C_UDP_EP1;
+          (*AT91C_UDP_RSTEP) &= ~AT91C_UDP_EP1;
+        } else if (ind == 2) {
+          (*AT91C_UDP_CSR2) = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);
+          (*AT91C_UDP_RSTEP) |= AT91C_UDP_EP2;
+          (*AT91C_UDP_RSTEP) &= ~AT91C_UDP_EP2;
+        } else if (ind == 3) {
+          (*AT91C_UDP_CSR3) = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN);
+          (*AT91C_UDP_RSTEP) |= AT91C_UDP_EP3;
+          (*AT91C_UDP_RSTEP) &= ~AT91C_UDP_EP3; 
+        }
+        udp_send_null();
+      }
+      else udp_send_stall();
+
+      break;
+      
+    case STD_GET_CONFIGURATION:                                   
+
+      udp_send_control((U8 *) &(currentConfig), sizeof(currentConfig), 0);
+      break;
+
+    case STD_GET_STATUS_ZERO:
+    
+      status = 0x01; 
+      udp_send_control((U8 *) &status, sizeof(status), 0);
+      break;
+      
+    case STD_GET_STATUS_INTERFACE:
+
+      status = 0;
+      udp_send_control((U8 *) &status, sizeof(status), 0);
+      break;
+
+    case STD_GET_STATUS_ENDPOINT:
+
+      status = 0;
+      ind &= 0x0F;
+
+      if (((*AT91C_UDP_GLBSTATE) & AT91C_UDP_CONFG) && (ind <= 3)) 
+      {
+        switch (ind)
+        {
+          case 1: 
+            status = ((*AT91C_UDP_CSR1) & AT91C_UDP_EPEDS) ? 0 : 1; 
+            break;
+          case 2: 
+            status = ((*AT91C_UDP_CSR2) & AT91C_UDP_EPEDS) ? 0 : 1;
+            break;
+          case 3: 
+            status = ((*AT91C_UDP_CSR3) & AT91C_UDP_EPEDS) ? 0 : 1;
+            break;
+        }
+        udp_send_control((U8 *) &status, sizeof(status), 0);
+      }
+      else if (((*AT91C_UDP_GLBSTATE) & AT91C_UDP_FADDEN) && (ind == 0))
+      {
+        status = ((*AT91C_UDP_CSR0) & AT91C_UDP_EPEDS) ? 0 : 1;
+        udp_send_control((U8 *) &status, sizeof(status), 0);
+      }
+      else udp_send_stall();                                // Illegal request :-(
+
+      break;
+      
+    case STD_SET_FEATURE_INTERFACE:
+    case STD_CLEAR_FEATURE_INTERFACE:
+      udp_send_null();
+      break;
+    case STD_SET_INTERFACE:     
+    case STD_SET_FEATURE_ZERO:
+    case STD_CLEAR_FEATURE_ZERO:
+    default:
+      udp_send_stall();
+  } 
+}
+
+
+
+
+
+
index 2ff8e37..7996c06 100644 (file)
@@ -4,7 +4,49 @@
 #  include "mytypes.h"
 
 void udp_isr_C(void);
+void udp_check_interrupt(void);
 int udp_init(void);
-void uart_close(U32 u);
+void udp_close(U32 u);
+void udp_disable(void);
+void udp_reset(void);
+int udp_timed_out(void);
+void udp_reset_timeout(void);
+int udp_short_timed_out(void);
+void udp_short_reset_timeout(void);
+void udp_write(U8* buf, int len);
+void udp_enumerate(void);
+void udp_send_control(U8* p,int len, int send_null);
+void udp_send_null(void);
+void udp_send_stall(void);
+int udp_configured(void);
+int udp_read(U8* buf, int len);
 
+#define   USB_TIMEOUT   0x0BB8 
+#define END_OF_BUS_RESET ((unsigned int) 0x1 << 12)
+#define SUSPEND_INT      ((unsigned int) 0x1 << 8)
+#define SUSPEND_RESUME   ((unsigned int) 0x1 << 9)
+#define WAKEUP           ((unsigned int) 0x1 << 13)
+
+/* USB standard request codes */
+
+#define STD_GET_STATUS_ZERO           0x0080
+#define STD_GET_STATUS_INTERFACE      0x0081
+#define STD_GET_STATUS_ENDPOINT       0x0082
+
+#define STD_CLEAR_FEATURE_ZERO        0x0100
+#define STD_CLEAR_FEATURE_INTERFACE   0x0101
+#define STD_CLEAR_FEATURE_ENDPOINT    0x0102
+
+#define STD_SET_FEATURE_ZERO          0x0300
+#define STD_SET_FEATURE_INTERFACE     0x0301
+#define STD_SET_FEATURE_ENDPOINT      0x0302
+
+#define STD_SET_ADDRESS               0x0500
+#define STD_GET_DESCRIPTOR            0x0680
+#define STD_SET_DESCRIPTOR            0x0700
+#define STD_GET_CONFIGURATION         0x0880
+#define STD_SET_CONFIGURATION         0x0900
+#define STD_GET_INTERFACE             0x0A81
+#define STD_SET_INTERFACE             0x0B01
+#define STD_SYNCH_FRAME               0x0C82
 #endif