Vodafone K3770/K3772-Z modems driver & networking library

Dependencies:   Socket USBHostWANDongle lwip-sys lwip

Dependents:   VodafoneUSBModemHTTPClientTest VodafoneUSBModemNTPClientTest VodafoneUSBModemSMSTest VodafoneUSBModemUSSDTest ... more

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   DBG("Trying to read at most %d chars", maxLength);
00051   int ret = waitAvailable(timeout);
00052   if(ret)
00053   {
00054     WARN("Error %d while waiting for incoming data", ret);
00055     return ret;
00056   }
00057   int a = available(); //Prevent macro issues
00058   int readLen = MIN( a, maxLength );
00059   *pLength = readLen;
00060   
00061   
00062   setupReadableISR(false);
00063   while(readLen--)
00064   {
00065     m_inBuf.dequeue(buf);
00066     buf++;
00067   }
00068   setupReadableISR(true);
00069   
00070   return OK;
00071 }
00072 
00073 /*virtual*/ size_t USBSerialStream::available()
00074 {
00075   setupReadableISR(false); //m_inBuf.available() is not reentrant
00076   size_t len = m_inBuf.available();
00077   setupReadableISR(true);
00078   return len;
00079 }
00080 
00081 /*virtual*/ int USBSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
00082 {
00083   int ret;
00084   if(available()) //Is data already available?
00085   {
00086     while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
00087     return OK;
00088   }
00089 
00090   DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
00091   ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
00092   if(ret <= 0)
00093   {
00094     DBG("Timeout");
00095     return NET_TIMEOUT;
00096   }
00097   if(!m_inBuf.available()) //Even if abort has been called, return that data is available
00098   {
00099     DBG("Aborted");
00100     return NET_INTERRUPTED;
00101   }
00102   DBG("Finished waiting");
00103   while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
00104   return OK;
00105 }
00106 
00107 /*virtual*/ int USBSerialStream::abortRead() //Abort current reading (or waiting) operation
00108 {
00109   if( /*!available()*/true ) //If there is data pending, no need to abort
00110   {
00111     m_availableSphre.release(); //Force exiting the waiting state
00112   }
00113   else
00114   {
00115     DBG("Serial is readable"); ;
00116   }
00117   return OK;
00118 }
00119 
00120 void USBSerialStream::setupReadableISR(bool en)
00121 {
00122   m_serial.setupIrq(en, IUSBHostSerial::RxIrq);
00123 }
00124 
00125 void USBSerialStream::readable() //Callback from m_serial when new data is available
00126 {
00127   while(m_serial.readable())
00128   {
00129     m_inBuf.queue(m_serial.getc());
00130   }
00131   m_serial.readPacket(); //Start read of next packet
00132   m_availableSphre.release(); //Force exiting the waiting state
00133 }
00134 
00135 
00136 
00137 //0 for non-blocking (returns immediately), -1 for infinite blocking
00138 /*virtual*/ int USBSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=-1*/)
00139 {
00140   DBG("Trying to write %d chars", length);
00141   do
00142   {
00143     int ret = waitSpace(timeout);
00144     if(ret)
00145     {
00146       WARN("Error %d while waiting for space", ret);
00147       return ret;
00148     }
00149     int s = space(); //Prevent macro issues
00150     int writeLen = MIN( s, length );
00151     DBG("Writing %d chars", writeLen);
00152     setupWriteableISR(false);
00153     while(writeLen)
00154     {
00155       m_outBuf.queue(*buf);
00156       buf++;
00157       length--;
00158       writeLen--;
00159     }
00160     //If m_serial tx fifo is empty we need to start the packet write
00161     if( m_outBuf.available() && m_serialTxFifoEmpty )
00162     {
00163       writeable();
00164     }
00165     setupWriteableISR(true);
00166   } while(length);
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     while( m_spaceSphre.wait(0) > 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   while( m_spaceSphre.wait(0) > 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     m_serial.writePacket(); //Start packet write
00234   }
00235   if(!m_outBuf.isFull())
00236   {
00237     m_spaceSphre.release(); //Force exiting the waiting state
00238   }
00239 }