usb_cdc_class.c

Go to the documentation of this file.
00001 
00015 #include "config.h"
00016 
00017 // PicPack includes
00018 #include "pic_usb.h"
00019 #include "pic_usb_buffer_mgt.h"
00020 
00021 #ifdef CDC_DEBUG
00022     #include "pic_serial.h"
00023 #endif
00024 
00025 // local includes
00026 #include "usb_cdc_class.h"
00027 
00028 // system includes
00029 #include "memory.h"
00030 
00031 // class definitions
00032 
00033 #define req_SEND_ENCAPSULATED_COMMAND   0x00
00034 #define req_GET_ENCAPSULATED_RESPONSE   0x01
00035 #define req_SET_COMM_FEATURE            0x02
00036 #define req_GET_COMM_FEATURE            0x03
00037 #define req_CLEAR_COMM_FEATURE          0x04
00038 #define req_SET_LINE_CODING             0x20
00039 #define req_GET_LINE_CODING             0x21
00040 #define req_SET_CONTROL_LINE_STATE      0x22
00041 #define req_SEND_BREAK                  0x23
00042 
00043 typedef  union _long_union{
00044         long as_long;
00045         uns8 as_byte_array[4];
00046 } long_union;
00047 
00051 typedef struct _line_coding  {
00052     long_union  dte_rate;
00053     uns8    stop_bits;  // 0=1 stop bit, 1=1.5 stop bits, 2=2 stop bits
00054     uns8    parity;     // 0=None, 1=Odd, 2=Even, 3=Mark, 4=Space
00055     uns8    data_bits;  // 5,6,7,8 or 16 bits
00056 }   line_coding;
00057 
00059 uns8 cdc_tx_buffer[USB_CDC_TX_BUFFER_SIZE];
00061 uns8 cdc_tx_start=0;
00063 uns8 cdc_tx_end=0;
00064 
00066 uns8 cdc_rx_buffer[USB_CDC_RX_BUFFER_SIZE];
00068 uns8 cdc_rx_start = 0;
00070 uns8 cdc_rx_end = 0;
00071     
00072 
00073 uns8 class_data[8]; // we'll dump all our class data in here
00074 
00075 
00076 void usb_handle_class_request_callback(setup_data_packet sdp) {
00077 
00078     switch (sdp.bRequest) {
00079         case req_SET_LINE_CODING:
00080             // we now expect the line coding to arrive in the data stage
00081             
00082             #ifdef CDC_DEBUG
00083                 serial_print_str("SET_LINE ");
00084             #endif
00085             control_mode = cm_CTRL_WRITE_DATA_STAGE_CLASS;
00086             break;
00087         case req_GET_LINE_CODING:
00088             #ifdef CDC_DEBUG
00089                 serial_print_str("GET_LINE ");
00090                 serial_print_str(" len=");
00091                 serial_print_int(sdp.wLength);
00092                 serial_putc(' ');
00093             #endif
00094             //control_mode = cm_CTRL_READ_DATA_STAGE_CLASS;
00095             control_mode = cm_CTRL_READ_DATA_STAGE_CLASS;
00096             //  need to prime ep0 IN with some funky data here
00097             usb_send_data(/*ep*/ 0, /*data*/ &class_data, /*count*/ 7, /*first*/ 1);
00098             // actually we know this will be the last packet, so go straight to waiting for the status ack
00099             control_mode = cm_CTRL_READ_AWAITING_STATUS;
00100             
00101             break;
00102         case req_SET_CONTROL_LINE_STATE:
00103             #ifdef CDC_DEBUG
00104                 serial_print_str("scls=");//dtr = bit 0, rts = bit 1
00105                 serial_print_int_hex(sdp.wValue);
00106             #endif
00107             // no data, so just ack the status
00108             control_mode = cm_CTRL_WRITE_SENDING_STATUS;
00109             usb_send_status_ack();
00110             // Could put a callback here for your own code when DTR or RTS change
00111             break;
00112         default:
00113             #ifdef CDC_DEBUG
00114                 serial_print_str("??r=");
00115                 serial_print_int(sdp.bRequest);
00116             #endif  
00117     }
00118 }
00119 
00120 void usb_handle_class_ctrl_write_callback(uns8 *data, uns16 count) {
00121 
00122     switch (usb_sdp.bRequest) {
00123         case req_SET_LINE_CODING:
00124             // dump it into class_data
00125             memcpy(/* dst */ (void *)&class_data,/* src */ (void *)data, count);
00126             
00127             // Now we need to send an ACK status back
00128             control_mode = cm_CTRL_WRITE_SENDING_STATUS;
00129             usb_send_status_ack();
00130             line_coding *my_lc;
00131             my_lc = (line_coding*) &class_data;
00132             #ifdef CDC_DEBUG
00133                 serial_print_int_hex(my_lc->dte_rate.as_byte_array[0]);
00134                 serial_print_int_hex(my_lc->dte_rate.as_byte_array[1]);
00135                 serial_print_int_hex(my_lc->dte_rate.as_byte_array[2]);
00136                 serial_print_int_hex(my_lc->dte_rate.as_byte_array[3]);
00137                 serial_print_str(" st=");
00138                 serial_print_int(my_lc->stop_bits);
00139                 serial_print_str(" p=");
00140                 serial_print_int(my_lc->parity);
00141                 serial_print_str(" db=");
00142                 serial_print_int(my_lc->data_bits);
00143             #endif
00144             break;  
00145         default:
00146             #ifdef CDC_DEBUG
00147                 serial_print_str(" ??ctrl write cb req=");
00148                 serial_print_int_hex(usb_sdp.bRequest);
00149                 serial_putc(' ');
00150             #endif  
00151             break;
00152     }       
00153 }   
00154 
00155 void usb_handle_class_ctrl_read_callback() {
00156         switch (usb_sdp.bRequest) {
00157             case req_GET_LINE_CODING:
00158                 // we know we've already sent everything, so now wait for status
00159                 control_mode = cm_CTRL_READ_AWAITING_STATUS;
00160                 break;
00161             default:
00162                 #ifdef CDC_DEBUG
00163                     serial_print_str(" cl read ?? ");
00164                     serial_print_int(usb_sdp.bRequest);
00165                 #endif  
00166         }       
00167             
00168 }
00169 
00170 void usb_ep_data_out_callback(uns8 end_point, uns8 *buffer,
00171                               uns16 byte_count) {
00172     uns8 cdc_rx_next;
00173     #ifdef CDC_DEBUG
00174         serial_print_str(" EP data out: ");
00175         serial_print_int(byte_count);
00176         serial_print_str(" bytes ");
00177     #endif  
00178     // We have some data!
00179     if (end_point == USB_CDC_DATA_ENDPOINT) {   // it's the data end point
00180         uns8 count;
00181         for (count = 0; count < byte_count; count++) {
00182             cdc_rx_next = cdc_rx_end + 1;   // get next buffer position 
00183             if (cdc_rx_next == USB_CDC_RX_BUFFER_SIZE) {    // if we're at the end
00184                 cdc_rx_next = 0;    // then wrap to the beginning
00185             }
00186             if (cdc_rx_next != cdc_rx_start) { // if space in the fifo
00187                 cdc_rx_buffer[cdc_rx_end] = buffer[count]; // put it in
00188                 cdc_rx_end = cdc_rx_next;  // and move pointer along
00189             } // else... just ignore it, we've lost a byte, no room in the inn
00190         }   
00191     } else {
00192         #ifdef CDC_DEBUG
00193             serial_print_str("data for ep ");
00194             serial_print_int(end_point);
00195         #endif  
00196     }
00197 }       
00198 
00199 
00200 
00201 void usb_ep_data_in_callback(uns8 end_point, uns16 byte_count) {
00202     #ifdef CDC_DEBUG
00203         serial_print_str(" EP data in: ");
00204         serial_print_int(byte_count);
00205         serial_print_str(" bytes ");
00206     #endif  
00207     // data has been sent, so do we need to send more?
00208     if (end_point == USB_CDC_DATA_ENDPOINT) {   // it's the data end point
00209         usb_cdc_handle_tx();
00210     }   
00211 }   
00212 
00213 
00214 
00215 void usb_cdc_putc(uns8 c) {
00216 uns8 cdc_tx_next;
00217 bit  my_store_gie;
00218 #ifdef CDC_IDE_DEBUG
00219 return;
00220 #endif
00221 
00222     cdc_tx_next = cdc_tx_end + 1;   // get next buffer position
00223     if (cdc_tx_next == USB_CDC_TX_BUFFER_SIZE) {    // if we're at the end
00224         cdc_tx_next = 0;    // wrap to the beginning
00225     }
00226     
00227     if ((!intcon.GIE) && (cdc_tx_next == cdc_tx_start)) {
00228         return;
00229     }
00230     while (cdc_tx_next == cdc_tx_start) { 
00231     }       
00232     my_store_gie = intcon.GIE;  // store interrupt state
00233     kill_interrupts();  // turn off global interrupts
00234     
00235     cdc_tx_buffer[cdc_tx_end] = c; // put it in
00236     cdc_tx_end = cdc_tx_next;  // move pointer along
00237     
00238     intcon.GIE = my_store_gie;  // restore interrupt state
00239     
00240 }
00241 
00242 uns8 usb_cdc_getc(void)
00243 {
00244     uns8 cdc_rx_char, cdc_rx_next;
00245     
00246     while(cdc_rx_end == cdc_rx_start);  // wait until there is something received
00247 
00248     start_crit_sec();   // make sure nobody else can muck with the buffer
00249     
00250     cdc_rx_char = cdc_rx_buffer[cdc_rx_start];  // get character from the front of the buffer
00251     cdc_rx_start++; // increment fifo start
00252     if (cdc_rx_start == USB_CDC_RX_BUFFER_SIZE) {   // if we're at the end
00253         cdc_rx_start = 0;   // then wrap to the beginning
00254     }
00255     
00256     end_crit_sec(); // now they can muck with the buffer
00257     
00258     return (cdc_rx_char);   // return the result we first thought of
00259 
00260 }   // -- getc    
00261 
00262 
00263 void usb_cdc_handle_tx()
00264 {
00265 uns8 cdc_tx_next;
00266 uns8 count;
00267 uns16 buffer_size;
00268 uns8 *buffer;
00269 buffer_descriptor *bd;
00270 
00271     bd = ep_in_bd_location[USB_CDC_DATA_ENDPOINT];
00272     if (test_bit(bd->stat, UOWN)) { // if there's already something in play
00273         return; // give up
00274     }
00275     
00276     buffer_size = ep_in_buffer_size[USB_CDC_DATA_ENDPOINT];
00277     buffer = ep_in_buffer_location[USB_CDC_DATA_ENDPOINT];
00278 
00279     if (cdc_tx_end == cdc_tx_start) { // anything in the fifo?
00280        return; // nope
00281     }
00282     #ifdef CDC_DEBUG
00283         serial_putc('<');
00284     #endif
00285     start_crit_sec();
00286     
00287     count = 0;
00288     while ((cdc_tx_end != cdc_tx_start) && (count < buffer_size)) {
00289         
00290         cdc_tx_next = cdc_tx_start + 1; // get next position
00291         if (cdc_tx_next == USB_CDC_TX_BUFFER_SIZE) {    // if we're at the end of the buffer
00292             cdc_tx_next = 0;    // wrap to the beginning
00293         }
00294         buffer[count] = cdc_tx_buffer[cdc_tx_start];    // transmit the character
00295         #ifdef CDC_DEBUG
00296             serial_putc(buffer[count]);
00297         #endif  
00298         count++;
00299         cdc_tx_start = cdc_tx_next; // move start position of fifo
00300     } 
00301     if (count > 0) {
00302         bd->count = count;
00303         bd->addr = (uns16)buffer;
00304 
00305         toggle_bit(bd->stat, DTS);
00306         clear_bit(bd->stat, KEN);   // clear the keep bit
00307         clear_bit(bd->stat, INCDIS);    // clear the increment disable
00308         set_bit  (bd->stat, DTSEN);
00309         clear_bit(bd->stat, BSTALL);    // clear stall bit
00310         clear_bit(bd->stat, BC9);
00311         clear_bit(bd->stat, BC8);
00312 
00313         set_bit  (bd->stat, UOWN);  // SIE owns the buffer
00314     }
00315     end_crit_sec();
00316     #ifdef CDC_DEBUG
00317         serial_putc('>');
00318         serial_print_str("send=");
00319         serial_print_int(count);
00320         serial_putc(' ');
00321     #endif  
00322 
00323 }
00324 
00325 uns8 usb_cdc_rx_avail() { return cdc_rx_start != cdc_rx_end; }
00326 uns8 usb_cdc_tx_empty() { return cdc_tx_start == cdc_tx_end; }
00327 
00328 void usb_cdc_print_str(char *str) {
00329 
00330 uns8 count;
00331 buffer_descriptor *bd;
00332 
00333     for(count = 0 ; str[count] != 0; count++)
00334     {
00335         usb_cdc_putc(str[count]);
00336     }
00337     
00338     // This will give possibly quicker send:
00339     
00340     //bd = ep_in_bd_location[CDC_DATA_ENDPOINT];
00341     //if (!test_bit(bd->stat, UOWN)) {
00342     //  usb_cdc_handle_tx();
00343     //} 
00344     // otherwise we wait for the SOF interrupt to send
00345 }    
00346 
00347 void usb_SOF_callback(uns16 frame) {
00348     // we don't care about the frame number, we only care if there's something to send...
00349     usb_cdc_handle_tx();    // start transmission
00350 }
00351 
00352 void usb_cdc_setup() {
00353     line_coding *my_lc;
00354     my_lc = (line_coding*) &class_data;
00355     my_lc->dte_rate.as_long = 0x80250000;
00356     my_lc->stop_bits = 0;   // = 1 stop bit
00357     my_lc->data_bits = 8;   // = 8 data bits
00358     my_lc->parity = 0;      // = No parity
00359 }   
00360 
00361 void usb_cdc_print_int(uns16 i) {
00362 
00363 char buffer[6]; // up to 5 characters plus \0
00364 uns8 count = 5;
00365     buffer[5] = '\0';
00366     do {
00367         count--;
00368         buffer[count] = '0' + i % 10;
00369         i = i / 10;
00370     } while (i > 0);    
00371     while (buffer[count]) {
00372         usb_cdc_putc(buffer[count]);
00373         count++;
00374     }  
00375     //serial_print_str(&buffer[count]); //  print it out 
00376 //  for(count = 0 ; str[count] != 0; count++)
00377  //   {
00378  //   }
00379 
00380 }   

Generated on Sun Jan 25 18:45:29 2009 for Pic Pack by  doxygen 1.5.7.1