pic_usb.h File Reference

Pic USB routines. More...

Include dependency graph for pic_usb.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  buffer_descriptor
struct  CDC_ACM_functional_descriptor
struct  CDC_call_mgt_functional_descriptor
struct  CDC_header_functional_descriptor
struct  CDC_union_functional_descriptor
struct  configuration_descriptor
struct  device_descriptor
struct  endpoint_descriptor
struct  hid_descriptor
struct  interface_descriptor
struct  setup_data_packet

Defines

#define BC8   0
#define BC9   1
#define BSTALL   2
#define DATA_STAGE_DIR   7
#define dt_CONFIGURATION   0x02
#define dt_CS_INTERFACE   0x24
#define dt_DEBUG   0x0a
#define dt_DEVICE   0x01
#define dt_DEVICE_QUALIFIER   0x06
#define dt_ENDPOINT   0x05
#define dt_HID   0x21
#define dt_HID_REPORT   0x22
#define dt_INTERFACE   0x04
#define dt_INTERFACE_ASSOC   0x0b
#define dt_INTERFACE_POWER   0x08
#define dt_OTG   0x09
#define dt_OTHER_SPEED_CONFIG   0x07
#define dt_STRING   0x03
#define DTS   6
#define DTSEN   3
#define INCDIS   4
#define KEN   5
#define PID0   2
#define PID1   3
#define PID2   4
#define PID3   5
#define pid_ACK   0b00000010
#define pid_DATA0   0b00000011
#define pid_DATA1   0b00001011
#define pid_DATA2   0b00000111
#define pid_IN   0b00001001
#define pid_MDATA   0b00001111
#define pid_NAK   0b00001010
#define pid_NYET   0b00000110
#define pid_OUT   0b00000001
#define pid_SETUP   0b00001101
#define pid_SOF   0b00000101
#define pid_STALL   0b00001110
#define req_Clear_Feature   0x01
#define req_Get_Configuration   0x08
#define req_Get_Descriptor   0x06
#define req_Get_Interface   0x0a
#define req_Get_Status   0x00
#define req_Set_Address   0x05
#define req_Set_Configuration   0x09
#define req_Set_Descriptor   0x07
#define req_Set_Feature   0x03
#define req_Set_Interface   0x0b
#define req_Synch_Frame   0x0c
#define REQUEST_TYPE0   5
#define REQUEST_TYPE1   6
#define UOWN   7
#define usb_send_status_ack()   usb_send_empty_data_pkt()

Enumerations

enum  control_mode_type {
  cm_IDLE, cm_CTRL_WRITE_DATA_STAGE, cm_CTRL_WRITE_DATA_STAGE_CLASS, cm_CTRL_READ_DATA_STAGE,
  cm_CTRL_READ_DATA_STAGE_CLASS, cm_CTRL_READ_AWAITING_STATUS, cm_CTRL_WRITE_SENDING_STATUS
}
enum  usb_state_type { st_POWERED, st_DEFAULT, st_ADDRESS, st_CONFIGURED }
enum  usb_status_type { us_IDLE, us_SET_ADDRESS }

Functions

void turn_usb_ints_on ()
 Turn on USB interrupts.
void usb_device_configured_callback ()
 Callback routine triggered when a successful intial USB negotiation has completed.
void usb_enable_module ()
 Enables the USB hardware and starts USB negotiations.
void usb_ep_data_in_callback (uns8 end_point, uns16 byte_count)
 Callback routine triggered when data has been sent to the host.
void usb_ep_data_out_callback (uns8 end_point, uns8 *buffer_location, uns16 byte_count)
 Callback routine triggered when data has been sent to the device.
void usb_get_descriptor_callback (uns8 descriptor_type, uns8 descriptor_num, uns8 **rtn_descriptor_ptr, uns16 *rtn_descriptor_size)
 Callback routine triggered when the descriptor is requested by the host.
usb_state_type usb_get_state ()
 Query the current state of the USB connection.
void usb_handle_class_ctrl_read_callback ()
 Callback routine for a class control read.
void usb_handle_class_ctrl_write_callback (uns8 *data, uns16 count)
 Callback routine for a class control write.
void usb_handle_class_request_callback (setup_data_packet sdp)
 Callback routine for a control transfer request that is placed on the class.
void usb_handle_isr ()
 Handle USB interrupts.
void usb_send_data (uns8 ep, uns8 *data, uns8 send_count, bit first)
 Send data over an endpoint pipe.
void usb_send_empty_data_pkt ()
 Send an empty data packet.
void usb_setup ()
 Setup USB hardware ready for use.
void usb_SOF_callback (uns16 frame)
 Callback routine triggered each time a start of frame (SOF) has been received.
void usb_stall_ep0 ()
 Send a stall on control transfer endpoint.

Variables

control_mode_type control_mode
uns8 usb_address
setup_data_packet usb_sdp
usb_state_type usb_state

Detailed Description

Put the following in your config.h

Use this define if you would like to get USB negotiation and data transfer information out the serial (UART) port. You'll also need to include pic_serial.c in your project. define USB_DEBUG

Use this define if you would like a high level (ie, lots) of USB debug information printed out the serial (UART) port. define USB_DEBUG_HIGH

Define the highest numbered endpoint you will use (in this case, we choose 3). define USB_HIGHEST_EP 3

Define either USB_SELF_POWERED or USB_BUS_POWERED define USB_SELF_POWERED define USB_BUS_POWERED

Define your endpoint buffers. These start at 0x500 for a 18f4550. You'll always need endpoint 0, which is the control transfer endpoint, and others as well depending on your use. You don't have to declare the endpoints you don't use, even if they're not sequential.

define USB_EP0_OUT_SIZE 8 define USB_EP0_OUT_ADDR 0x0200

define USB_EP0_IN_SIZE 8 define USB_EP0_IN_ADDR 0x0208

EP1 not used

define USB_EP2_IN_SIZE 8 define USB_EP2_IN_ADDR 0x0210

define USB_EP3_OUT_SIZE 8 define USB_EP3_OUT_ADDR 0x0218 define USB_EP3_IN_SIZE 8 define USB_EP3_IN_ADDR 0x0220

Use this define if you want to get a callback each SOF (Start Of Frame), generally every 1ms define USB_CALLBACK_ON_SOF if you define it, you'll need to include this routine in your code: void usb_SOF_callback(uns16 frame) { }

Use this define if you would like to know when your device has been configured and is ready for use define USB_CALLBACK_ON_DEVICE_CONFIGURED if you define it, you'll need to include this routine in your code: void usb_device_configured_callback() { }

Use this define if your device uses class control transfers, eg, CDC (virtual serial port) is one that does define USB_CALLBACK_ON_CTRL_CLASS if you define it, you'll need to include these routines in your code: void usb_handle_class_ctrl_read_callback(); void usb_handle_class_ctrl_write_callback(uns8 *data, uns16 count); void usb_handle_class_request_callback(setup_data_packet sdp);

Use this define if you would like to get notified when data has arrived or been succesfully sent define USB_EP_DATA_CALLBACK if you define it, you'll need to include these routines in your code: void usb_ep_data_out_callback(uns8 end_point, uns8 *buffer_location, uns16 byte_count); void usb_ep_data_in_callback(uns8 end_point, uns16 byte_count);

Put the following in your ISR

usb_handle_isr();

Put the following in your system setup routine

Setup USB usb_setup();

Turn on USB interrupts void turn_usb_ints_on();

Turn on global interrupts turn_global_ints_on();

When you're ready to start the USB subsystem and negotiate address, send descriptors etc, call

usb_enable_module();


Define Documentation

#define BC8   0
#define BC9   1
#define BSTALL   2
#define DATA_STAGE_DIR   7
#define dt_CONFIGURATION   0x02
#define dt_CS_INTERFACE   0x24
#define dt_DEBUG   0x0a
#define dt_DEVICE   0x01
#define dt_DEVICE_QUALIFIER   0x06
#define dt_ENDPOINT   0x05
#define dt_HID   0x21
#define dt_HID_REPORT   0x22
#define dt_INTERFACE   0x04
#define dt_INTERFACE_ASSOC   0x0b
#define dt_INTERFACE_POWER   0x08
#define dt_OTG   0x09
#define dt_OTHER_SPEED_CONFIG   0x07
#define dt_STRING   0x03
#define DTS   6
#define DTSEN   3
#define INCDIS   4
#define KEN   5
#define PID0   2
#define PID1   3
#define PID2   4
#define PID3   5
#define pid_ACK   0b00000010
#define pid_DATA0   0b00000011
#define pid_DATA1   0b00001011
#define pid_DATA2   0b00000111
#define pid_IN   0b00001001
#define pid_MDATA   0b00001111
#define pid_NAK   0b00001010
#define pid_NYET   0b00000110
#define pid_OUT   0b00000001
#define pid_SETUP   0b00001101
#define pid_SOF   0b00000101
#define pid_STALL   0b00001110
#define req_Clear_Feature   0x01
#define req_Get_Configuration   0x08
#define req_Get_Descriptor   0x06
#define req_Get_Interface   0x0a
#define req_Get_Status   0x00
#define req_Set_Address   0x05
#define req_Set_Configuration   0x09
#define req_Set_Descriptor   0x07
#define req_Set_Feature   0x03
#define req_Set_Interface   0x0b
#define req_Synch_Frame   0x0c
#define REQUEST_TYPE0   5
#define REQUEST_TYPE1   6
#define UOWN   7
 
#define usb_send_status_ack (  )     usb_send_empty_data_pkt()

Send a status acknowledge by sending an empty data packet


Enumeration Type Documentation

Describe the state of the control transfer

Enumerator:
cm_IDLE 

No control transfer taking place

cm_CTRL_WRITE_DATA_STAGE 

Device receiving data during the data stage

cm_CTRL_WRITE_DATA_STAGE_CLASS 

Device receiving data during the data stage destined for the class

cm_CTRL_READ_DATA_STAGE 

Device sending data during the data stage

cm_CTRL_READ_DATA_STAGE_CLASS 

Device class is sending data during the data stage

cm_CTRL_READ_AWAITING_STATUS 

Device is awaiting reception of status after sending data

cm_CTRL_WRITE_SENDING_STATUS 

Device is sending status after receiving data

Handle the different states that USB device can be in

Enumerator:
st_POWERED 

USB device is powered up, ready to start negotiating

st_DEFAULT 

USB device is now negotiating

st_ADDRESS 

USB device now has an address

st_CONFIGURED 

USB device is completely configured and ready to rock and roll

00141 {
00143     st_POWERED,
00145     st_DEFAULT, 
00147     st_ADDRESS, 
00149     st_CONFIGURED
00150 } usb_state_type;

Handle the special case of when we send a status ack and THEN change the address. So we need to know that the USB device is in that micro state (ie, received the new address but not yet sent the status

Enumerator:
us_IDLE 
us_SET_ADDRESS 

00232                               {
00233     us_IDLE,
00234     us_SET_ADDRESS
00235 } usb_status_type;


Function Documentation

void turn_usb_ints_on (  ) 

If you are using interrupt-driven code (generally the best way of doing things) you can turn on USB interrupts using turn_usb_ints_on(). Don't forget that you will also need to call turn_global_ints_on() as well. Typically this is called in your system setup routine.

00962                         {
00963     
00964     set_bit(uie,  STALLIE); // interrupt on stall
00965     set_bit(uie,  TRNIE);   //   on transaction complete
00966     set_bit(uie,  URSTIE);  //   on reset 
00967     set_bit(pie2, USBIE);   // general USB interrupts
00968     #ifdef USB_CALLBACK_ON_SOF 
00969         set_bit(uie, SOFIE);
00970     #endif  
00971 }

void usb_device_configured_callback (  ) 

Once descriptors have been received by the host and the host has selected a configuration to use, this routine is triggered. Typically this means that negotiations have completed successfully and an appropriate driver has been loaded.

In order for this callback to be triggered, you must define USB_CALLBACK_ON_DEVICE_CONFIGURED in your config.h

Here is the caller graph for this function:

void usb_enable_module (  ) 

After you've called usb_setup(), you can call usb_enable_module() whenever you're ready for USB negotiations to occur. Normally, this would need to occur relatively quickly after power-up if your PIC is powered by USB and it's purpose is to talk over USB. This is normally called from your main() routine once all other configuration is done.

Once the USB module has successfully negotiated a connection with the host, usb_device_configured_callback() will be called if you have requested this in your config.h file. This will indicate a successful connection. Because of the way USB works, there is no way to tell that it *hasn't* worked, except via a timer - if you haven't had a good connection in several seconds, you can assume it has failed (although this may just mean the user is hunting for a driver disk etc).

01033                          {
01034     uir = 0;
01035     set_bit(ucon, USBEN);   // enable USB serial interface engine (SIE)
01036     usb_state = st_DEFAULT;
01037 }

void usb_ep_data_in_callback ( uns8  end_point,
uns16  byte_count 
)

If you have called usb_send_data to transfer data to the host, this routine will be fired once this data has been transferred. You may send more data by using usb_send_data(). Since the current PicPack USB library supports only single buffering, transfer speed is limited by how quickly you can refill the buffer again. In the future, we may support double buffering (ping poing buffering) which will most likely improve transfer speeds (to be fair, transfer performance has not been a limiting factor in tests so far).

In order for this callback to be triggered, you must define USB_EP_DATA_CALLBACK in your config.h

Parameters:
end_point The endpoint on which the data was transferred
byte_count The number of bytes that were actually transferred

00328                                                                {
00329     #ifdef CDC_DEBUG
00330         serial_print_str(" EP data in: ");
00331         serial_print_int(byte_count);
00332         serial_print_str(" bytes ");
00333     #endif  
00334     // data has been sent, so do we need to send more?
00335     if (end_point == USB_CDC_DATA_ENDPOINT) {   // it's the data end point
00336         usb_cdc_handle_tx();
00337     }   
00338 }   

Here is the call graph for this function:

Here is the caller graph for this function:

void usb_ep_data_out_callback ( uns8  end_point,
uns8 *  buffer_location,
uns16  byte_count 
)

If data is sent to the device and the endpoint is not endpoint 0 (the control transfer endpoint) then this routine is called. Since the routine is passed the actual hardware buffer location, it is important to pull data out of the buffer as soon as possible in order to free up the buffer to receive more data. The buffer is re-primed only once this routine completes since PicPack only supports single-buffered mode. In the future, we may look at supporting double buffering (ping-pong buffering) in order to be able to receive more data even while this routine is being called.

In order for this callback to be triggered, you must define USB_EP_DATA_CALLBACK in your config.h

Parameters:
end_point The endpoint the data was sent do
buffer_lcoation The memory location of the USB buffer where the data was received into
byte_count The number of bytes received

00289                                                 {
00290     uns8 cdc_rx_next;
00291     #ifdef CDC_DEBUG
00292         serial_print_str(" EP data out: ");
00293         serial_print_int(byte_count);
00294         serial_print_str(" bytes ");
00295     #endif
00296     
00297     // We have some data!
00298 
00299     if (end_point == USB_CDC_DATA_ENDPOINT) {   // it's the data end point
00300         uns8 count;
00301         for (count = 0; count < byte_count; count++) {
00302             cdc_rx_next = cdc_rx_end + 1;   // get next buffer position 
00303             if (cdc_rx_next == USB_CDC_RX_BUFFER_SIZE) {    // if we're at the end
00304                 cdc_rx_next = 0;    // then wrap to the beginning
00305             }
00306             if (cdc_rx_next != cdc_rx_start) { // if space in the fifo
00307                 cdc_rx_buffer[cdc_rx_end] = buffer[count]; // put it in
00308                 cdc_rx_end = cdc_rx_next;  // and move pointer along
00309             } else {
00310                 // else... just ignore it, we've lost a byte, no room in the inn
00311                 break;
00312             }   
00313         }   
00314     } else {
00315         #ifdef CDC_DEBUG
00316             serial_print_str("data for ep ");
00317             serial_print_int(end_point);
00318         #endif  
00319     }
00320 
00321     #ifdef USB_CDC_USE_LEDS
00322         platform_leds_flash(3);
00323     #endif  
00324 }       

Here is the call graph for this function:

Here is the caller graph for this function:

void usb_get_descriptor_callback ( uns8  descriptor_type,
uns8  descriptor_num,
uns8 **  rtn_descriptor_ptr,
uns16 *  rtn_descriptor_size 
)

Once negotiations start, descriptors are quested by the host. The device must be able to respond to these requests. Typically, this routine consists of a switch statement depending on the descriptor_type parameter. The descriptor_num is used to specify which of the descriptor_type descriptors are required, since they may be several (for example, string descriptors).

Since descriptors are specific to a particular device (and project), this callback routine and the associated descriptors are put in a file called usb_config_xxxx.c and placed in the project workspace. This is because while the descriptors could have been provided as part of the PicPack library, you will almost always want to change them to suit your application, even if only for changing the vendor and device IDs and serial numbers.

At present, descriptors are required to be in RAM.

Since descriptor requests are an essential part of the USB protocol, this callback routine is mandatory.

Here is the caller graph for this function:

usb_state_type usb_get_state (  ) 

Returns the USB state, either powered, default, address or connect. This is updated as the negotiation progresses. It may be useful to query this if, after a suitable time-out, the connection has not been made.

01039                                {
01040     return usb_state;
01041 }

void usb_handle_class_ctrl_read_callback (  ) 

When a control transfer is taking place, this routine is called to indicate that a control read for the class has taken place. Since everything in USB land is all about what has just happened, this callback will occur after data has been transferred to the host. If you wish to send more data to the host, use usb_send_data(), or if your control read has sent all the data required, you will need to indicate that the state has changed by setting the control_mode variable to cm_CTRL_READ_AWAITING_STATUS. This will indicate to the stack that it should now wait for the status packet before completing the control transfer.

To allow this callback to trigger, ensure you define USB_CALLBACK_ON_CLASS_CTRL in your config.h

00273                                            {
00274         switch (usb_sdp.bRequest) {
00275             case req_GET_LINE_CODING:
00276                 // we know we've already sent everything, so now wait for status
00277                 control_mode = cm_CTRL_READ_AWAITING_STATUS;
00278                 break;
00279             default:
00280                 #ifdef CDC_DEBUG
00281                     serial_print_str(" cl read ?? ");
00282                     serial_print_int(usb_sdp.bRequest);
00283                 #endif  
00284         }       
00285             
00286 }

Here is the call graph for this function:

Here is the caller graph for this function:

void usb_handle_class_ctrl_write_callback ( uns8 *  data,
uns16  count 
)

When a control transfer is taking place, this routine is called to indicate that a control write for the class has taken place. Since everything in USB land is all about what has just happened, this callback will occur after data has been received by the device. If you expect more data from the host, it will arrive in due course since endpoint 0 will be primed for more data automatically. If you have received all the data from the host, you will need to set the control_mode state variable to cm_CTRL_WRITE_SENDING_STATUS and then actually send the status by calling usb_send_status_ack(). Once the status has actually been sent, the control_mode state will automatically change to cm_IDLE to indicate the transfer has completed.

To allow this callback to trigger, ensure you define USB_CALLBACK_ON_CLASS_CTRL in your config.h

00171                                                                    {
00172 
00173     switch (usb_sdp.bRequest) {
00174         case req_SET_LINE_CODING:
00175             // dump it into class_data
00176             memcpy(/* dst */ (void *)&class_data,/* src */ (void *)data, count);
00177             
00178             // Now we need to send an ACK status back
00179 
00180             usb_send_status_ack();
00181             control_mode = cm_CTRL_WRITE_SENDING_STATUS;            
00182 
00183             line_coding *my_lc;
00184             my_lc = (line_coding*) &class_data;
00185             #ifdef CDC_DEBUG
00186                 serial_print_int_hex(my_lc->dte_rate.as_byte_array[0]);
00187                 serial_print_int_hex(my_lc->dte_rate.as_byte_array[1]);
00188                 serial_print_int_hex(my_lc->dte_rate.as_byte_array[2]);
00189                 serial_print_int_hex(my_lc->dte_rate.as_byte_array[3]);
00190                 serial_print_str(" st=");
00191                 serial_print_int(my_lc->stop_bits);
00192                 serial_print_str(" p=");
00193                 serial_print_int(my_lc->parity);
00194                 serial_print_str(" db=");
00195                 serial_print_int(my_lc->data_bits);
00196                 serial_print_str(" bit rate: ");
00197             #endif
00198 
00199             dte_rate.as_byte_array[0] = my_lc->dte_rate.as_byte_array[3];
00200             dte_rate.as_byte_array[1] = my_lc->dte_rate.as_byte_array[2];
00201             dte_rate.as_byte_array[2] = my_lc->dte_rate.as_byte_array[1];
00202             dte_rate.as_byte_array[3] = my_lc->dte_rate.as_byte_array[0];
00203             parity = my_lc->parity;
00204             data_bits = my_lc->data_bits;
00205             
00206             switch (my_lc->dte_rate.as_long) {
00207                 case 2400: 
00208                     current_bit_rate = SPBRG_2400;
00209                     #ifdef CDC_DEBUG
00210                     serial_print_str("2400 ");
00211                     #endif
00212                     break;
00213                 case 4800: 
00214                     current_bit_rate = SPBRG_4800;
00215                     #ifdef CDC_DEBUG
00216                     serial_print_str("4800 ");
00217                     #endif
00218                     break;
00219                 case 9600: 
00220                     current_bit_rate = SPBRG_9600;
00221                     #ifdef CDC_DEBUG
00222                     serial_print_str("9600 ");
00223                     #endif
00224                     break;
00225                 case 19200: 
00226                     current_bit_rate = SPBRG_19200;
00227                     #ifdef CDC_DEBUG
00228                     serial_print_str("19200 ");
00229                     #endif
00230                     break;
00231                 case 38400: 
00232                     current_bit_rate = SPBRG_38400;
00233                     #ifdef CDC_DEBUG
00234                     serial_print_str("38400 ");
00235                     #endif
00236                     break;
00237                 case 115200: 
00238                     current_bit_rate = SPBRG_115200;
00239                     #ifdef CDC_DEBUG
00240                     serial_print_str("115200 ");
00241                     #endif
00242                     break;
00243                 default:    
00244                     #ifdef CDC_DEBUG
00245                         serial_print_str("Don't handle this bit rate");
00246                     #endif
00247             }
00248             
00249             clear_bit(rcsta, SPEN);
00250             clear_bit(txsta, TXEN);
00251             clear_bit(rcsta, CREN); 
00252             
00253   
00254             serial_setup(current_bit_rate);
00255             if (!serial_tx_empty()) {
00256                 #ifdef USB_CDC_USE_LEDS
00257                     platform_leds_flash(1);
00258                 #endif
00259                 set_bit(pie1, TXIE);
00260                 serial_tx_isr();
00261             }
00262             break;
00263         default:
00264             #ifdef CDC_DEBUG
00265                 serial_print_str(" ??cw req=");
00266                 serial_print_int_hex(usb_sdp.bRequest);
00267                 serial_putc(' ');
00268             #endif  
00269             break;
00270     }       
00271 }   

Here is the call graph for this function:

Here is the caller graph for this function:

void usb_handle_class_request_callback ( setup_data_packet  sdp  ) 

After receiving a setup packet, where the request is placed on the class, this routine is called. In usb_handle_class_request_callback, you can set up ready for the data stage of the control transfer. The direction of the data stage can be determined by examining test_bit(sdp.bRequest, DATA_STAGE_DIR) although generally it appears to be obvious from the request. The request is stored in sdp.bRequest.

Typically, if it is a control read transfer (that is, it is a request by the host for data), then you will need to move the control_mode state variable to cm_CTRL_READ_DATA_STAGE_CLASS and send data using usb_send_data(). If you only intend to send one packet, you can immediately move the control_mode state variable to cm_CTRL_READ_AWAITING_STATUS to indicate you are waiting for the status to arrive. You could wait for the usb_handle_class_ctrl_read callback and do it (move to cm_CTROL_READ_AWAITING_STATUS) but the PicPack USB stack can handle the control read event for you if you've already switched states.

If it is a control write transfer (that is, it is a request by the host to send data to the device), then you will need to move the control_mode state variable to cm_CTRL_WRITE_DATA_STAGE_CLASS. Then, the usb_handle_class_ctrl_write will be fired when data is received by the device in the data stage.

To allow this callback to trigger, ensure you define USB_CALLBACK_ON_CLASS_CTRL in your config.h

00115                                                               {
00116 
00117     switch (sdp.bRequest) {
00118         case req_SET_LINE_CODING:
00119             // we now expect the line coding to arrive in the data stage
00120             
00121             #ifdef CDC_DEBUG
00122                 serial_print_str("SET_LINE ");
00123             #endif
00124             control_mode = cm_CTRL_WRITE_DATA_STAGE_CLASS;
00125             break;
00126         case req_GET_LINE_CODING:
00127             #ifdef CDC_DEBUG
00128                 serial_print_str("GET_LINE ");
00129                 serial_print_str(" len=");
00130                 serial_print_int(sdp.wLength);
00131                 serial_putc(' ');
00132             #endif
00133             //control_mode = cm_CTRL_READ_DATA_STAGE_CLASS;
00134             control_mode = cm_CTRL_READ_DATA_STAGE_CLASS;
00135             //  need to prime ep0 IN with some funky data here
00136             line_coding my_line_coding;
00137             
00138             // We stored dte rate from ealier
00139             my_line_coding.dte_rate.as_byte_array[0] = dte_rate.as_byte_array[3];
00140             my_line_coding.dte_rate.as_byte_array[1] = dte_rate.as_byte_array[2];
00141             my_line_coding.dte_rate.as_byte_array[2] = dte_rate.as_byte_array[1];
00142             my_line_coding.dte_rate.as_byte_array[3] = dte_rate.as_byte_array[0];           
00143             my_line_coding.stop_bits = 0;   // 1 stop bit
00144             my_line_coding.data_bits = data_bits;   
00145             my_line_coding.parity = parity;     
00146             
00147             usb_send_data(/*ep*/ 0, /*data*/ (uns8 *)&my_line_coding, /*count*/ sizeof(my_line_coding), /*first*/ 1);
00148             // actually we know this will be the last packet, so go straight to waiting for the status ack
00149             control_mode = cm_CTRL_READ_AWAITING_STATUS;
00150             
00151             break;
00152         case req_SET_CONTROL_LINE_STATE:
00153             #ifdef CDC_DEBUG
00154                 serial_print_str("scls=");//dtr = bit 0, rts = bit 1
00155                 serial_print_int_hex(sdp.wValue);
00156             #endif
00157             // no data, so just ack the status
00158             // !!! set dtr, rts
00159             usb_send_status_ack();
00160             control_mode = cm_CTRL_WRITE_SENDING_STATUS;
00161             // Could put a callback here for your own code when DTR or RTS change
00162             break;
00163         default:
00164             #ifdef CDC_DEBUG
00165                 serial_print_str("??r=");
00166                 serial_print_int(sdp.bRequest);
00167             #endif  
00168     }
00169 }

Here is the call graph for this function:

Here is the caller graph for this function:

void usb_handle_isr (  ) 

usb_handle_isr() should be inserted in your interrupt service routine. Alternatively, if you have reason not to want to do interrupt-driven USB, for example, a bootloader, you can poll this routine.

Make sure you call turn_usb_ints() and turn_global_ints_on() to ensure interrupts occur.

It will check for any of the USB interrupt flags and handle: USB transactions, USB reset, USB stall, USB Start Of Frame (including calling usb_SOF_callback() if configured in your config.h and most importantly USB transaction, which is where all the hard work is done.

00928                       {
00929     
00930     while (test_bit(pir2, USBIF)) {
00931         
00932         while (test_bit(uir, TRNIF)) {
00933             uns8 stat = ustat;
00934             clear_bit(uir, TRNIF);
00935             usb_handle_transaction(stat);
00936         }
00937         
00938         if (test_bit(uir, URSTIF)) {
00939             usb_handle_reset();
00940             clear_bit(uir, URSTIF);
00941         }   
00942         
00943         if (test_bit(uir, STALLIF)) {
00944             usb_handle_stall();
00945             clear_bit(uir, STALLIF);
00946         }
00947         if (test_bit(uir, SOFIF)) {
00948             #ifdef USB_CALLBACK_ON_SOF
00949                 #ifdef ufrm
00950                     usb_SOF_callback(ufrm);
00951                 #else
00952                     usb_SOF_callback(ufrmh << 8 | ufrml);
00953                 #endif  
00954                 clear_bit(uir, SOFIF);
00955             #endif
00956         }
00957         
00958         clear_bit(pir2, USBIF);
00959     }
00960 }

Here is the call graph for this function:

void usb_send_data ( uns8  ep,
uns8 *  data,
uns8  send_count,
bit  first 
)

Use this routine to send data across the USB pipe.

Parameters:
ep Endpoint that the data should be sent from
data pointer to the data
send_count the number of bytes to send
first True if this is the first in a series of sends. Generally, this can be set to False, since it will automatically be set to the right value on endpoint creation. However, in the case of control transfers, the data stage needs to have the first parameter set to True to ensure the DTS bit is set correctly.

00211                                                                     {
00212 uns8 count;
00213 buffer_descriptor *bd;
00214 uns8 *buffer;
00215 
00216     // this is going to be an IN transaction
00217     #ifdef USB_DEBUG
00218         serial_print_str("Send:EP");
00219         serial_print_int(ep);
00220         serial_putc(' ');
00221     #endif
00222     // need to grab buffer descriptor
00223     buffer = ep_in_buffer_location[ep];
00224     
00225     bd = ep_in_bd_location[ep];
00226     
00227     if (test_bit(bd->stat, UOWN)) {
00228     #ifdef USB_DEBUG
00229         serial_print_str(" !Adon't own it! ");
00230     #endif
00231         return;
00232     }
00233     
00234     count = 0;  
00235     while ((count < send_count)) {
00236         buffer[count] = data[count];
00237         count++;
00238     }           
00239     
00240 
00241     bd->count = count;
00242     bd->addr = (uns16)buffer;
00243     if (first) {
00244         clear_bit(bd->stat, DTS);   // So when it flips, will end up set 
00245     }
00246 
00247     toggle_bit(bd->stat, DTS);  // flip the DTS bit
00248     clear_bit(bd->stat, KEN);   // clear the keep bit
00249     clear_bit(bd->stat, INCDIS);    // clear the increment disable
00250     set_bit  (bd->stat, DTSEN);
00251     clear_bit(bd->stat, BSTALL);    // clear stall bit
00252     clear_bit(bd->stat, BC9);
00253     clear_bit(bd->stat, BC8);
00254 
00255     set_bit  (bd->stat, UOWN);  // SIE owns the buffer
00256 }   

Here is the call graph for this function:

Here is the caller graph for this function:

void usb_send_empty_data_pkt (  ) 

Use this routine to send an data across the USB pipe on endpoint 0. This is the equivalent of sending a status acknowledge.

00341                                {
00342     delivery_buffer_size = USB_EP0_IN_SIZE;
00343     delivery_bd = &bd0in;
00344     delivery_buffer = &buffer_0_in;
00345     delivery_bytes_sent = 0;
00346     delivery_bytes_to_send = 0;
00347     delivery_bytes_max_send = 0;
00348     delivery_ptr = (uns8 *) 0;
00349     clear_bit(bd0in.stat, DTS); // ready to get toggled 
00350     usb_send_data_chunk();
00351 }

Here is the call graph for this function:

void usb_setup (  ) 

usb_setup() configures the PIC USB hardware ready for use and prepares the internal data structures used to keep track of where the endpoint buffers are.

After calling usb_setup(), you are ready to call usb_enable_module() to actually start USB negotiations. Ensure that you have usb_handle_isr() in your interrupt service routine.

00973                  {
00974 
00975     usb_state = st_POWERED;
00976     
00977     // init hardware
00978     #ifdef UTRDIS
00979         clear_bit(ucfg, UTRDIS);    // enable internal tranceiver
00980     #endif
00981     set_bit  (ucfg, FSEN);  // clear for low speed, set for high speed
00982     set_bit  (ucfg, UPUEN); // enable on-chip pull-ups
00983 
00984     clear_bit(ucfg, PPB1);  // double buffering for EP0 OUT
00985     set_bit(ucfg, PPB0);    
00986 
00987     // if using ping pong buffers, need to do this:
00988     set_bit(ucon, PPBRST);  // reset ping pong buffers to even
00989     clear_bit(ucon, PPBRST);
00990 
00991     // init endpoint 0
00992         
00993     set_bit(uep0,   EPHSHK);    // EP0 handshaking on
00994     set_bit(uep0,   EPOUTEN);   // EP0 OUT enable 
00995     set_bit(uep0,   EPINEN);    // EP0 IN enable 
00996     clear_bit(uep0, EPCONDIS);  // EP0 control transfers on (and IN and OUT)
00997     
00998     // init interrupts
00999     // Config buffer descriptor table
01000 
01001     ep_out_bd_location[0] = &bd0out_e;
01002     #if USB_HIGHEST_EP >= 1
01003         ep_out_bd_location[1] = &bd1out;
01004     #endif
01005     #if USB_HIGHEST_EP >= 2
01006         ep_out_bd_location[2] = &bd2out;
01007     #endif
01008     #if USB_HIGHEST_EP >= 3
01009         ep_out_bd_location[3] = &bd3out;
01010     #endif
01011     #if USB_HIGHEST_EP >= 4
01012         ep_out_bd_location[4] = &bd4out;
01013     #endif
01014     
01015     ep_in_bd_location[0] = &bd0in;
01016     #if USB_HIGHEST_EP >= 1
01017         ep_in_bd_location[1] = &bd1in;
01018     #endif
01019     #if USB_HIGHEST_EP >= 2
01020         ep_in_bd_location[2] = &bd2in;
01021     #endif
01022     #if USB_HIGHEST_EP >= 3
01023         ep_in_bd_location[3] = &bd3in;
01024     #endif
01025     #if USB_HIGHEST_EP >= 4
01026         ep_in_bd_location[4] = &bd4in;
01027     #endif
01028 
01029 
01030 }

void usb_SOF_callback ( uns16  frame  ) 

Frames in USB occur each 1ms. A SOF packet is sent to each device at the start of each frame. This is a really neat way of getting a 1ms timer without any further work.

Parameters:
frame The frame number. Frames will wrap at 65535.

00483                                    {
00484     // we don't care about the frame number, we only care if there's something to send...
00485     usb_cdc_handle_tx();    // start transmission
00486 }

Here is the call graph for this function:

Here is the caller graph for this function:

void usb_stall_ep0 (  ) 

Use this routine to send a stall on the control transfer endpoint - usually used to indicate that the requested function is not available.

00203                      {
00204     set_bit(bd0in.stat, BSTALL);    // stall
00205     set_bit(bd0in.stat, UOWN);  // SIE owns the buffer
00206 //  set_bit(bd0out.stat, BSTALL);   // stall
00207 //  set_bit(bd0out.stat, UOWN); // SIE owns the buffer
00208     // ??set_bit(uep0,EPSTALL);
00209 }

Here is the caller graph for this function:


Variable Documentation

Store the control mode state

Store the usb address

Store the last setup data packet

Store the current USB device state


Generated on Fri Aug 19 09:09:11 2011 for Pic Pack Library by  doxygen 1.6.1