- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# usb.c

Go to the documentation of this file.

    00001 /*********************************************************************************
    00002
    00003  Copyright 2006-2008 MakingThings
    00004
    00005  Licensed under the Apache License,
    00006  Version 2.0 (the "License"); you may not use this file except in compliance
    00007  with the License. You may obtain a copy of the License at
    00008
    00009  http://www.apache.org/licenses/LICENSE-2.0
    00010
    00011  Unless required by applicable law or agreed to in writing, software distributed
    00012  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    00013  CONDITIONS OF ANY KIND, either express or implied. See the License for
    00014  the specific language governing permissions and limitations under the License.
    00015
    00016 *********************************************************************************/
    00017
    00018 /** \file usb.c
    00019   USB Subsystem.
    00020   Functions for controlling the USB port on the Make Controller Board.
    00021 */
    00022
    00023 #include "config.h"
    00024 #ifdef MAKE_CTRL_USB
    00025
    00026 #include "usb.h"
    00027 #include "rtos.h"
    00028 #include "stdio.h"
    00029 #include "USB-CDC.h"
    00030 #include "queue.h"
    00031 #include "string.h"
    00032
    00033 // SLIP codes
    00034 #define END             0300    // indicates end of packet
    00035 #define ESC             0333    // indicates byte stuffing
    00036 #define ESC_END         0334    // ESC ESC_END means END data byte
    00037 #define ESC_ESC         0335    // ESC ESC_ESC means ESC data byte
    00038
    00039 extern xQueueHandle xTxCDC;
    00040 extern xQueueHandle xRxCDC;
    00041
    00042 static int Usb_Users;
    00043 // set by the running task when it gets started
    00044 int Usb_Running;
    00045
    00046 #define mainUSB_PRIORITY      ( 4 )
    00047 #define mainUSB_TASK_STACK    ( 600 )
    00048 #define TICKRATE 1000
    00049
    00050 void vUSBCDCTask( void *pvParameters );
    00051 static void Usb_WriteInternal(xBULKBUFFER *pq);
    00052 Usb_* Usb = NULL;
    00053
    00054 /** \defgroup USB USB
    00055   The USB subsystem provides access to USB Virtual Serial Port (CDC) functionality.
    00056
    00057   On OS X, the system USB CDC driver is used - no external drivers are needed.
    00058   An entry in \b /dev is created - similar to <b>/dev/cu.usbmodem.xxxx</b>.  It may be opened for reading and
    00059   writing like a regular file using the standard POSIX open(), close(), read(), write() functions.
    00060
    00061   On Windows, the first time the device is seen, it needs
    00062   to be pointed to a .INF file containing additional information - the \b make_controller_kit.inf in
    00063   the same directory as this file.  Once Windows sets this up, the device can be opened as a normal
    00064   COM port.  See also the \b mchelper codebase for code snippets.
    00065
    00066   \todo expand usb support to include emulation of other kinds of USB device - mouse, keyboard, etc.
    00067 * \ingroup Core
    00068 * @{
    00069 */
    00070
    00071 /**
    00072   Sets whether the Usb subsystem is active.
    00073   @param state An integer specifying the active state of the Usb system - 1 (on) or 0 (off).
    00074   @return Zero on success.
    00075 */
    00076 int Usb_SetActive( int state )
    00077 {
    00078   if ( state )
    00079   {
    00080     if ( Usb_Users++ == 0 )
    00081     {
    00082       // Create the USB task.
    00083       Usb = MallocWait( sizeof( Usb_ ), 100 );
    00084       TaskCreate(  vUSBCDCTask, "USB", mainUSB_TASK_STACK, NULL, mainUSB_PRIORITY );
    00085
    00086       while ( !Usb_Running )
    00087         Sleep( 100 );
    00088     }
    00089   }
    00090   else
    00091   {
    00092     if ( Usb_Users )
    00093     {
    00094       if ( --Usb_Users == 0 )
    00095       {
    00096         /* kill the task, someday */
    00097       }
    00098     }
    00099   }
    00100   return CONTROLLER_OK;
    00101 }
    00102
    00103 /**
    00104   Read the active state of the Usb system.
    00105   @return State - 1 (on) or 0 (off).
    00106 */
    00107 int Usb_GetActive( )
    00108 {
    00109   return Usb_Users > 0;
    00110 }
    00111
    00112
    00113 /**
    00114   Read from the USB port.
    00115   Pass in a pointer to a char buffer to read into, and the number of characters requested to read.
    00116   This function will return immediately with the number of characters read.
    00117   @param buffer A pointer to a char buffer to read into
    00118   @param length An integer specifying the number of characters to read
    00119   @return The number of characters successfully read.
    00120 */
    00121 int Usb_Read(char *buffer, int length)
    00122 {
    00123   static xBULKBUFFER DeQueue;
    00124   static int queueRemaining = 0; // whether or not there's anything left over from last time.
    00125   static unsigned char *queuePtr = DeQueue.Data; // pointer into our block buffer
    00126   char *bufferPtr = buffer; // pointer into the buffer passed in
    00127
    00128   while( bufferPtr - buffer < length )
    00129   {
    00130     if( queueRemaining ) // first check if there's anything left from a previous read
    00131     {
    00132       if( queuePtr - DeQueue.Data < DeQueue.Count )
    00133         *bufferPtr++ = *queuePtr++;
    00134       else
    00135         queueRemaining = 0;
    00136     }
    00137     else // nothing left to read, so grab more from the queue
    00138     {
    00139       if ( xQueueReceive( xRxCDC, &DeQueue, 0 ) == pdTRUE  ) // got a new message from USB waiting on the queue
    00140       {
    00141         queueRemaining = 1;
    00142         queuePtr = DeQueue.Data;
    00143       }
    00144       else // nothing was available so we're done
    00145         break;
    00146     }
    00147   }
    00148   return bufferPtr - buffer;
    00149 }
    00150
    00151 /**
    00152   Write to the USB port.
    00153   Pass in a pointer to a char buffer to from, and the number of characters requested to write.
    00154   @param buffer A pointer to a char buffer to write from
    00155   @param length An integer specifying the number of characters to write
    00156   @return The number of characters successfully written
    00157 */
    00158 int Usb_Write( char* buffer, int length )
    00159 {
    00160   if ( !Usb_Users )
    00161     Usb_SetActive( 1 );
    00162
    00163   xBULKBUFFER q;
    00164   q.Count = 0;
    00165   int count = length;
    00166
    00167   // load bytes into the BULKBUFFER and when it's full, send it and continue loading
    00168   while( length-- )
    00169   {
    00170     q.Data[q.Count++] = *buffer++;
    00171     if(q.Count == EP_FIFO)
    00172       Usb_WriteInternal(&q);
    00173   }
    00174
    00175   // if bytes have been loaded into the BULKBUFFER but not sent because it's not full yet, send it now
    00176   if( q.Count )
    00177     Usb_WriteInternal(&q);
    00178
    00179   return count;
    00180 }
    00181
    00182 // the outgoing USB hardware can write a block of 64 (EP_FIFO) bytes.
    00183 // test the buffer's size and send it if we're full.
    00184 void Usb_WriteInternal(xBULKBUFFER *pq)
    00185 {
    00186   while(xQueueSend( xTxCDC, pq, 0) != pdPASS)
    00187     Sleep( usbSHORTEST_DELAY );
    00188   pq->Count = 0;
    00189 }
    00190
    00191 /**
    00192   Write to the USB port using SLIP codes to packetize messages.
    00193   SLIP (Serial Line Internet Protocol) is a way to separate one "packet" from another on an open serial connection.
    00194   This is the way OSC messages are sent over USB, for example.  SLIP uses a simple start/end byte and an escape
    00195   byte in case your data actually contains the start/end byte.  Pass your normal buffer to this function to
    00196   have the SLIP codes inserted and then write it out over USB.
    00197
    00198   Check the Wikipedia description of SLIP at http://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol
    00199   @param buffer A pointer to a char buffer to write from
    00200   @param length An integer specifying the number of characters to write
    00201   @return The number of characters successfully written
    00202 */
    00203 int Usb_SlipSend( char* buffer, int length )
    00204 {
    00205   if( length > MAX_OUTGOING_SLIP_PACKET )
    00206     return CONTROLLER_ERROR_INSUFFICIENT_RESOURCES;
    00207
    00208   char *obp = Usb->slipSendBuffer, *bp = buffer;
    00209   int count = length;
    00210
    00211   *obp++ = (char)END;
    00212
    00213   while( count-- )
    00214   {
    00215     switch(*bp)
    00216     {
    00217       // if it's the same code as an END character, we send a special
    00218       //two character code so as not to make the receiver think we sent an END
    00219       case END:
    00220         *obp++ = (char) ESC;
    00221         *obp++ = (char) ESC_END;
    00222         break;
    00223         // if it's the same code as an ESC character, we send a special
    00224         //two character code so as not to make the receiver think we sent an ESC
    00225       case ESC:
    00226         *obp++ = (char) ESC;
    00227         *obp++ = (char) ESC_ESC;
    00228         break;
    00229         //otherwise, just send the character
    00230       default:
    00231         *obp++ = *bp;
    00232     }
    00233     bp++;
    00234   }
    00235
    00236   *obp++ = END; // tell the receiver that we're done sending the packet
    00237   int sendLength = obp - Usb->slipSendBuffer;
    00238   Usb_Write( Usb->slipSendBuffer, sendLength );
    00239
    00240   return CONTROLLER_OK;
    00241 }
    00242
    00243 /**
    00244   Read from the USB port using SLIP codes to de-packetize messages.
    00245   SLIP (Serial Line Internet Protocol) is a way to separate one "packet" from another on an open serial connection.
    00246   This is the way OSC messages are sent over USB, for example.  SLIP uses a simple start/end byte and an escape
    00247   byte in case your data actually contains the start/end byte.  This function will block until it has received a
    00248   complete SLIP encoded message, and will pass back the original message with the SLIP codes removed.
    00249
    00250   Check the Wikipedia description of SLIP at http://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol
    00251   @param buffer A pointer to a char buffer to read into
    00252   @param length An integer specifying the number of characters to read
    00253   @return The number of characters successfully written
    00254 */
    00255 int Usb_SlipReceive( char* buffer, int length )
    00256 {
    00257   if( length > MAX_INCOMING_SLIP_PACKET )
    00258     return CONTROLLER_ERROR_INSUFFICIENT_RESOURCES;
    00259
    00260   int started = 0, finished = 0, count = 0, i;
    00261   char *pbp = Usb->slipReadBuffer;
    00262   static int bufRemaining = 0;
    00263   char *bp = buffer;
    00264
    00265   while ( count < length )
    00266   {
    00267     if( !bufRemaining ) // if there's nothing left over from last time, get more
    00268     {
    00269       bufRemaining = Usb_Read( Usb->slipReadBuffer, MAX_INCOMING_SLIP_PACKET );
    00270       pbp = Usb->slipReadBuffer;
    00271     }
    00272
    00273     for( i = 0; i < bufRemaining; i++ )
    00274     {
    00275       switch( *pbp )
    00276       {
    00277         case END:
    00278           if( started && count ) // it was the END byte
    00279             finished = true;
    00280           else // skipping all starting END bytes
    00281             started = true;
    00282           break;
    00283         case ESC:
    00284           // get the next byte.  if it's not an ESC_END or ESC_ESC, it's a
    00285           // malformed packet.  http://tools.ietf.org/html/rfc1055 says just
    00286           // drop it in the packet in this case
    00287           pbp++;
    00288           if( started )
    00289           {
    00290             if( *pbp == ESC_END )
    00291             {
    00292               *bp++ = END;
    00293               count++;
    00294               break;
    00295             }
    00296             else if( *pbp == ESC_ESC )
    00297             {
    00298               *bp++ = ESC;
    00299               count++;
    00300               break;
    00301             }
    00302           }
    00303           // no break here
    00304         default:
    00305           if( started )
    00306           {
    00307             *bp++ = *pbp;
    00308             count++;
    00309           }
    00310           break;
    00311       }
    00312       pbp++;
    00313       bufRemaining--;
    00314       if( finished )
    00315         return count;
    00316     }
    00317     Sleep(1);
    00318   }
    00319   return CONTROLLER_ERROR_BAD_FORMAT; // should never get here
    00320 }
    00321
    00322 /** @}
    00323 */
    00324
    00325 #ifdef OSC
    00326
    00327 #include "osc.h"
    00328 #include "string.h"
    00329 #include "stdio.h"
    00330
    00331 // Need a list of property names
    00332 // MUST end in zero
    00333 static char* UsbOsc_Name = "usb";
    00334 static char* UsbOsc_PropertyNames[] = { "active", 0 }; // must have a trailing 0
    00335
    00336 int UsbOsc_PropertySet( int property, int value );
    00337 int UsbOsc_PropertyGet( int property );
    00338
    00339 // Returns the name of the subsystem
    00340 const char* UsbOsc_GetName( )
    00341 {
    00342   return UsbOsc_Name;
    00343 }
    00344
    00345 // Now getting a message.  This is actually a part message, with the first
    00346 // part (the subsystem) already parsed off.
    00347 int UsbOsc_ReceiveMessage( int channel, char* message, int length )
    00348 {
    00349   return Osc_IntReceiverHelper( channel, message, length,
    00350                                 UsbOsc_Name,
    00351                                 UsbOsc_PropertySet, UsbOsc_PropertyGet,
    00352                                 UsbOsc_PropertyNames );
    00353 }
    00354
    00355 // Set the index Usb, property with the value
    00356 int UsbOsc_PropertySet( int property, int value )
    00357 {
    00358   switch ( property )
    00359   {
    00360     case 0:
    00361       Usb_SetActive( value );
    00362       break;
    00363   }
    00364   return CONTROLLER_OK;
    00365 }
    00366
    00367 // Get the index Usb, property
    00368 int UsbOsc_PropertyGet( int property )
    00369 {
    00370   int value = 0;
    00371   switch ( property )
    00372   {
    00373     case 0:
    00374       value = Usb_GetActive( );
    00375       break;
    00376   }
    00377
    00378   return value;
    00379 }
    00380
    00381 #endif  // OSC
    00382
    00383 #endif // MAKE_CTRL_USB
    00384
    00385

The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.