Nicholas Herriot / VodafoneK3770Lib
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers IOSerialStream.cpp Source File

IOSerialStream.cpp

00001 /* IOSerialStream.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__ "IOSerialStream.cpp"
00027 #endif
00028 
00029 #include "core/fwk.h"
00030 
00031 #include <stdio.h>
00032 
00033 #include "IOSerialStream.h"
00034 
00035 IOSerialStream::IOSerialStream(mbed::Serial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
00036 m_availableSphre(1), m_spaceSphre(1), m_inBuf(), m_outBuf()
00037 {
00038   m_availableSphre.wait();
00039   m_spaceSphre.wait();
00040   //Attach interrupts
00041   m_serial.attach(this, &IOSerialStream::readable, mbed::Serial::RxIrq);
00042   m_serial.attach(this, &IOSerialStream::writeable, mbed::Serial::TxIrq);
00043 }
00044 
00045 /*virtual*/ IOSerialStream::~IOSerialStream()
00046 {
00047   m_serial.attach(NULL, mbed::Serial::RxIrq);
00048   m_serial.attach(NULL, mbed::Serial::TxIrq);
00049 }
00050 
00051 //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
00052 /*virtual*/ int IOSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
00053 {
00054   DBG("Trying to read at most %d chars", maxLength);
00055   int ret = waitAvailable(timeout);
00056   if(ret)
00057   {
00058     WARN("Error %d while waiting for incoming data");
00059     return ret;
00060   }
00061   int readLen = MIN( available(), maxLength );
00062   *pLength = readLen;
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 IOSerialStream::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 IOSerialStream::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(!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 IOSerialStream::abortRead() //Abort current reading (or waiting) operation
00109 {
00110   if( !available() ) //If there is data pending, no need to abort
00111   {
00112     m_availableSphre.release(); //Force exiting the waiting state; kludge to pass a RC directly
00113   }
00114   else
00115   {
00116     DBG("Serial is readable"); ;
00117   }
00118   return OK;
00119 }
00120 
00121 void IOSerialStream::setupReadableISR(bool en)
00122 {
00123   if(en)
00124   {
00125     ((LPC_UART_TypeDef *)(UART_3))->IER |= 1 << 0;
00126   }
00127   else
00128   {
00129     ((LPC_UART_TypeDef *)(UART_3))->IER &= ~(1 << 0);
00130   }
00131 }
00132 
00133 void IOSerialStream::readable() //Callback from m_serial when new data is available
00134 {
00135   do
00136   {
00137     m_inBuf.queue(((LPC_UART_TypeDef *)UART_3)->RBR); //FIXME mbed libraries this is an awful kludge
00138   } while(m_serial.readable());
00139   m_availableSphre.release(); //Force exiting the waiting state
00140 }
00141 
00142 //0 for non-blocking (returns immediately), osWaitForever for infinite blocking
00143 /*virtual*/ int IOSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=osWaitForever*/)
00144 {
00145   DBG("Trying to write %d chars", length);
00146   int ret = waitSpace(timeout);
00147   if(ret)
00148   {
00149     WARN("Error %d while waiting for space");
00150     return ret;
00151   }
00152   DBG("Writing %d chars", length);
00153   setupWriteableISR(false);
00154   while(length)
00155   {
00156     m_outBuf.queue(*buf);
00157     buf++;
00158     length--;
00159     if(length && !space())
00160     {
00161       DBG("Waiting to write remaining %d chars", length);
00162       setupWriteableISR(true);
00163       ret = waitSpace(timeout);
00164       if(ret)
00165       {
00166         WARN("Error %d while waiting for space");
00167         return ret;
00168       }
00169       setupWriteableISR(false);
00170     }
00171   }
00172   //If m_serial tx fifo is empty we need to manually tx a byte in order to trigger the interrupt
00173   if( m_outBuf.available() && m_serialTxFifoEmpty )
00174   {
00175     m_serialTxFifoEmpty = false;
00176     uint8_t c;
00177     m_outBuf.dequeue(&c);
00178     //m_serial.putc((char)c);
00179     ((LPC_UART_TypeDef *)UART_3)->THR = c; //FIXME awful kludge
00180   }
00181   setupWriteableISR(true);
00182   DBG("Write successful");
00183   return OK;
00184 }
00185 
00186 /*virtual*/ size_t IOSerialStream::space()
00187 {
00188   setupWriteableISR(false); //m_outBuf.available() is not reentrant
00189   size_t len = CIRCBUF_SIZE - m_outBuf.available();
00190   setupWriteableISR(true);
00191   return len;
00192 }
00193 
00194 /*virtual*/ int IOSerialStream::waitSpace(uint32_t timeout/*=osWaitForever*/) //Wait for space to be available
00195 {
00196   int ret;
00197   if(space()) //Is still space already left?
00198   {
00199     m_spaceSphre.wait(0); //Clear the queue as space is available
00200     return OK;
00201   }
00202 
00203   DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
00204   ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
00205   if(ret <= 0)
00206   {
00207     DBG("Timeout");
00208     return NET_TIMEOUT;
00209   }
00210   if(!space()) //Even if abort has been called, return that space is available
00211   {
00212     DBG("Aborted");
00213     return NET_INTERRUPTED;
00214   }
00215   m_spaceSphre.wait(0); //Clear the queue as space is available
00216   return OK;
00217 }
00218 
00219 /*virtual*/ int IOSerialStream::abortWrite() //Abort current writing (or waiting) operation
00220 {
00221   if( !space() ) //If there is space left, no need to abort
00222   {
00223     m_spaceSphre.release(); //Force exiting the waiting state
00224   }
00225   return OK;
00226 }
00227 
00228 void IOSerialStream::setupWriteableISR(bool en)
00229 {
00230   if(en)
00231   {
00232     ((LPC_UART_TypeDef *)(UART_3))->IER |= 1 << 1;
00233   }
00234   else
00235   {
00236     ((LPC_UART_TypeDef *)(UART_3))->IER &= ~(1 << 1);
00237   }
00238 }
00239 
00240 void IOSerialStream::writeable() //Callback from m_serial when new space is available
00241 {
00242   if(m_outBuf.isEmpty())
00243   {
00244     m_serialTxFifoEmpty = true;
00245   }
00246   else
00247   {
00248     while(m_serial.writeable() && !m_outBuf.isEmpty())
00249     {
00250       uint8_t c;
00251       m_outBuf.dequeue(&c);
00252       //m_serial.putc((char)c);
00253       ((LPC_UART_TypeDef *)UART_3)->THR = c; //FIXME awful kludge
00254     }
00255   }
00256   m_spaceSphre.release(); //Force exiting the waiting state
00257 }