Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1702 - 1
/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */
2
/* USB functions */
3
 
4
#include "Usb.h"
5
 
6
static byte usb_error = 0;
7
static byte usb_task_state;
8
DEV_RECORD devtable[ USB_NUMDEVICES + 1 ];
9
EP_RECORD dev0ep;           //Endpoint data structure used during enumeration for uninitialized device
10
 
11
 
12
/* constructor */
13
 
14
USB::USB () {
15
    usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;  //set up state machine
16
    init();
17
}
18
/* Initialize data structures */
19
void USB::init()
20
{
21
  byte i;
22
    for( i = 0; i < ( USB_NUMDEVICES + 1 ); i++ ) {
23
        devtable[ i ].epinfo = NULL;       //clear device table
24
        devtable[ i ].devclass = 0;
25
    }
26
    devtable[ 0 ].epinfo = &dev0ep; //set single ep for uninitialized device  
27
    // not necessary dev0ep.MaxPktSize = 8;          //minimum possible                         
28
    dev0ep.sndToggle = bmSNDTOG0;   //set DATA0/1 toggles to 0
29
    dev0ep.rcvToggle = bmRCVTOG0;
30
}
31
byte USB::getUsbTaskState( void )
32
{
33
    return( usb_task_state );
34
}
35
void USB::setUsbTaskState( byte state )
36
{
37
    usb_task_state = state;
38
}    
39
EP_RECORD* USB::getDevTableEntry( byte addr, byte ep )
40
{
41
  EP_RECORD* ptr;
42
    ptr = devtable[ addr ].epinfo;
43
    ptr += ep;
44
    return( ptr );
45
}
46
/* set device table entry */
47
/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */
48
void USB::setDevTableEntry( byte addr, EP_RECORD* eprecord_ptr )
49
{
50
    devtable[ addr ].epinfo = eprecord_ptr;
51
    //return();
52
}
53
/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer,   */
54
/* depending on request. Actual requests are defined as inlines                                                                                      */
55
/* return codes:                */
56
/* 00       =   success         */
57
/* 01-0f    =   non-zero HRSLT  */
58
byte USB::ctrlReq( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, unsigned int nbytes, char* dataptr, unsigned int nak_limit )
59
{
60
 boolean direction = false;     //request direction, IN or OUT
61
 byte rcode;  
62
 SETUP_PKT setup_pkt;
63
 
64
  regWr( rPERADDR, addr );                    //set peripheral address
65
  if( bmReqType & 0x80 ) {
66
    direction = true;                       //determine request direction
67
  }
68
    /* fill in setup packet */
69
    setup_pkt.ReqType_u.bmRequestType = bmReqType;
70
    setup_pkt.bRequest = bRequest;
71
    setup_pkt.wVal_u.wValueLo = wValLo;
72
    setup_pkt.wVal_u.wValueHi = wValHi;
73
    setup_pkt.wIndex = wInd;
74
    setup_pkt.wLength = nbytes;
75
    bytesWr( rSUDFIFO, 8, ( char *)&setup_pkt );    //transfer to setup packet FIFO
76
    rcode = dispatchPkt( tokSETUP, ep, nak_limit );            //dispatch packet
77
    //Serial.println("Setup packet");   //DEBUG
78
    if( rcode ) {                                   //return HRSLT if not zero
79
        Serial.print("Setup packet error: ");
80
        Serial.print( rcode, HEX );                                          
81
        return( rcode );
82
    }
83
    //Serial.println( direction, HEX ); 
84
    if( dataptr != NULL ) {                         //data stage, if present
85
        rcode = ctrlData( addr, ep, nbytes, dataptr, direction );
86
    }
87
    if( rcode ) {   //return error
88
        Serial.print("Data packet error: ");
89
        Serial.print( rcode, HEX );                                          
90
        return( rcode );
91
    }
92
    rcode = ctrlStatus( ep, direction );                //status stage
93
    return( rcode );
94
}
95
/* Control transfer with status stage and no data stage */
96
/* Assumed peripheral address is already set */
97
byte USB::ctrlStatus( byte ep, boolean direction, unsigned int nak_limit )
98
{
99
  byte rcode;
100
    if( direction ) { //GET
101
        rcode = dispatchPkt( tokOUTHS, ep, nak_limit );
102
    }
103
    else {
104
        rcode = dispatchPkt( tokINHS, ep, nak_limit );
105
    }
106
    return( rcode );
107
}
108
/* Control transfer with data stage. Stages 2 and 3 of control transfer. Assumes preipheral address is set and setup packet has been sent */
109
byte USB::ctrlData( byte addr, byte ep, unsigned int nbytes, char* dataptr, boolean direction, unsigned int nak_limit )
110
{
111
 byte rcode;
112
  if( direction ) {                      //IN transfer
113
    devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
114
    rcode = inTransfer( addr, ep, nbytes, dataptr, nak_limit );
115
    return( rcode );
116
  }
117
  else {              //OUT transfer
118
    devtable[ addr ].epinfo[ ep ].sndToggle = bmSNDTOG1;
119
    rcode = outTransfer( addr, ep, nbytes, dataptr, nak_limit );
120
    return( rcode );
121
  }    
122
}
123
/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
124
/* Keep sending INs and writes data to memory area pointed by 'data'                                                           */
125
/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error,
126
            fe USB xfer timeout */
127
byte USB::inTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit )
128
{
129
 byte rcode;
130
 byte pktsize;
131
 byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize;
132
 unsigned int xfrlen = 0;
133
    regWr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle );    //set toggle value
134
    while( 1 ) { // use a 'return' to exit this loop
135
        rcode = dispatchPkt( tokIN, ep, nak_limit );           //IN packet to EP-'endpoint'. Function takes care of NAKS.
136
        if( rcode ) {
137
            return( rcode );                            //should be 0, indicating ACK. Else return error code.
138
        }
139
        /* check for RCVDAVIRQ and generate error if not present */
140
        /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */
141
        if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) {
142
            return ( 0xf0 );                            //receive error
143
        }
144
        pktsize = regRd( rRCVBC );                      //number of received bytes
145
        data = bytesRd( rRCVFIFO, pktsize, data );
146
        regWr( rHIRQ, bmRCVDAVIRQ );                    // Clear the IRQ & free the buffer
147
        xfrlen += pktsize;                              // add this packet's byte count to total transfer length
148
        /* The transfer is complete under two conditions:           */
149
        /* 1. The device sent a short packet (L.T. maxPacketSize)   */
150
        /* 2. 'nbytes' have been transferred.                       */
151
        if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) {      // have we transferred 'nbytes' bytes?
152
            if( regRd( rHRSL ) & bmRCVTOGRD ) {                     //save toggle value
153
                devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1;
154
            }
155
            else {
156
                devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0;
157
            }
158
            return( 0 );
159
        }
160
  }//while( 1 )
161
}
162
/* OUT transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
163
/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer   */
164
/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL                       */
165
/* major part of this function borrowed from code shared by Richard Ibbotson    */
166
byte USB::outTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit )
167
{
168
 byte rcode, retry_count;
169
 char* data_p = data;   //local copy of the data pointer
170
 unsigned int bytes_tosend, nak_count;
171
 unsigned int bytes_left = nbytes;
172
 byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize;
173
 unsigned long timeout = millis() + USB_XFER_TIMEOUT;
174
 
175
  if (!maxpktsize) { //todo: move this check close to epinfo init. Make it 1< pktsize <64
176
    return 0xFE;
177
  }
178
 
179
  regWr( rHCTL, devtable[ addr ].epinfo[ ep ].sndToggle );    //set toggle value
180
  while( bytes_left ) {
181
    retry_count = 0;
182
    nak_count = 0;
183
    bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
184
    bytesWr( rSNDFIFO, bytes_tosend, data_p );      //filling output FIFO
185
    regWr( rSNDBC, bytes_tosend );                  //set number of bytes    
186
    regWr( rHXFR, ( tokOUT | ep ));                 //dispatch packet
187
    while(!(regRd( rHIRQ ) & bmHXFRDNIRQ ));        //wait for the completion IRQ
188
    regWr( rHIRQ, bmHXFRDNIRQ );                    //clear IRQ
189
    rcode = ( regRd( rHRSL ) & 0x0f );
190
    while( rcode && ( timeout > millis())) {
191
      switch( rcode ) {
192
        case hrNAK:
193
          nak_count++;
194
          if( nak_limit && ( nak_count == USB_NAK_LIMIT )) {
195
            return( rcode);                                   //return NAK
196
          }
197
          break;
198
        case hrTIMEOUT:
199
          retry_count++;
200
          if( retry_count == USB_RETRY_LIMIT ) {
201
            return( rcode );    //return TIMEOUT
202
          }
203
          break;
204
        default:  
205
          return( rcode );
206
      }//switch( rcode...
207
      /* process NAK according to Host out NAK bug */
208
      regWr( rSNDBC, 0 );
209
      regWr( rSNDFIFO, *data_p );
210
      regWr( rSNDBC, bytes_tosend );
211
      regWr( rHXFR, ( tokOUT | ep ));                 //dispatch packet
212
      while(!(regRd( rHIRQ ) & bmHXFRDNIRQ ));        //wait for the completion IRQ
213
      regWr( rHIRQ, bmHXFRDNIRQ );                    //clear IRQ
214
      rcode = ( regRd( rHRSL ) & 0x0f );
215
    }//while( rcode && ....
216
    bytes_left -= bytes_tosend;
217
    data_p += bytes_tosend;
218
  }//while( bytes_left...
219
  devtable[ addr ].epinfo[ ep ].sndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? bmSNDTOG1 : bmSNDTOG0;  //update toggle
220
  return( rcode );    //should be 0 in all cases
221
}
222
/* dispatch usb packet. Assumes peripheral address is set and relevant buffer is loaded/empty       */
223
/* If NAK, tries to re-send up to nak_limit times                                                   */
224
/* If nak_limit == 0, do not count NAKs, exit after timeout                                         */
225
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times                                             */
226
/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout                       */
227
byte USB::dispatchPkt( byte token, byte ep, unsigned int nak_limit )
228
{
229
 unsigned long timeout = millis() + USB_XFER_TIMEOUT;
230
 byte tmpdata;  
231
 byte rcode;
232
 unsigned int nak_count = 0;
233
 char retry_count = 0;
234
 
235
  while( timeout > millis() ) {
236
    regWr( rHXFR, ( token|ep ));            //launch the transfer
237
    rcode = 0xff;  
238
    while( millis() < timeout ) {           //wait for transfer completion
239
      tmpdata = regRd( rHIRQ );
240
      if( tmpdata & bmHXFRDNIRQ ) {
241
        regWr( rHIRQ, bmHXFRDNIRQ );    //clear the interrupt
242
        rcode = 0x00;
243
        break;
244
      }//if( tmpdata & bmHXFRDNIRQ
245
    }//while ( millis() < timeout
246
    if( rcode != 0x00 ) {                //exit if timeout
247
      return( rcode );
248
    }
249
    rcode = ( regRd( rHRSL ) & 0x0f );  //analyze transfer result
250
    switch( rcode ) {
251
      case hrNAK:
252
        nak_count ++;
253
        if( nak_limit && ( nak_count == nak_limit )) {
254
          return( rcode );
255
        }
256
        break;
257
      case hrTIMEOUT:
258
        retry_count ++;
259
        if( retry_count == USB_RETRY_LIMIT ) {
260
          return( rcode );
261
        }
262
        break;
263
      default:
264
        return( rcode );
265
    }//switch( rcode
266
  }//while( timeout > millis() 
267
  return( rcode );
268
}
269
/* USB main task. Performs enumeration/cleanup */
270
void USB::Task( void )      //USB state machine
271
{
272
  byte i;  
273
  byte rcode;
274
  static byte tmpaddr;
275
  byte tmpdata;
276
  static unsigned long delay = 0;
277
  USB_DEVICE_DESCRIPTOR buf;
278
    tmpdata = getVbusState();
279
    /* modify USB task state if Vbus changed */
280
 
281
    switch( tmpdata ) {
282
        case SE1:   //illegal state
283
            usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
284
            break;
285
        case SE0:   //disconnected
286
            if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) {
287
                usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
288
            }
289
            break;
290
        case FSHOST:    //attached
291
        case LSHOST:
292
            if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
293
                delay = millis() + USB_SETTLE_DELAY;
294
                usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
295
            }
296
            break;
297
        }// switch( tmpdata
298
    //Serial.print("USB task state: ");
299
    //Serial.println( usb_task_state, HEX );
300
    switch( usb_task_state ) {
301
        case USB_DETACHED_SUBSTATE_INITIALIZE:
302
            init();
303
            usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
304
            break;
305
        case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE:     //just sit here
306
            break;
307
        case USB_DETACHED_SUBSTATE_ILLEGAL:             //just sit here
308
            break;
309
        case USB_ATTACHED_SUBSTATE_SETTLE:              //setlle time for just attached device                  
310
            if( delay < millis() ) {
311
                usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
312
            }
313
            break;
314
        case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
315
            regWr( rHCTL, bmBUSRST );                   //issue bus reset
316
            usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
317
            break;
318
        case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
319
            if(( regRd( rHCTL ) & bmBUSRST ) == 0 ) {
320
                tmpdata = regRd( rMODE ) | bmSOFKAENAB;                 //start SOF generation
321
                regWr( rMODE, tmpdata );
322
//                  regWr( rMODE, bmSOFKAENAB );
323
                usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
324
                delay = millis() + 20; //20ms wait after reset per USB spec
325
            }
326
            break;
327
        case USB_ATTACHED_SUBSTATE_WAIT_SOF:  //todo: change check order
328
            if( regRd( rHIRQ ) & bmFRAMEIRQ ) {                         //when first SOF received we can continue
329
              if( delay < millis() ) {                                    //20ms passed
330
                usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
331
              }
332
            }
333
            break;
334
        case USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE:
335
            // toggle( BPNT_0 );
336
            devtable[ 0 ].epinfo->MaxPktSize = 8;   //set max.packet size to min.allowed
337
            rcode = getDevDescr( 0, 0, 8, ( char* )&buf );
338
            if( rcode == 0 ) {
339
                devtable[ 0 ].epinfo->MaxPktSize = buf.bMaxPacketSize0;
340
                usb_task_state = USB_STATE_ADDRESSING;
341
            }
342
            else {
343
                usb_error = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE;
344
                usb_task_state = USB_STATE_ERROR;
345
            }
346
            break;
347
        case USB_STATE_ADDRESSING:
348
            for( i = 1; i < USB_NUMDEVICES; i++ ) {
349
                if( devtable[ i ].epinfo == NULL ) {
350
                    devtable[ i ].epinfo = devtable[ 0 ].epinfo;        //set correct MaxPktSize
351
                                                                        //temporary record
352
                                                                        //until plugged with real device endpoint structure
353
                    rcode = setAddr( 0, 0, i );
354
                    if( rcode == 0 ) {
355
                        tmpaddr = i;
356
                        usb_task_state = USB_STATE_CONFIGURING;
357
                    }
358
                    else {
359
                        usb_error = USB_STATE_ADDRESSING;          //set address error
360
                        usb_task_state = USB_STATE_ERROR;
361
                    }
362
                    break;  //break if address assigned or error occured during address assignment attempt                      
363
                }
364
            }//for( i = 1; i < USB_NUMDEVICES; i++
365
            if( usb_task_state == USB_STATE_ADDRESSING ) {     //no vacant place in devtable
366
                usb_error = 0xfe;
367
                usb_task_state = USB_STATE_ERROR;
368
            }
369
            break;
370
        case USB_STATE_CONFIGURING:
371
            break;
372
        case USB_STATE_RUNNING:
373
            break;
374
        case USB_STATE_ERROR:
375
            break;
376
    }// switch( usb_task_state
377
}    
378