MakingThings
  • 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.