Implementation of 3G USB Modem Huawei E372
USBSerialStream.cpp@2:61ac95f0af72, 2015-04-14 (annotated)
- 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?
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 | 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 | } |