Implementation of 3G USB Modem Huawei E372

Dependents:   PYRN

Committer:
clemounet
Date:
Fri Feb 20 16:48:12 2015 +0000
Revision:
0:67daedd6f74f
Child:
2:61ac95f0af72
3G Modem driver HUAWEI E372

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 0:67daedd6f74f 20 #include <stdio.h>
clemounet 0:67daedd6f74f 21
clemounet 0:67daedd6f74f 22 #include "USBSerialStream.h"
clemounet 0:67daedd6f74f 23
clemounet 0:67daedd6f74f 24
clemounet 0:67daedd6f74f 25 USBSerialStream::USBSerialStream(IUSBHostSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
clemounet 0:67daedd6f74f 26 m_availableSphre(1), m_spaceSphre(1), m_inBuf()
clemounet 0:67daedd6f74f 27 {
clemounet 0:67daedd6f74f 28 m_availableSphre.wait();
clemounet 0:67daedd6f74f 29 m_spaceSphre.wait();
clemounet 0:67daedd6f74f 30 //Attach interrupts
clemounet 0:67daedd6f74f 31 m_serial.attach(this);
clemounet 0:67daedd6f74f 32 }
clemounet 0:67daedd6f74f 33
clemounet 0:67daedd6f74f 34 /*virtual*/ USBSerialStream::~USBSerialStream()
clemounet 0:67daedd6f74f 35 {
clemounet 0:67daedd6f74f 36 m_serial.attach(NULL);
clemounet 0:67daedd6f74f 37 }
clemounet 0:67daedd6f74f 38
clemounet 0:67daedd6f74f 39 //0 for non-blocking (returns immediately), -1 for infinite blocking
clemounet 0:67daedd6f74f 40 /*virtual*/ int USBSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
clemounet 0:67daedd6f74f 41 {
clemounet 0:67daedd6f74f 42 USB_DBG("Trying to read at most %d chars", maxLength);
clemounet 0:67daedd6f74f 43 int ret = waitAvailable(timeout);
clemounet 0:67daedd6f74f 44 if(ret)
clemounet 0:67daedd6f74f 45 {
clemounet 0:67daedd6f74f 46 USB_WARN("Error %d while waiting for incoming data", ret);
clemounet 0:67daedd6f74f 47 return ret;
clemounet 0:67daedd6f74f 48 }
clemounet 0:67daedd6f74f 49 int a = available(); //Prevent macro issues
clemounet 0:67daedd6f74f 50 int readLen = MIN( a, maxLength );
clemounet 0:67daedd6f74f 51 *pLength = readLen;
clemounet 0:67daedd6f74f 52
clemounet 0:67daedd6f74f 53 setupReadableISR(false);
clemounet 0:67daedd6f74f 54 while(readLen--)
clemounet 0:67daedd6f74f 55 {
clemounet 0:67daedd6f74f 56 m_inBuf.dequeue(buf);
clemounet 0:67daedd6f74f 57 buf++;
clemounet 0:67daedd6f74f 58 }
clemounet 0:67daedd6f74f 59 setupReadableISR(true);
clemounet 0:67daedd6f74f 60 USB_DBG("Read %d chars successfully", *pLength);
clemounet 0:67daedd6f74f 61 return OK;
clemounet 0:67daedd6f74f 62 }
clemounet 0:67daedd6f74f 63
clemounet 0:67daedd6f74f 64 /*virtual*/ size_t USBSerialStream::available()
clemounet 0:67daedd6f74f 65 {
clemounet 0:67daedd6f74f 66 setupReadableISR(false); //m_inBuf.available() is not reentrant
clemounet 0:67daedd6f74f 67 size_t len = m_inBuf.available();
clemounet 0:67daedd6f74f 68 setupReadableISR(true);
clemounet 0:67daedd6f74f 69 return len;
clemounet 0:67daedd6f74f 70 }
clemounet 0:67daedd6f74f 71
clemounet 0:67daedd6f74f 72 /*virtual*/ int USBSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
clemounet 0:67daedd6f74f 73 {
clemounet 0:67daedd6f74f 74 int ret;
clemounet 0:67daedd6f74f 75 if(available()) //Is data already available?
clemounet 0:67daedd6f74f 76 {
clemounet 0:67daedd6f74f 77 while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
clemounet 0:67daedd6f74f 78 return OK;
clemounet 0:67daedd6f74f 79 }
clemounet 0:67daedd6f74f 80
clemounet 0:67daedd6f74f 81 USB_DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
clemounet 0:67daedd6f74f 82 ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
clemounet 0:67daedd6f74f 83 if(ret <= 0)
clemounet 0:67daedd6f74f 84 {
clemounet 0:67daedd6f74f 85 USB_DBG("Timeout");
clemounet 0:67daedd6f74f 86 return NET_TIMEOUT;
clemounet 0:67daedd6f74f 87 }
clemounet 0:67daedd6f74f 88 if(!m_inBuf.available()) //Even if abort has been called, return that data is available
clemounet 0:67daedd6f74f 89 {
clemounet 0:67daedd6f74f 90 USB_DBG("Aborted");
clemounet 0:67daedd6f74f 91 return NET_INTERRUPTED;
clemounet 0:67daedd6f74f 92 }
clemounet 0:67daedd6f74f 93 USB_DBG("Finished waiting");
clemounet 0:67daedd6f74f 94 while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
clemounet 0:67daedd6f74f 95 return OK;
clemounet 0:67daedd6f74f 96 }
clemounet 0:67daedd6f74f 97
clemounet 0:67daedd6f74f 98 /*virtual*/ int USBSerialStream::abortRead() //Abort current reading (or waiting) operation
clemounet 0:67daedd6f74f 99 {
clemounet 0:67daedd6f74f 100 if( /*!available()*/true ) //If there is data pending, no need to abort
clemounet 0:67daedd6f74f 101 {
clemounet 0:67daedd6f74f 102 m_availableSphre.release(); //Force exiting the waiting state
clemounet 0:67daedd6f74f 103 }
clemounet 0:67daedd6f74f 104 else
clemounet 0:67daedd6f74f 105 {
clemounet 0:67daedd6f74f 106 USB_DBG("Serial is readable"); ;
clemounet 0:67daedd6f74f 107 }
clemounet 0:67daedd6f74f 108 return OK;
clemounet 0:67daedd6f74f 109 }
clemounet 0:67daedd6f74f 110
clemounet 0:67daedd6f74f 111 void USBSerialStream::setupReadableISR(bool en)
clemounet 0:67daedd6f74f 112 {
clemounet 0:67daedd6f74f 113 m_serial.setupIrq(en, IUSBHostSerial::RxIrq);
clemounet 0:67daedd6f74f 114 }
clemounet 0:67daedd6f74f 115
clemounet 0:67daedd6f74f 116 void USBSerialStream::readable() //Callback from m_serial when new data is available
clemounet 0:67daedd6f74f 117 {
clemounet 0:67daedd6f74f 118 while(m_serial.readable())
clemounet 0:67daedd6f74f 119 {
clemounet 0:67daedd6f74f 120 m_inBuf.queue(m_serial.getc());
clemounet 0:67daedd6f74f 121 }
clemounet 0:67daedd6f74f 122 m_serial.readPacket(); //Start read of next packet
clemounet 0:67daedd6f74f 123 m_availableSphre.release(); //Force exiting the waiting state
clemounet 0:67daedd6f74f 124 }
clemounet 0:67daedd6f74f 125
clemounet 0:67daedd6f74f 126 //0 for non-blocking (returns immediately), -1 for infinite blocking
clemounet 0:67daedd6f74f 127 /*virtual*/ int USBSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=-1*/)
clemounet 0:67daedd6f74f 128 {
clemounet 0:67daedd6f74f 129 USB_DBG("Trying to write %d chars", length);
clemounet 0:67daedd6f74f 130 do
clemounet 0:67daedd6f74f 131 {
clemounet 0:67daedd6f74f 132 int ret = waitSpace(timeout);
clemounet 0:67daedd6f74f 133 if(ret)
clemounet 0:67daedd6f74f 134 {
clemounet 0:67daedd6f74f 135 USB_WARN("Error %d while waiting for space", ret);
clemounet 0:67daedd6f74f 136 return ret;
clemounet 0:67daedd6f74f 137 }
clemounet 0:67daedd6f74f 138 int s = space(); //Prevent macro issues
clemounet 0:67daedd6f74f 139 int writeLen = MIN( s, length );
clemounet 0:67daedd6f74f 140 USB_DBG("Writing %d chars", writeLen);
clemounet 0:67daedd6f74f 141 setupWriteableISR(false);
clemounet 0:67daedd6f74f 142 while(writeLen)
clemounet 0:67daedd6f74f 143 {
clemounet 0:67daedd6f74f 144 m_outBuf.queue(*buf);
clemounet 0:67daedd6f74f 145 buf++;
clemounet 0:67daedd6f74f 146 length--;
clemounet 0:67daedd6f74f 147 writeLen--;
clemounet 0:67daedd6f74f 148 }
clemounet 0:67daedd6f74f 149 //If m_serial tx fifo is empty we need to start the packet write
clemounet 0:67daedd6f74f 150 if( m_outBuf.available() && m_serialTxFifoEmpty )
clemounet 0:67daedd6f74f 151 {
clemounet 0:67daedd6f74f 152 writeable();
clemounet 0:67daedd6f74f 153 }
clemounet 0:67daedd6f74f 154 setupWriteableISR(true);
clemounet 0:67daedd6f74f 155 } while(length);
clemounet 0:67daedd6f74f 156
clemounet 0:67daedd6f74f 157 USB_DBG("Write successful");
clemounet 0:67daedd6f74f 158 return OK;
clemounet 0:67daedd6f74f 159 }
clemounet 0:67daedd6f74f 160
clemounet 0:67daedd6f74f 161 /*virtual*/ size_t USBSerialStream::space()
clemounet 0:67daedd6f74f 162 {
clemounet 0:67daedd6f74f 163 setupWriteableISR(false); //m_outBuf.available() is not reentrant
clemounet 0:67daedd6f74f 164 size_t len = CIRCBUF_SIZE - m_outBuf.available();
clemounet 0:67daedd6f74f 165 setupWriteableISR(true);
clemounet 0:67daedd6f74f 166 return len;
clemounet 0:67daedd6f74f 167 }
clemounet 0:67daedd6f74f 168
clemounet 0:67daedd6f74f 169 /*virtual*/ int USBSerialStream::waitSpace(uint32_t timeout/*=-1*/) //Wait for space to be available
clemounet 0:67daedd6f74f 170 {
clemounet 0:67daedd6f74f 171 int ret;
clemounet 0:67daedd6f74f 172 if(space()) //Is still space already left?
clemounet 0:67daedd6f74f 173 {
clemounet 0:67daedd6f74f 174 while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
clemounet 0:67daedd6f74f 175 return OK;
clemounet 0:67daedd6f74f 176 }
clemounet 0:67daedd6f74f 177
clemounet 0:67daedd6f74f 178 USB_DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
clemounet 0:67daedd6f74f 179 ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
clemounet 0:67daedd6f74f 180 if(ret <= 0)
clemounet 0:67daedd6f74f 181 {
clemounet 0:67daedd6f74f 182 USB_DBG("Timeout");
clemounet 0:67daedd6f74f 183 return NET_TIMEOUT;
clemounet 0:67daedd6f74f 184 }
clemounet 0:67daedd6f74f 185 if(!space()) //Even if abort has been called, return that space is available
clemounet 0:67daedd6f74f 186 {
clemounet 0:67daedd6f74f 187 USB_DBG("Aborted");
clemounet 0:67daedd6f74f 188 return NET_INTERRUPTED;
clemounet 0:67daedd6f74f 189 }
clemounet 0:67daedd6f74f 190 while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
clemounet 0:67daedd6f74f 191 return OK;
clemounet 0:67daedd6f74f 192 }
clemounet 0:67daedd6f74f 193
clemounet 0:67daedd6f74f 194 /*virtual*/ int USBSerialStream::abortWrite() //Abort current writing (or waiting) operation
clemounet 0:67daedd6f74f 195 {
clemounet 0:67daedd6f74f 196 if( !space() ) //If there is space left, no need to abort
clemounet 0:67daedd6f74f 197 {
clemounet 0:67daedd6f74f 198 m_spaceSphre.release(); //Force exiting the waiting state
clemounet 0:67daedd6f74f 199 }
clemounet 0:67daedd6f74f 200 return OK;
clemounet 0:67daedd6f74f 201 }
clemounet 0:67daedd6f74f 202
clemounet 0:67daedd6f74f 203 void USBSerialStream::setupWriteableISR(bool en)
clemounet 0:67daedd6f74f 204 {
clemounet 0:67daedd6f74f 205 m_serial.setupIrq(en, IUSBHostSerial::TxIrq);
clemounet 0:67daedd6f74f 206 }
clemounet 0:67daedd6f74f 207
clemounet 0:67daedd6f74f 208 void USBSerialStream::writeable() //Callback from m_serial when new space is available
clemounet 0:67daedd6f74f 209 {
clemounet 0:67daedd6f74f 210 if(m_outBuf.isEmpty())
clemounet 0:67daedd6f74f 211 {
clemounet 0:67daedd6f74f 212 m_serialTxFifoEmpty = true;
clemounet 0:67daedd6f74f 213 }
clemounet 0:67daedd6f74f 214 else
clemounet 0:67daedd6f74f 215 {
clemounet 0:67daedd6f74f 216 m_serialTxFifoEmpty = false;
clemounet 0:67daedd6f74f 217 while(m_serial.writeable() && !m_outBuf.isEmpty())
clemounet 0:67daedd6f74f 218 {
clemounet 0:67daedd6f74f 219 uint8_t c;
clemounet 0:67daedd6f74f 220 m_outBuf.dequeue(&c);
clemounet 0:67daedd6f74f 221 m_serial.putc((char)c);
clemounet 0:67daedd6f74f 222 }
clemounet 0:67daedd6f74f 223 m_serial.writePacket(); //Start packet write
clemounet 0:67daedd6f74f 224 }
clemounet 0:67daedd6f74f 225 if(!m_outBuf.isFull())
clemounet 0:67daedd6f74f 226 {
clemounet 0:67daedd6f74f 227 m_spaceSphre.release(); //Force exiting the waiting state
clemounet 0:67daedd6f74f 228 }
clemounet 0:67daedd6f74f 229 }