modified u-blox modem driver

Dependencies:   CellularModem USBHost

Fork of CellularUSBModem by mbed official

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