$search
00001 /* 00002 Aseba - an event-based framework for distributed robot control 00003 Copyright (C) 2007--2010: 00004 Stephane Magnenat <stephane at magnenat dot net> 00005 (http://stephane.magnenat.net) 00006 and other contributors, see authors.txt for details 00007 00008 This program is free software: you can redistribute it and/or modify 00009 it under the terms of the GNU Lesser General Public License as published 00010 by the Free Software Foundation, version 3 of the License. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 #include <usb/usb.h> 00022 #include <usb/usb_device.h> 00023 #include "usb_function_cdc.h" 00024 #include "usb-buffer.h" 00025 #include "usb_uart.h" 00026 00027 struct fifo { 00028 unsigned char * buffer; 00029 size_t size; 00030 size_t insert; 00031 size_t consume; 00032 }; 00033 00034 static struct { 00035 struct fifo rx; 00036 struct fifo tx; 00037 } AsebaUsb; 00038 00039 /* Basic assumption in order to protect concurrent access to the fifos: 00040 - If the code in "main()" access the fifo it need to disable the usb interrupt 00041 */ 00042 00043 static inline size_t get_used(struct fifo * f) { 00044 size_t ipos, cpos; 00045 ipos = f->insert; 00046 cpos = f->consume; 00047 if (ipos >= cpos) 00048 return ipos - cpos; 00049 else 00050 return f->size - cpos + ipos; 00051 } 00052 00053 static inline size_t get_free(struct fifo * f) { 00054 return f->size - get_used(f); 00055 } 00056 00057 /* you MUST ensure that you pass correct size to thoses two function, 00058 * no check are done .... 00059 */ 00060 static inline void memcpy_out_fifo(unsigned char * dest, struct fifo * f, size_t size) { 00061 while(size--) { 00062 *dest++ = f->buffer[f->consume++]; 00063 if(f->consume == f->size) 00064 f->consume = 0; 00065 } 00066 } 00067 00068 static inline void memcpy_to_fifo(struct fifo * f, const unsigned char * src, size_t size) { 00069 while(size--) { 00070 f->buffer[f->insert++] = *src++; 00071 if(f->insert == f->size) 00072 f->insert = 0; 00073 } 00074 } 00075 00076 static inline void fifo_peek(unsigned char * d, struct fifo * f,size_t size) { 00077 int ct = f->consume; 00078 while(size--) { 00079 *d++ = f->buffer[ct++]; 00080 if(ct == f->size) 00081 ct = 0; 00082 } 00083 } 00084 00085 static inline void fifo_reset(struct fifo * f) { 00086 f->insert = f->consume = 0; 00087 } 00088 00089 /* USB interrupt part */ 00090 // They can be called from the main, but with usb interrupt disabled, so it's OK 00091 static int tx_busy; 00092 static int debug; 00093 00094 unsigned char AsebaTxReady(unsigned char *data) { 00095 size_t size = get_used(&AsebaUsb.tx); 00096 00097 if(size == 0) { 00098 tx_busy = 0; 00099 debug = 0; 00100 return 0; 00101 } 00102 00103 if(size > ASEBA_USB_MTU) 00104 size = ASEBA_USB_MTU; 00105 00106 memcpy_out_fifo(data, &AsebaUsb.tx, size); 00107 debug ++; 00108 return size; 00109 } 00110 00111 int AsebaUsbBulkRecv(unsigned char *data, unsigned char size) { 00112 size_t free = get_free(&AsebaUsb.rx); 00113 00114 if(size >= free) 00115 return 1; 00116 00117 memcpy_to_fifo(&AsebaUsb.rx, data, size); 00118 00119 return 0; 00120 } 00121 00122 /* main() part */ 00123 00124 void AsebaSendBuffer(AsebaVMState *vm, const uint8 *data, uint16 length) { 00125 int flags; 00126 // Here we must loop until we can send the data. 00127 // BUT if the usb connection is not available, we drop the packet 00128 if(!usb_uart_serial_port_open()) 00129 return; 00130 00131 // Sanity check, should never be true 00132 if (length < 2) 00133 return; 00134 00135 do { 00136 USBMaskInterrupts(flags); 00137 if(get_free(&AsebaUsb.tx) > length + 4) { 00138 length -= 2; 00139 memcpy_to_fifo(&AsebaUsb.tx, (unsigned char *) &length, 2); 00140 memcpy_to_fifo(&AsebaUsb.tx, (unsigned char *) &vm->nodeId, 2); 00141 memcpy_to_fifo(&AsebaUsb.tx, (unsigned char *) data, length + 2); 00142 00143 // Will callback AsebaUsbTxReady 00144 if (!tx_busy) { 00145 tx_busy = 1; 00146 USBCDCKickTx(); 00147 } 00148 00149 length = 0; 00150 } 00151 00152 00153 00154 // Usb can be disconnected while sending ... 00155 if(!usb_uart_serial_port_open()) { 00156 fifo_reset(&AsebaUsb.tx); 00157 USBUnmaskInterrupts(flags); 00158 break; 00159 } 00160 00161 USBUnmaskInterrupts(flags); 00162 } while(length); 00163 } 00164 00165 uint16 AsebaGetBuffer(AsebaVMState *vm, uint8 * data, uint16 maxLength, uint16* source) { 00166 int flags; 00167 uint16 ret = 0; 00168 size_t u; 00169 // Touching the FIFO, mask the interrupt ... 00170 USBMaskInterrupts(flags); 00171 00172 u = get_used(&AsebaUsb.rx); 00173 00174 /* Minium packet size == len + src + msg_type == 6 bytes */ 00175 if(u >= 6) { 00176 int len; 00177 fifo_peek((unsigned char *) &len, &AsebaUsb.rx, 2); 00178 if (u >= len + 6) { 00179 memcpy_out_fifo((unsigned char *) &len, &AsebaUsb.rx, 2); 00180 memcpy_out_fifo((unsigned char *) source, &AsebaUsb.rx, 2); 00181 // msg_type is not in the len but is always present 00182 len = len + 2; 00183 /* Yay ! We have a complete packet ! */ 00184 if(len > maxLength) 00185 len = maxLength; 00186 memcpy_out_fifo(data, &AsebaUsb.rx, len); 00187 ret = len; 00188 } 00189 } 00190 if(usb_uart_serial_port_open()) 00191 USBCDCKickRx(); 00192 else 00193 fifo_reset(&AsebaUsb.rx); 00194 00195 USBUnmaskInterrupts(flags); 00196 return ret; 00197 } 00198 00199 void AsebaUsbInit(unsigned char * sendQueue, size_t sendQueueSize, unsigned char * recvQueue, size_t recvQueueSize) { 00200 AsebaUsb.tx.buffer = sendQueue; 00201 AsebaUsb.tx.size = sendQueueSize; 00202 00203 AsebaUsb.rx.buffer = recvQueue; 00204 AsebaUsb.rx.size = recvQueueSize; 00205 } 00206 00207 int AsebaUsbRecvBufferEmpty(void) { 00208 // We are called with interrupt disabled ! Check if rx contain something meaningfull 00209 00210 int u; 00211 00212 u = get_used(&AsebaUsb.rx); 00213 if(u > 6) { 00214 int len; 00215 fifo_peek((unsigned char *) &len, &AsebaUsb.rx, 2); 00216 if (u >= len + 6) 00217 return 0; 00218 } 00219 return 1; 00220 } 00221 00222 int AsebaUsbTxBusy(void) { 00223 return tx_busy; 00224 }