Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
USBSerialStream.cpp
00001 /* USBSerialStream.cpp */ 00002 /* Copyright (C) 2012 mbed.org, MIT License 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00005 * and associated documentation files (the "Software"), to deal in the Software without restriction, 00006 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 00007 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 00008 * furnished to do so, subject to the following conditions: 00009 * 00010 * The above copyright notice and this permission notice shall be included in all copies or 00011 * substantial portions of the Software. 00012 * 00013 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00014 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00015 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00016 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00017 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00018 */ 00019 00020 #define __DEBUG__ 0 00021 #ifndef __MODULE__ 00022 #define __MODULE__ "USBSerialStream.cpp" 00023 #endif 00024 00025 #include "core/fwk.h" 00026 00027 #include <cstring> 00028 00029 #include "USBSerialStream.h" 00030 00031 00032 USBSerialStream::USBSerialStream(IUSBHostSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true), 00033 m_availableSphre(1), m_spaceSphre(1), m_inBuf() 00034 { 00035 m_availableSphre.wait(); 00036 m_spaceSphre.wait(); 00037 //Attach interrupts 00038 m_serial.attach(this); 00039 } 00040 00041 /*virtual*/ USBSerialStream::~USBSerialStream() 00042 { 00043 m_serial.attach(NULL); 00044 } 00045 00046 //0 for non-blocking (returns immediately), -1 for infinite blocking 00047 /*virtual*/ int USBSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/) 00048 { 00049 DBG("Trying to read at most %d chars", maxLength); 00050 int ret = waitAvailable(timeout); 00051 if(ret) 00052 { 00053 WARN("Error %d while waiting for incoming data", ret); 00054 return ret; 00055 } 00056 int a = available(); //Prevent macro issues 00057 int readLen = MIN( a, maxLength ); 00058 *pLength = readLen; 00059 00060 setupReadableISR(false); 00061 while(readLen--) 00062 { 00063 m_inBuf.dequeue(buf); 00064 buf++; 00065 } 00066 setupReadableISR(true); 00067 DBG("Read %d chars successfully", *pLength); 00068 return OK; 00069 } 00070 00071 /*virtual*/ size_t USBSerialStream::available() 00072 { 00073 setupReadableISR(false); //m_inBuf.available() is not reentrant 00074 size_t len = m_inBuf.available(); 00075 setupReadableISR(true); 00076 return len; 00077 } 00078 00079 /*virtual*/ int USBSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available 00080 { 00081 int ret; 00082 if(available()) //Is data already available? 00083 { 00084 while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available 00085 return OK; 00086 } 00087 00088 DBG("Waiting for data availability %d ms (-1 is infinite)", timeout); 00089 ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort 00090 if(ret <= 0) 00091 { 00092 DBG("Timeout"); 00093 return NET_TIMEOUT; 00094 } 00095 if(!m_inBuf.available()) //Even if abort has been called, return that data is available 00096 { 00097 DBG("Aborted"); 00098 return NET_INTERRUPTED; 00099 } 00100 DBG("Finished waiting"); 00101 while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available 00102 return OK; 00103 } 00104 00105 /*virtual*/ int USBSerialStream::abortRead() //Abort current reading (or waiting) operation 00106 { 00107 if( /*!available()*/true ) //If there is data pending, no need to abort 00108 { 00109 m_availableSphre.release(); //Force exiting the waiting state 00110 } 00111 else 00112 { 00113 DBG("Serial is readable"); ; 00114 } 00115 return OK; 00116 } 00117 00118 void USBSerialStream::setupReadableISR(bool en) 00119 { 00120 m_serial.setupIrq(en, IUSBHostSerial::RxIrq); 00121 } 00122 00123 void USBSerialStream::readable() //Callback from m_serial when new data is available 00124 { 00125 while(m_serial.readable()) 00126 { 00127 m_inBuf.queue(m_serial.getc()); 00128 } 00129 m_serial.readPacket(); //Start read of next packet 00130 m_availableSphre.release(); //Force exiting the waiting state 00131 } 00132 00133 //0 for non-blocking (returns immediately), -1 for infinite blocking 00134 /*virtual*/ int USBSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=-1*/) 00135 { 00136 DBG("Trying to write %d chars", length); 00137 do 00138 { 00139 int ret = waitSpace(timeout); 00140 if(ret) 00141 { 00142 WARN("Error %d while waiting for space", ret); 00143 return ret; 00144 } 00145 int s = space(); //Prevent macro issues 00146 int writeLen = MIN( s, length ); 00147 DBG("Writing %d chars", writeLen); 00148 setupWriteableISR(false); 00149 while(writeLen) 00150 { 00151 m_outBuf.queue(*buf); 00152 buf++; 00153 length--; 00154 writeLen--; 00155 } 00156 //If m_serial tx fifo is empty we need to start the packet write 00157 if( m_outBuf.available() && m_serialTxFifoEmpty ) 00158 { 00159 writeable(); 00160 } 00161 setupWriteableISR(true); 00162 } while(length); 00163 00164 DBG("Write successful"); 00165 return OK; 00166 } 00167 00168 /*virtual*/ size_t USBSerialStream::space() 00169 { 00170 setupWriteableISR(false); //m_outBuf.available() is not reentrant 00171 size_t len = CIRCBUF_SIZE - m_outBuf.available(); 00172 setupWriteableISR(true); 00173 return len; 00174 } 00175 00176 /*virtual*/ int USBSerialStream::waitSpace(uint32_t timeout/*=-1*/) //Wait for space to be available 00177 { 00178 int ret; 00179 if(space()) //Is still space already left? 00180 { 00181 while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available 00182 return OK; 00183 } 00184 00185 DBG("Waiting for data space %d ms (-1 is infinite)", timeout); 00186 ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort 00187 if(ret <= 0) 00188 { 00189 DBG("Timeout"); 00190 return NET_TIMEOUT; 00191 } 00192 if(!space()) //Even if abort has been called, return that space is available 00193 { 00194 DBG("Aborted"); 00195 return NET_INTERRUPTED; 00196 } 00197 while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available 00198 return OK; 00199 } 00200 00201 /*virtual*/ int USBSerialStream::abortWrite() //Abort current writing (or waiting) operation 00202 { 00203 if( !space() ) //If there is space left, no need to abort 00204 { 00205 m_spaceSphre.release(); //Force exiting the waiting state 00206 } 00207 return OK; 00208 } 00209 00210 void USBSerialStream::setupWriteableISR(bool en) 00211 { 00212 m_serial.setupIrq(en, IUSBHostSerial::TxIrq); 00213 } 00214 00215 void USBSerialStream::writeable() //Callback from m_serial when new space is available 00216 { 00217 if(m_outBuf.isEmpty()) 00218 { 00219 m_serialTxFifoEmpty = true; 00220 } 00221 else 00222 { 00223 m_serialTxFifoEmpty = false; 00224 while(m_serial.writeable() && !m_outBuf.isEmpty()) 00225 { 00226 uint8_t c; 00227 m_outBuf.dequeue(&c); 00228 m_serial.putc((char)c); 00229 } 00230 m_serial.writePacket(); //Start packet write 00231 } 00232 if(!m_outBuf.isFull()) 00233 { 00234 m_spaceSphre.release(); //Force exiting the waiting state 00235 } 00236 }
Generated on Tue Jul 12 2022 17:35:00 by
1.7.2