Nicholas Herriot / VodafoneK3770Lib
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBSerialStream.cpp Source File

USBSerialStream.cpp

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