Implementation of 3G USB Modem Huawei E372
USBSerialStream.cpp@0:67daedd6f74f, 2015-02-20 (annotated)
- 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?
User | Revision | Line number | New 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 | } |