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