local fork

Dependencies:   Socket USBHostWANDongle_bleedingedge lwip-sys lwip

Dependents:   Encrypted

Fork of VodafoneUSBModem_bleedingedge by Donatien Garnier

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBSerialStream.cpp Source File

USBSerialStream.cpp

00001 /* USBSerialStream.cpp */
00002 /* Copyright (C) 2012 mbed.org, MIT License
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00005  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00006  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00007  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The above copyright notice and this permission notice shall be included in all copies or
00011  * substantial portions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00014  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00015  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00016  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00017  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00018  */
00019 
00020 
00021 
00022 #define __DEBUG__ 0
00023 #ifndef __MODULE__
00024 #define __MODULE__ "USBSerialStream.cpp"
00025 #endif
00026 
00027 #include "core/fwk.h"
00028 
00029 #include <cstring>
00030 
00031 #include "USBSerialStream.h"
00032 
00033 USBSerialStream::USBSerialStream(IUSBHostSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
00034 m_availableSphre(1), m_spaceSphre(1), m_inBuf()
00035 {
00036   m_availableSphre.wait();
00037   m_spaceSphre.wait();
00038   //Attach interrupts
00039   m_serial.attach(this);
00040 }
00041 
00042 /*virtual*/ USBSerialStream::~USBSerialStream()
00043 {
00044   m_serial.attach(NULL);
00045 }
00046 
00047 //0 for non-blocking (returns immediately), -1 for infinite blocking
00048 /*virtual*/ int USBSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
00049 {
00050   uint8_t *bufPointerCopy = buf;
00051   DBG("Trying to read at most %d chars", maxLength);
00052   int ret = waitAvailable(timeout);
00053   if(ret)
00054   {
00055     WARN("Error %d while waiting for incoming data", ret);
00056     return ret;
00057   }
00058   int a = available(); //Prevent macro issues
00059   int readLen = MIN( a, maxLength );
00060   *pLength = readLen;
00061   
00062   
00063   setupReadableISR(false);
00064   while(readLen--)
00065   {
00066     m_inBuf.dequeue(buf);
00067     buf++;
00068   }
00069   setupReadableISR(true);
00070   //printBuffer(bufPointerCopy,*pLength,true); // XXX
00071   
00072   return OK;
00073 }
00074 
00075 /*virtual*/ size_t USBSerialStream::available()
00076 {
00077   setupReadableISR(false); //m_inBuf.available() is not reentrant
00078   size_t len = m_inBuf.available();
00079   setupReadableISR(true);
00080   return len;
00081 }
00082 
00083 /*virtual*/ int USBSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
00084 {
00085   int ret;
00086   if(available()) //Is data already available?
00087   {
00088     while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
00089     return OK;
00090   }
00091 
00092   DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
00093   ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
00094   if(ret <= 0)
00095   {
00096     DBG("Timeout");
00097     return NET_TIMEOUT;
00098   }
00099   if(!m_inBuf.available()) //Even if abort has been called, return that data is available
00100   {
00101     DBG("Aborted");
00102     return NET_INTERRUPTED;
00103   }
00104   DBG("Finished waiting");
00105   while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
00106   return OK;
00107 }
00108 
00109 /*virtual*/ int USBSerialStream::abortRead() //Abort current reading (or waiting) operation
00110 {
00111   if( /*!available()*/true ) //If there is data pending, no need to abort
00112   {
00113     m_availableSphre.release(); //Force exiting the waiting state
00114   }
00115   else
00116   {
00117     DBG("Serial is readable"); ;
00118   }
00119   return OK;
00120 }
00121 
00122 void USBSerialStream::setupReadableISR(bool en)
00123 {
00124   m_serial.setupIrq(en, IUSBHostSerial::RxIrq);
00125 }
00126 
00127 void USBSerialStream::readable() //Callback from m_serial when new data is available
00128 {
00129   while(m_serial.readable())
00130   {
00131     m_inBuf.queue(m_serial.getc());
00132   }
00133   m_serial.readPacket(); //Start read of next packet
00134   m_availableSphre.release(); //Force exiting the waiting state
00135 }
00136 
00137 
00138 
00139 //0 for non-blocking (returns immediately), -1 for infinite blocking
00140 /*virtual*/ int USBSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=-1*/)
00141 {
00142   //printBuffer(buf,length,false); // XXX
00143   DBG("Trying to write %d chars", length);
00144   do
00145   {
00146     int ret = waitSpace(timeout);
00147     if(ret)
00148     {
00149       WARN("Error %d while waiting for space", ret);
00150       return ret;
00151     }
00152     int s = space(); //Prevent macro issues
00153     int writeLen = MIN( s, length );
00154     DBG("Writing %d chars", writeLen);
00155     setupWriteableISR(false);
00156     while(writeLen)
00157     {
00158       m_outBuf.queue(*buf);
00159       buf++;
00160       length--;
00161       writeLen--;
00162     }
00163     //If m_serial tx fifo is empty we need to start the packet write
00164     if( m_outBuf.available() && m_serialTxFifoEmpty )
00165     {
00166       writeable();
00167     }
00168     setupWriteableISR(true);
00169   } while(length);
00170   DBG("Write successful");
00171   return OK;
00172 }
00173 
00174 /*virtual*/ size_t USBSerialStream::space()
00175 {
00176   setupWriteableISR(false); //m_outBuf.available() is not reentrant
00177   size_t len = CIRCBUF_SIZE - m_outBuf.available();
00178   setupWriteableISR(true);
00179   return len;
00180 }
00181 
00182 /*virtual*/ int USBSerialStream::waitSpace(uint32_t timeout/*=-1*/) //Wait for space to be available
00183 {
00184   int ret;
00185   if(space()) //Is still space already left?
00186   {
00187     while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
00188     return OK;
00189   }
00190 
00191   DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
00192   ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
00193   if(ret <= 0)
00194   {
00195     DBG("Timeout");
00196     return NET_TIMEOUT;
00197   }
00198   if(!space()) //Even if abort has been called, return that space is available
00199   {
00200     DBG("Aborted");
00201     return NET_INTERRUPTED;
00202   }
00203   while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
00204   return OK;
00205 }
00206 
00207 /*virtual*/ int USBSerialStream::abortWrite() //Abort current writing (or waiting) operation
00208 {
00209   if( !space() ) //If there is space left, no need to abort
00210   {
00211     m_spaceSphre.release(); //Force exiting the waiting state
00212   }
00213   return OK;
00214 }
00215 
00216 void USBSerialStream::setupWriteableISR(bool en)
00217 {
00218   m_serial.setupIrq(en, IUSBHostSerial::TxIrq);
00219 }
00220 
00221 void USBSerialStream::writeable() //Callback from m_serial when new space is available
00222 {
00223   if(m_outBuf.isEmpty())
00224   {
00225     m_serialTxFifoEmpty = true;
00226   }
00227   else
00228   {
00229     m_serialTxFifoEmpty = false;
00230     while(m_serial.writeable() && !m_outBuf.isEmpty())
00231     {
00232       uint8_t c;
00233       m_outBuf.dequeue(&c);
00234       m_serial.putc((char)c);
00235     }
00236     m_serial.writePacket(); //Start packet write
00237   }
00238   if(!m_outBuf.isFull())
00239   {
00240     m_spaceSphre.release(); //Force exiting the waiting state
00241   }
00242 }