Implementation of 3G USB Modem Huawei E372

Dependents:   PYRN

Committer:
clemounet
Date:
Tue Apr 14 13:27:07 2015 +0000
Revision:
2:61ac95f0af72
Parent:
0:67daedd6f74f
.up (working)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
clemounet 0:67daedd6f74f 1 /* USBSerialStream.cpp */
clemounet 0:67daedd6f74f 2 /* Copyright (C) 2012 mbed.org, MIT License
clemounet 0:67daedd6f74f 3 *
clemounet 0:67daedd6f74f 4 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
clemounet 0:67daedd6f74f 5 * and associated documentation files (the "Software"), to deal in the Software without restriction,
clemounet 0:67daedd6f74f 6 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
clemounet 0:67daedd6f74f 7 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
clemounet 0:67daedd6f74f 8 * furnished to do so, subject to the following conditions:
clemounet 0:67daedd6f74f 9 *
clemounet 0:67daedd6f74f 10 * The above copyright notice and this permission notice shall be included in all copies or
clemounet 0:67daedd6f74f 11 * substantial portions of the Software.
clemounet 0:67daedd6f74f 12 *
clemounet 0:67daedd6f74f 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
clemounet 0:67daedd6f74f 14 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
clemounet 0:67daedd6f74f 15 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
clemounet 0:67daedd6f74f 16 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
clemounet 0:67daedd6f74f 17 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
clemounet 0:67daedd6f74f 18 */
clemounet 0:67daedd6f74f 19
clemounet 2:61ac95f0af72 20 #include <cstdio>
clemounet 0:67daedd6f74f 21
clemounet 0:67daedd6f74f 22 #include "USBSerialStream.h"
clemounet 0:67daedd6f74f 23
clemounet 2:61ac95f0af72 24 #define __DEBUG__ 0
clemounet 2:61ac95f0af72 25 #ifndef __MODULE__
clemounet 2:61ac95f0af72 26 #define __MODULE__ "USBSerialStream.cpp"
clemounet 2:61ac95f0af72 27 #endif
clemounet 2:61ac95f0af72 28 #include "MyDebug.h"
clemounet 0:67daedd6f74f 29
clemounet 0:67daedd6f74f 30 USBSerialStream::USBSerialStream(IUSBHostSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
clemounet 0:67daedd6f74f 31 m_availableSphre(1), m_spaceSphre(1), m_inBuf()
clemounet 0:67daedd6f74f 32 {
clemounet 0:67daedd6f74f 33 m_availableSphre.wait();
clemounet 0:67daedd6f74f 34 m_spaceSphre.wait();
clemounet 0:67daedd6f74f 35 //Attach interrupts
clemounet 0:67daedd6f74f 36 m_serial.attach(this);
clemounet 0:67daedd6f74f 37 }
clemounet 0:67daedd6f74f 38
clemounet 0:67daedd6f74f 39 /*virtual*/ USBSerialStream::~USBSerialStream()
clemounet 0:67daedd6f74f 40 {
clemounet 0:67daedd6f74f 41 m_serial.attach(NULL);
clemounet 0:67daedd6f74f 42 }
clemounet 0:67daedd6f74f 43
clemounet 0:67daedd6f74f 44 //0 for non-blocking (returns immediately), -1 for infinite blocking
clemounet 0:67daedd6f74f 45 /*virtual*/ int USBSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
clemounet 0:67daedd6f74f 46 {
clemounet 2:61ac95f0af72 47 DBG("Trying to read at most %d chars", maxLength);
clemounet 0:67daedd6f74f 48 int ret = waitAvailable(timeout);
clemounet 0:67daedd6f74f 49 if(ret)
clemounet 0:67daedd6f74f 50 {
clemounet 2:61ac95f0af72 51 WARN("Error %d while waiting for incoming data", ret);
clemounet 0:67daedd6f74f 52 return ret;
clemounet 0:67daedd6f74f 53 }
clemounet 0:67daedd6f74f 54 int a = available(); //Prevent macro issues
clemounet 0:67daedd6f74f 55 int readLen = MIN( a, maxLength );
clemounet 0:67daedd6f74f 56 *pLength = readLen;
clemounet 0:67daedd6f74f 57
clemounet 0:67daedd6f74f 58 setupReadableISR(false);
clemounet 0:67daedd6f74f 59 while(readLen--)
clemounet 0:67daedd6f74f 60 {
clemounet 0:67daedd6f74f 61 m_inBuf.dequeue(buf);
clemounet 0:67daedd6f74f 62 buf++;
clemounet 0:67daedd6f74f 63 }
clemounet 0:67daedd6f74f 64 setupReadableISR(true);
clemounet 2:61ac95f0af72 65 DBG("Read %d chars successfully", *pLength);
clemounet 0:67daedd6f74f 66 return OK;
clemounet 0:67daedd6f74f 67 }
clemounet 0:67daedd6f74f 68
clemounet 0:67daedd6f74f 69 /*virtual*/ size_t USBSerialStream::available()
clemounet 0:67daedd6f74f 70 {
clemounet 0:67daedd6f74f 71 setupReadableISR(false); //m_inBuf.available() is not reentrant
clemounet 0:67daedd6f74f 72 size_t len = m_inBuf.available();
clemounet 0:67daedd6f74f 73 setupReadableISR(true);
clemounet 0:67daedd6f74f 74 return len;
clemounet 0:67daedd6f74f 75 }
clemounet 0:67daedd6f74f 76
clemounet 0:67daedd6f74f 77 /*virtual*/ int USBSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
clemounet 0:67daedd6f74f 78 {
clemounet 0:67daedd6f74f 79 int ret;
clemounet 0:67daedd6f74f 80 if(available()) //Is data already available?
clemounet 0:67daedd6f74f 81 {
clemounet 0:67daedd6f74f 82 while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
clemounet 0:67daedd6f74f 83 return OK;
clemounet 0:67daedd6f74f 84 }
clemounet 0:67daedd6f74f 85
clemounet 2:61ac95f0af72 86 DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
clemounet 0:67daedd6f74f 87 ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
clemounet 0:67daedd6f74f 88 if(ret <= 0)
clemounet 0:67daedd6f74f 89 {
clemounet 2:61ac95f0af72 90 DBG("Timeout");
clemounet 0:67daedd6f74f 91 return NET_TIMEOUT;
clemounet 0:67daedd6f74f 92 }
clemounet 0:67daedd6f74f 93 if(!m_inBuf.available()) //Even if abort has been called, return that data is available
clemounet 0:67daedd6f74f 94 {
clemounet 2:61ac95f0af72 95 DBG("Aborted");
clemounet 0:67daedd6f74f 96 return NET_INTERRUPTED;
clemounet 0:67daedd6f74f 97 }
clemounet 2:61ac95f0af72 98 DBG("Finished waiting");
clemounet 0:67daedd6f74f 99 while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
clemounet 0:67daedd6f74f 100 return OK;
clemounet 0:67daedd6f74f 101 }
clemounet 0:67daedd6f74f 102
clemounet 0:67daedd6f74f 103 /*virtual*/ int USBSerialStream::abortRead() //Abort current reading (or waiting) operation
clemounet 0:67daedd6f74f 104 {
clemounet 0:67daedd6f74f 105 if( /*!available()*/true ) //If there is data pending, no need to abort
clemounet 0:67daedd6f74f 106 {
clemounet 0:67daedd6f74f 107 m_availableSphre.release(); //Force exiting the waiting state
clemounet 0:67daedd6f74f 108 }
clemounet 0:67daedd6f74f 109 else
clemounet 0:67daedd6f74f 110 {
clemounet 2:61ac95f0af72 111 DBG("Serial is readable"); ;
clemounet 0:67daedd6f74f 112 }
clemounet 0:67daedd6f74f 113 return OK;
clemounet 0:67daedd6f74f 114 }
clemounet 0:67daedd6f74f 115
clemounet 0:67daedd6f74f 116 void USBSerialStream::setupReadableISR(bool en)
clemounet 0:67daedd6f74f 117 {
clemounet 0:67daedd6f74f 118 m_serial.setupIrq(en, IUSBHostSerial::RxIrq);
clemounet 0:67daedd6f74f 119 }
clemounet 0:67daedd6f74f 120
clemounet 0:67daedd6f74f 121 void USBSerialStream::readable() //Callback from m_serial when new data is available
clemounet 0:67daedd6f74f 122 {
clemounet 0:67daedd6f74f 123 while(m_serial.readable())
clemounet 0:67daedd6f74f 124 {
clemounet 0:67daedd6f74f 125 m_inBuf.queue(m_serial.getc());
clemounet 0:67daedd6f74f 126 }
clemounet 0:67daedd6f74f 127 m_serial.readPacket(); //Start read of next packet
clemounet 0:67daedd6f74f 128 m_availableSphre.release(); //Force exiting the waiting state
clemounet 0:67daedd6f74f 129 }
clemounet 0:67daedd6f74f 130
clemounet 0:67daedd6f74f 131 //0 for non-blocking (returns immediately), -1 for infinite blocking
clemounet 0:67daedd6f74f 132 /*virtual*/ int USBSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=-1*/)
clemounet 0:67daedd6f74f 133 {
clemounet 2:61ac95f0af72 134 DBG("Trying to write %d chars", length);
clemounet 0:67daedd6f74f 135 do
clemounet 0:67daedd6f74f 136 {
clemounet 0:67daedd6f74f 137 int ret = waitSpace(timeout);
clemounet 0:67daedd6f74f 138 if(ret)
clemounet 0:67daedd6f74f 139 {
clemounet 2:61ac95f0af72 140 WARN("Error %d while waiting for space", ret);
clemounet 0:67daedd6f74f 141 return ret;
clemounet 0:67daedd6f74f 142 }
clemounet 0:67daedd6f74f 143 int s = space(); //Prevent macro issues
clemounet 0:67daedd6f74f 144 int writeLen = MIN( s, length );
clemounet 2:61ac95f0af72 145 DBG("Writing %d chars", writeLen);
clemounet 0:67daedd6f74f 146 setupWriteableISR(false);
clemounet 0:67daedd6f74f 147 while(writeLen)
clemounet 0:67daedd6f74f 148 {
clemounet 0:67daedd6f74f 149 m_outBuf.queue(*buf);
clemounet 0:67daedd6f74f 150 buf++;
clemounet 0:67daedd6f74f 151 length--;
clemounet 0:67daedd6f74f 152 writeLen--;
clemounet 0:67daedd6f74f 153 }
clemounet 0:67daedd6f74f 154 //If m_serial tx fifo is empty we need to start the packet write
clemounet 0:67daedd6f74f 155 if( m_outBuf.available() && m_serialTxFifoEmpty )
clemounet 0:67daedd6f74f 156 {
clemounet 0:67daedd6f74f 157 writeable();
clemounet 0:67daedd6f74f 158 }
clemounet 0:67daedd6f74f 159 setupWriteableISR(true);
clemounet 0:67daedd6f74f 160 } while(length);
clemounet 0:67daedd6f74f 161
clemounet 2:61ac95f0af72 162 DBG("Write successful");
clemounet 0:67daedd6f74f 163 return OK;
clemounet 0:67daedd6f74f 164 }
clemounet 0:67daedd6f74f 165
clemounet 0:67daedd6f74f 166 /*virtual*/ size_t USBSerialStream::space()
clemounet 0:67daedd6f74f 167 {
clemounet 0:67daedd6f74f 168 setupWriteableISR(false); //m_outBuf.available() is not reentrant
clemounet 0:67daedd6f74f 169 size_t len = CIRCBUF_SIZE - m_outBuf.available();
clemounet 0:67daedd6f74f 170 setupWriteableISR(true);
clemounet 0:67daedd6f74f 171 return len;
clemounet 0:67daedd6f74f 172 }
clemounet 0:67daedd6f74f 173
clemounet 0:67daedd6f74f 174 /*virtual*/ int USBSerialStream::waitSpace(uint32_t timeout/*=-1*/) //Wait for space to be available
clemounet 0:67daedd6f74f 175 {
clemounet 0:67daedd6f74f 176 int ret;
clemounet 0:67daedd6f74f 177 if(space()) //Is still space already left?
clemounet 0:67daedd6f74f 178 {
clemounet 0:67daedd6f74f 179 while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
clemounet 0:67daedd6f74f 180 return OK;
clemounet 0:67daedd6f74f 181 }
clemounet 0:67daedd6f74f 182
clemounet 2:61ac95f0af72 183 DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
clemounet 0:67daedd6f74f 184 ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
clemounet 0:67daedd6f74f 185 if(ret <= 0)
clemounet 0:67daedd6f74f 186 {
clemounet 2:61ac95f0af72 187 DBG("Timeout");
clemounet 0:67daedd6f74f 188 return NET_TIMEOUT;
clemounet 0:67daedd6f74f 189 }
clemounet 0:67daedd6f74f 190 if(!space()) //Even if abort has been called, return that space is available
clemounet 0:67daedd6f74f 191 {
clemounet 2:61ac95f0af72 192 DBG("Aborted");
clemounet 0:67daedd6f74f 193 return NET_INTERRUPTED;
clemounet 0:67daedd6f74f 194 }
clemounet 0:67daedd6f74f 195 while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
clemounet 0:67daedd6f74f 196 return OK;
clemounet 0:67daedd6f74f 197 }
clemounet 0:67daedd6f74f 198
clemounet 0:67daedd6f74f 199 /*virtual*/ int USBSerialStream::abortWrite() //Abort current writing (or waiting) operation
clemounet 0:67daedd6f74f 200 {
clemounet 0:67daedd6f74f 201 if( !space() ) //If there is space left, no need to abort
clemounet 0:67daedd6f74f 202 {
clemounet 0:67daedd6f74f 203 m_spaceSphre.release(); //Force exiting the waiting state
clemounet 0:67daedd6f74f 204 }
clemounet 0:67daedd6f74f 205 return OK;
clemounet 0:67daedd6f74f 206 }
clemounet 0:67daedd6f74f 207
clemounet 0:67daedd6f74f 208 void USBSerialStream::setupWriteableISR(bool en)
clemounet 0:67daedd6f74f 209 {
clemounet 0:67daedd6f74f 210 m_serial.setupIrq(en, IUSBHostSerial::TxIrq);
clemounet 0:67daedd6f74f 211 }
clemounet 0:67daedd6f74f 212
clemounet 0:67daedd6f74f 213 void USBSerialStream::writeable() //Callback from m_serial when new space is available
clemounet 0:67daedd6f74f 214 {
clemounet 0:67daedd6f74f 215 if(m_outBuf.isEmpty())
clemounet 0:67daedd6f74f 216 {
clemounet 0:67daedd6f74f 217 m_serialTxFifoEmpty = true;
clemounet 0:67daedd6f74f 218 }
clemounet 0:67daedd6f74f 219 else
clemounet 0:67daedd6f74f 220 {
clemounet 0:67daedd6f74f 221 m_serialTxFifoEmpty = false;
clemounet 0:67daedd6f74f 222 while(m_serial.writeable() && !m_outBuf.isEmpty())
clemounet 0:67daedd6f74f 223 {
clemounet 0:67daedd6f74f 224 uint8_t c;
clemounet 0:67daedd6f74f 225 m_outBuf.dequeue(&c);
clemounet 0:67daedd6f74f 226 m_serial.putc((char)c);
clemounet 0:67daedd6f74f 227 }
clemounet 0:67daedd6f74f 228 m_serial.writePacket(); //Start packet write
clemounet 0:67daedd6f74f 229 }
clemounet 0:67daedd6f74f 230 if(!m_outBuf.isFull())
clemounet 0:67daedd6f74f 231 {
clemounet 0:67daedd6f74f 232 m_spaceSphre.release(); //Force exiting the waiting state
clemounet 0:67daedd6f74f 233 }
clemounet 0:67daedd6f74f 234 }