Dependents:   TimeZoneDemo EthernetJackTestCode MMEx_Challenge ntp_mem ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UsbSerial.cpp Source File

UsbSerial.cpp

00001 
00002 /*
00003 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
00004  
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to deal
00007 in the Software without restriction, including without limitation the rights
00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009 copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011  
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014  
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00021 THE SOFTWARE.
00022 */
00023 
00024 #include "rpc.h"
00025 
00026 #include "UsbSerial.h"
00027 
00028 //#define __DEBUG
00029 #include "dbg/dbg.h"
00030 
00031 #include "netCfg.h"
00032 #if NET_USB_SERIAL
00033 
00034 namespace mbed {
00035 
00036 #define BUF_LEN 64
00037 #define FLUSH_TMOUT 100000 //US
00038 
00039 UsbSerial::UsbSerial(UsbDevice* pDevice, int epIn, int epOut, const char* name /*= NULL*/) : Stream(name), m_epIn(pDevice, epIn, true, USB_BULK, BUF_LEN), m_epOut(pDevice, epOut, false, USB_BULK, BUF_LEN),
00040 m_pInCbItem(NULL), m_pInCbMeth(NULL), m_pOutCbItem(NULL), m_pOutCbMeth(NULL)
00041 { 
00042   m_inBufEven = new char[BUF_LEN];
00043   m_inBufOdd = new char[BUF_LEN];
00044   m_pInBufPos = m_inBufUsr = m_inBufEven;
00045   m_inBufTrmt = m_inBufOdd;
00046   
00047   m_outBufEven = new char[BUF_LEN];
00048   m_outBufOdd = new char[BUF_LEN];
00049   m_pOutBufPos = m_outBufUsr = m_outBufEven;
00050   m_outBufTrmt = m_outBufOdd;
00051   
00052   m_inBufLen = m_outBufLen = 0;
00053   
00054   DBG("Starting RX'ing on in ep\n");
00055   
00056   m_timeout = false;
00057   
00058   m_epIn.setOnCompletion(this, &UsbSerial::onEpInTransfer);
00059   m_epOut.setOnCompletion(this, &UsbSerial::onEpOutTransfer);
00060   
00061   startRx();
00062 }
00063 
00064 UsbSerial::~UsbSerial()
00065 {
00066   delete[] m_inBufEven;
00067   delete[] m_inBufOdd;
00068   delete[] m_outBufEven;
00069   delete[] m_outBufOdd;
00070 }
00071 
00072 void UsbSerial::baud(int baudrate) { 
00073     //
00074 }
00075 
00076 void UsbSerial::format(int bits, int parity, int stop) { 
00077   //
00078 } 
00079 
00080 #if 0 //For doc only
00081 template <class T>
00082 void attach(T* pCbItem, void (T::*pCbMeth)())
00083 {
00084   m_pCbItem = (CDummy*) pCbItem;
00085   m_pCbMeth = (void (CDummy::*)()) pCbMeth;
00086 }
00087 #endif
00088 
00089 int UsbSerial::_getc() { 
00090     NVIC_DisableIRQ(US_TICKER_TIMER_IRQn);
00091     NVIC_DisableIRQ(USB_IRQn);
00092     char c;
00093     c = *m_pInBufPos;
00094     m_pInBufPos++;
00095     NVIC_EnableIRQ(USB_IRQn);
00096     NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
00097     return c;
00098 }
00099 
00100 int UsbSerial::_putc(int c) { 
00101     NVIC_DisableIRQ(US_TICKER_TIMER_IRQn);
00102     NVIC_DisableIRQ(USB_IRQn);
00103     if( (m_pOutBufPos - m_outBufUsr) < BUF_LEN )
00104     {
00105       *m_pOutBufPos = (char) c;
00106       m_pOutBufPos++;
00107     }
00108     else
00109     {
00110       DBG("NO WAY!!!\n");
00111     }
00112     #if 1
00113     if( (m_pOutBufPos - m_outBufUsr) >= BUF_LEN ) //Must flush
00114     {
00115       if(m_timeout)
00116         m_txTimeout.detach();
00117       startTx();
00118     }
00119     else
00120     {
00121       /*if(m_timeout)
00122         m_txTimeout.detach();
00123       m_timeout = true;
00124       m_txTimeout.attach_us(this, &UsbSerial::startTx, FLUSH_TMOUT);*/
00125       if(!m_timeout)
00126       {
00127         m_timeout = true;
00128         m_txTimeout.attach_us(this, &UsbSerial::startTx, FLUSH_TMOUT);
00129       }
00130     }
00131     #endif
00132     //startTx();
00133     NVIC_EnableIRQ(USB_IRQn);
00134     NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
00135     return c;
00136 }
00137 
00138 int UsbSerial::readable() { 
00139     NVIC_DisableIRQ(US_TICKER_TIMER_IRQn);
00140     NVIC_DisableIRQ(USB_IRQn);
00141     int res;
00142     if( (m_pInBufPos - m_inBufUsr) < m_inBufLen )
00143     {
00144       //DBG("\r\nREADABLE\r\n");
00145       res = true;
00146     }
00147     else
00148     {
00149       //DBG("\r\nNOT READABLE\r\n");
00150       startRx(); //Try to swap packets & start another transmission
00151       res = ((m_pInBufPos - m_inBufUsr) < m_inBufLen )?true:false;
00152     }
00153     NVIC_EnableIRQ(USB_IRQn);
00154     NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
00155     return (bool)res;
00156 }
00157 
00158 int UsbSerial::writeable() { 
00159     NVIC_DisableIRQ(US_TICKER_TIMER_IRQn);
00160     NVIC_DisableIRQ(USB_IRQn);
00161   //  DBG("\r\nWRITEABLE???\r\n");
00162     int res = (bool)( (m_pOutBufPos - m_outBufUsr) < BUF_LEN);
00163     NVIC_EnableIRQ(USB_IRQn);
00164     NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
00165     return res;
00166 }
00167 
00168 void UsbSerial::onReadable()
00169 {
00170   if(m_pInCbItem && m_pInCbMeth)
00171     (m_pInCbItem->*m_pInCbMeth)();
00172 }
00173 
00174 void UsbSerial::onWriteable()
00175 {
00176   if(m_pOutCbItem && m_pOutCbMeth)
00177     (m_pOutCbItem->*m_pOutCbMeth)();
00178 }
00179 
00180 void UsbSerial::onEpInTransfer()
00181 {
00182   int len = m_epIn.status();
00183   DBG("RX transfer completed w len=%d\n",len);
00184   startRx();
00185   if(len > 0)
00186     onReadable();
00187 }
00188 
00189 void UsbSerial::onEpOutTransfer()
00190 {
00191   int len = m_epOut.status();
00192   DBG("TX transfer completed w len=%d\n",len);
00193   if(m_timeout)
00194     m_txTimeout.detach();
00195   startTx();
00196   if(len > 0)
00197     onWriteable();
00198 }
00199 
00200 void UsbSerial::startTx()
00201 {
00202   
00203   DBG("Transfer>\n");
00204   
00205   m_timeout = false;
00206   
00207 //  m_txTimeout.detach();
00208    
00209   if(!(m_pOutBufPos - m_outBufUsr))
00210   {
00211     DBG("?!?!?\n");
00212     return;
00213   }
00214   
00215   if( m_epOut.status() == USBERR_PROCESSING )
00216   {
00217     //Wait & retry
00218     //m_timeout = true;
00219     //m_txTimeout.attach_us(this, &UsbSerial::startTx, FLUSH_TMOUT);
00220     DBG("Ep is busy...\n");
00221     return;
00222   }
00223   
00224   if( m_epOut.status() < 0 )
00225   {
00226     DBG("Tx trying again...\n");
00227     m_epOut.transfer((volatile uint8_t*)m_outBufTrmt, m_outBufLen);
00228     return;
00229   }
00230 
00231   m_outBufLen = m_pOutBufPos - m_outBufUsr;
00232   
00233   //Swap buffers
00234   volatile char* swapBuf = m_outBufUsr;
00235   m_outBufUsr = m_outBufTrmt;
00236   m_outBufTrmt = swapBuf;
00237   
00238   m_epOut.transfer((volatile uint8_t*)m_outBufTrmt, m_outBufLen);
00239   
00240   m_pOutBufPos = m_outBufUsr;
00241 
00242 }
00243 
00244 void UsbSerial::startRx()
00245 {
00246   if( (m_pInBufPos - m_inBufUsr) < m_inBufLen )
00247   {
00248     //User buf is not empty, cannot swap now...
00249     return;
00250   }
00251   int len = m_epIn.status();
00252   if( len == USBERR_PROCESSING )
00253   {
00254     //Previous transmission not completed
00255     return;
00256   }
00257   if( len < 0 )
00258   {
00259     DBG("Rx trying again...\n");
00260     m_epIn.transfer((volatile uint8_t*)m_inBufTrmt, BUF_LEN); //Start another transmission
00261     return;
00262   }
00263   
00264   m_inBufLen = len;
00265   
00266   //Swap buffers
00267   volatile char* swapBuf = m_inBufUsr;
00268   m_inBufUsr =  m_inBufTrmt;
00269   m_inBufTrmt = swapBuf;
00270   m_pInBufPos = m_inBufUsr;
00271   
00272   DBG("Starting new transfer\n");
00273   m_epIn.transfer((volatile uint8_t*)m_inBufTrmt, BUF_LEN); //Start another transmission
00274   
00275 }
00276 
00277 #ifdef MBED_RPC
00278 const struct rpc_method *UsbSerial::get_rpc_methods() { 
00279     static const rpc_method methods[] = {
00280         { "readable", rpc_method_caller<int, UsbSerial, &UsbSerial::readable> },
00281         { "writeable", rpc_method_caller<int, UsbSerial, &UsbSerial::writeable> },
00282         RPC_METHOD_SUPER(Stream)
00283     };
00284     return methods;
00285 }
00286 
00287 struct rpc_class *UsbSerial::get_rpc_class() {
00288     static const rpc_function funcs[] = {
00289         /*{ "new", rpc_function_caller<const char*, UsbDevice*, int, int, const char*, Base::construct<UsbSerial,UsbDevice*,int,int,const char*> > },*/ //RPC is buggy
00290         RPC_METHOD_END
00291     };
00292     static rpc_class c = { "UsbSerial", funcs, NULL };
00293     return &c;
00294 }
00295 #endif
00296 
00297 } // namespace mbed
00298 
00299 #endif
00300