CONTINUA AKI:
*/
/******************************************************************************
/* usb_attached()
/*
/* Summary: Returns TRUE if the device is attached to a USB cable
/*
/*****************************************************************************/
#if USB_CON_SENSE_PIN
#define usb_attached() input(USB_CON_SENSE_PIN)
#else
#define usb_attached() TRUE
#endif
/******************************************************************************
/* usb_detach()
/*
/* Summary: Remove the D+/D- lines from the USB bus. Basically, disable USB.
/*
/*****************************************************************************/
void usb_detach(void) { //done
UCON=0; //disable USB hardware
UIE=0; //disable USB interrupts
usb_state=USB_STATE_DETACHED;
usb_token_reset(); //clear the chapter9 stack
__usb_kbhit_status=0;
}
/******************************************************************************
/* usb_attach()
/*
/* Summary: Attach the D+/D- lines to the USB bus. Enable the USB peripheral
/*
/*****************************************************************************/
void usb_attach(void) {
UCON = 0;
UIE = 0; // Mask all USB interrupts
UCON_USBEN = 1; // Enable module & attach to bus
usb_state = USB_STATE_ATTACHED; // Defined in usbmmap.c & .h
}
/*****************************************************************************
/* usb_init_cs()
/*
/* Summary: Resets and initalizes USB peripheral. Does not attach the peripheral
/* to the USB bus. See usb_attach() and usb_task() on how to
/* attach to the USB bus.
/*
/* You must call this before any other USB code.
/*
/* NOTE: an alternative function, usb_init(), is provided that
/* initializes the USB and then connects.
/*
/*****************************************************************************/
void usb_init_cs(void) {
UCFG = __UCFG_VAL_;
USTAT=0;
usb_state = USB_STATE_DETACHED;
usb_token_reset(); //clear the chapter9 stack
__usb_kbhit_status=0;
}
/*****************************************************************************
/* usb_task()
/*
/* Summary: Keeps an eye on the connection sense pin to determine if we are
/* attached to a USB cable or not. If we are attached to a USB cable,
/* initialize the USB peripheral if needed. If we are disconnected
/* from the USB cable, disable the USB peripheral.
/*
/* NOTE: If you are not using a connection sense pin, will automatically
/* enable the USB peripheral.
/*
/* NOTE: this enables interrupts once the USB peripheral is ready
/*
/*****************************************************************************/
void usb_task(void) {
if (usb_attached()) {
if (UCON_USBEN==0) {
debug_usb(debug_putc, "
USB TASK: ATTACH"
;
usb_attach();
}
}
else {
if (UCON_USBEN==1) {
debug_usb(debug_putc, "
USB TASK: DE-ATTACH"
;
usb_detach();
}
}
if ((usb_state == USB_STATE_ATTACHED)&&(!UCON_SE0)) {
UIR=0;
UIE=0;
enable_interrupts(INT_USB);
enable_interrupts(GLOBAL);
UIE=__USB_UIF_IDLE | __USB_UIF_RESET; //enable IDLE and RESET USB interrupt
usb_state=USB_STATE_POWERED;
debug_usb(debug_putc, "
USB TASK: POWERED"
;
}
}
/*****************************************************************************
/* usb_init()
/*
/* Summary: Resets and initalizes USB hardware. You must call this first before
/* using code. Will attach the USB periperhal to the USB bus.
/*
/* NOTE: If you are using a connection sense pin, this will wait in
/* an infinite loop until the device is connected to a USB cable.
/*
/* NOTE: If you are not using a connection sense pin, this will wait
/* in an infinte loop until the SE0 condition clears, which usually
/* doesn"t take long
/*
/* NOTE: this enables interrupts.
/*
/*****************************************************************************/
void usb_init(void) {
usb_init_cs();
do {
usb_task();
} while (usb_state != USB_STATE_POWERED);
}
/****************************************************************************
/* usb_kbhit(endpoint)
/*
/* Input: endpoint - endpoint to check
/*
/* Output: TRUE if there is new data in RX buffer, FALSE if there is not.
/*
/* Summary: Similar to kbhit(), sees if there is new data in the RX USB buffers.
/*
/*****************************************************************************/
#define usb_kbhit(x) bit_test(__usb_kbhit_status,x)
/**************************************************************
/* usb_flush_packet_0()
/*
/* Input: len - size of packet to send
/*
/* Summary: Marks usb_ep0_tx_buffer[] as ready to transmit after
/* processing the SETUP token interrupt.
/*
/***************************************************************/
void usb_flush_packet_0(int len) {
__setup_0_tx_size=len;
}
/**************************************************************
/* usb_flush_in()
/*
/* Input: endpoint - which endpoint to mark for transfer
/* len - length of data that is being tramsferred
/* tgl - Data toggle synchronization for this packet
/*
/* Output: TRUE if success, FALSE if error (we don"t control the endpoint)
/*
/* Summary: Marks the endpoint ready for transmission. You must
/* have already loaded the endpoint buffer with data.
/* (IN is PIC -> PC)
/***************************************************************/
int1 usb_flush_in(int8 endpoint, int8 len, USB_DTS_BIT tgl) {
int8 i;
debug_usb(debug_putc,"
PUT %X %U %U",endpoint, tgl, len);
if (!bit_test(EP_BDxST_I(endpoint),7)) {
EP_BDxCNT_I(endpoint)=len;
debug_display_ram(len, EP_BDxADR_I(endpoint));
#if USB_IGNORE_TX_DTS
i=0x80;
#else
i=EP_BDxST_I(endpoint);
if (tgl == USB_DTS_TOGGLE) {
if (bit_test(i,6))
tgl=USB_DTS_DATA0; //was DATA1, goto DATA0
else
tgl=USB_DTS_DATA1; //was DATA0, goto DATA1
}
if (tgl == USB_DTS_DATA1) {
i=0xC8; //DATA1, UOWN
}
else if (tgl == USB_DTS_DATA0) {
i=0x88; //DATA0, UOWN
}
#endif
debug_usb(debug_putc," %X",i,len);
EP_BDxST_I(endpoint)=i;//save changes
return(1);
}
else {
debug_usb(debug_putc,"
PUT ERR"
;
}
return(0);
}
/*******************************************************************************
/* usb_put_packet(endpoint,*ptr,len,toggle)
/*
/* Input: endpoint - endpoint to send packet to
/* ptr - points to data to send
/* len - amount of data to send
/* toggle - whether to send data with a DATA0 pid, a DATA1 pid, or toggle from the last DATAx pid.
/*
/* Output: TRUE if data was sent correctly, FALSE if it was not. The only reason it will
/* return FALSE is if because the TX buffer is still full from the last time you
/* tried to send a packet.
/*
/* Summary: Sends one packet out the EP to the host. Notice that there is a difference
/* between a packet and a message. If you wanted to send a 512 byte message you
/* would accomplish this by sending 8 64-byte packets, followed by a 0 length packet.
/* If the last (or only packet) being sent is less than the max packet size defined
/* in your descriptor then you do not need to send a 0 length packet to identify
/* an end of message.
/*
/* usb_puts() (provided in usb.c) will send a multi-packet message correctly.
/*
/********************************************************************************/
int1 usb_put_packet(int8 endpoint, int8 * ptr, int8 len, USB_DTS_BIT tgl) { //done
int8 i;
int8 * buff_add;
if (!bit_test(EP_BDxST_I(endpoint),7)) {
buff_add=EP_BDxADR_I(endpoint);
for (i=0;i<len;i++) {
*buff_add=*ptr;
buff_add++;
ptr++;
}
return(usb_flush_in(endpoint, len, tgl));
}
else {
debug_usb(debug_putc,"
PUT ERR"
;
}
return(0);
}
/// END User Functions
/// BEGIN Hardware layer functions required by USB.C
/**************************************************************
/* usb_flush_out()
/*
/* Input: endpoint - which endpoint to mark for transfer
/* tgl - Data toggle synchronization to expect in the next packet
/*
/* Output: NONE
/*
/* Summary: Clears the previously received packet, and then marks this
/* endpoint"s receive buffer as ready for more data.
/* (OUT is PC -> PIC)
/***************************************************************/
void usb_flush_out(int8 endpoint, USB_DTS_BIT tgl) {
int8 i;
#if USB_IGNORE_TX_DTS
if (tgl == USB_DTS_STALL) {
debug_usb(debug_putc, "*");
i=0x84;
EP_BDxST_I(endpoint)=0x84;
return;
}
else
i=0x80;
#else
i=EP_BDxST_O(endpoint);
if (tgl == USB_DTS_TOGGLE) {
if (bit_test(i,6))
tgl=USB_DTS_DATA0; //was DATA1, goto DATA0
else
tgl=USB_DTS_DATA1; //was DATA0, goto DATA1
}
if (tgl == USB_DTS_STALL) {
i=0x84;
EP_BDxST_I(endpoint)=0x84; //stall both in and out endpoints
}
else if (tgl == USB_DTS_IGNORE) {
i=0x80;
}
else if (tgl == USB_DTS_DATA1) {
i=0xC8; //DATA1, UOWN
}
else if (tgl == USB_DTS_DATA0) {
i=0x88; //DATA0, UOWN
}
#endif
bit_clear(__usb_kbhit_status,endpoint);
EP_BDxCNT_O(endpoint)=usb_ep_rx_size[endpoint];
EP_BDxST_O(endpoint)=i;
}
/*******************************************************************************
/* usb_get_packet(endpoint, *ptr, max)
/*
/* Input: endpoint - endpoint to get data from
/* ptr - where to save data to local PIC RAM
/* max - max amount of data to receive from buffer
/*
/* Output: the amount of data taken from the buffer.
/*
/* NOTE - IF THERE IS NO PACKET TO GET YOU WILL GET INVALID RESULTS!
/* VERIFY WITH USB_KBHIT() BEFORE YOU CALL USB_GET_PACKET()!
/*
/* Summary: Gets a packet of data from the USB buffer and puts into local PIC RAM.
/* Until you call usb_get_packet() the data will sit in the endpoint
/* buffer and the PC will get NAKs when it tries to write more data
/* to the endpoint.
/*
/********************************************************************************/
int8 usb_get_packet(int8 endpoint, int8 * ptr, int8 max) {
int8 * al;
int8 i;
al=EP_BDxADR_O(endpoint);
i=EP_BDxCNT_O(endpoint);
if (i<max) {max=i;}
i=0;
while (i<max) {
*ptr=*al;
ptr++;
al++;
i++;
}
usb_flush_out(endpoint, USB_DTS_TOGGLE);
return(max);
}
/*******************************************************************************
/* usb_stall_ep(endpoint,direction)
/*
/* Input: endpoint - endpoint to stall.
/* top most bit indicates direction (set is IN, clear is OUT)
/*
/* Summary: Stalls specified endpoint. If endpoint is stalled it will NAK any tokens
/* destined to that endpoint.
/*
/*
/* NOTE: WE ASSUME ENDPOINT IS VALID. USB.C SHOULD CHECK THIS
/*
/********************************************************************************/
void usb_stall_ep(int8 endpoint) { //done
int1 direction;
direction=bit_test(endpoint,7);
endpoint&=0x7F;
if (direction) {
EP_BDxST_I(endpoint)=0x84;
}
else {
EP_BDxST_O(endpoint)=0x84;
}
}
/*******************************************************************************
/* usb_unstall_ep(endpoint, direction)
/*
/* Input: endpoint - endpoint to un-stall.
/* top most bit indicates direction (set is IN, clear is OUT)
/*
/* Summary: Un-stalls endpoint.
/*
/* NOTE: WE ASSUME ENDPOINT IS VALID. USB.C SHOULD CHECK THIS
/********************************************************************************/
void usb_unstall_ep(int8 endpoint) { //done
int1 direction;
direction=bit_test(endpoint,7);
endpoint&=0x7F;
if (direction) {
#if USB_IGNORE_RX_DTS
EP_BDxST_I(endpoint)=0x80;
#else
EP_BDxST_I(endpoint)=0x88;
#endif
}
else {
EP_BDxST_O(endpoint)=0x00;
}
}
/*******************************************************************************
/* usb_endpoint_stalled(endpoint)
/*
/* Input: endpoint - endpoint to check
/* top most bit indicates direction (set is IN, clear is OUT)
/*
/* Output: returns a TRUE if endpoint is stalled, FALSE if it is not.
/*
/* Summary: Looks to see if an endpoint is stalled, or not. Does not look to
/* see if endpoint has been issued a STALL, just whether or not it is
/* configured to STALL on the next packet. See Set_Feature and Clear_Feature
/* Chapter 9 requests.
/*
/* NOTE: WE ASSUME ENDPOINT IS VALID. USB.C SHOULD CHECK THIS
/********************************************************************************/
int1 usb_endpoint_stalled(int8 endpoint) { //done
int1 direction;
int8 st;
direction=bit_test(endpoint,7);
endpoint&=0x7F;
if (direction) {
st=EP_BDxST_I(endpoint);
}
else {
st=EP_BDxST_O(endpoint);
}
return(bit_test(st,7) && bit_test(st,2));
}
/*******************************************************************************
/* usb_set_address(address)
/*
/* Input: address - address the host specified that we use
/*
/* Summary: Configures the USB Peripheral for the specified device address. The host
/* will now talk to use with the following address.
/*
/********************************************************************************/
void usb_set_address(int8 address) { //done
UADDR=address;
if (address) {
usb_state=USB_STATE_ADDRESS;
}
else {
usb_state=USB_STATE_POWERED;
}
}
/*******************************************************************************
/* usb_set_configured(config)
/*
/* Input: config - Configuration to use. 0 to uncofigure device.
/*
/* Summary: Configures or unconfigures device. If configuring device it will
/* enable all the endpoints the user specified for this configuration.
/* If un-configuring device it will disable all endpoints.
/*
/* NOTE: CCS only provides code to handle 1 configuration.
/*
/********************************************************************************/
void usb_set_configured(int config) {
int8 en;
int16 addy;
int8 new_uep;
if (config==0) {
//if config=0 then set addressed state
usb_state=USB_STATE_ADDRESS;
usb_disable_endpoints();
}
else {
usb_state=USB_STATE_CONFIGURED; //else set configed state
addy=(int16)0x500+(2*USB_MAX_EP0_PACKET_LENGTH);
for (en=1;en<16;en++) {
new_uep=0;
if (usb_ep_rx_type[en]!=USB_ENABLE_DISABLED) {
new_uep=0x04;
EP_BDxCNT_O(en)=usb_ep_rx_size[en];
EP_BDxADR_O(en)=addy;
addy+=usb_ep_rx_size[en];
#if USB_IGNORE_RX_DTS
EP_BDxST_O(en)=0x80;
#else
EP_BDxST_O(en)=0x88;
#endif
}
if (usb_ep_tx_type[en]!=USB_ENABLE_DISABLED) {
new_uep|=0x02;
EP_BDxADR_I(en)=addy;
addy+=usb_ep_tx_size[en];
EP_BDxST_I(en)=0x40;
}
if (new_uep==0x06) {new_uep=0x0E;}
if (usb_ep_tx_type[en]!=USB_ENABLE_ISOCHRONOUS) {
new_uep|=0x10;
}
UEP(en)=new_uep;
}
}
}
/// END Hardware layer functions required by USB.C
/// BEGIN USB Interrupt Service Routine
/*******************************************************************************
/* usb_handle_interrupt()
/*
/* Summary: Checks the interrupt, and acts upon event. Processing finished
/* tokens is the majority of this code, and is handled by usb.c
/*
/* NOTE: If you wish to change to a polling method (and not an interrupt method),
/* then you must call this function rapidly. If there is more than 10ms
/* latency the PC may think the USB device is stalled and disable it.
/* To switch to a polling method, remove the #int_usb line above this fuction.
/* Also, goto usb_init() and remove the code that enables the USB interrupt.
/********************************************************************************/
#int_usb
void usb_isr() {
if (usb_state==USB_STATE_DETACHED) return; //should never happen, though
if (UIR) {
debug_usb(debug_putc,"
[%X] ",UIR);
if (UIR_ACTV && UIE_ACTV) {usb_isr_activity();} //activity detected. (only enable after sleep)
if (UCON_SUSPND) return;
if (UIR_UERR && UIE_UERR) {usb_isr_uerr();} //error has been detected
if (UIR_URST && UIE_URST) {usb_isr_rst();} //usb reset has been detected
if (UIR_IDLE && UIE_IDLE) {usb_isr_uidle();} //idle time, we can go to sleep
if (UIR_SOF && UIE_SOF) {usb_isr_sof();}
if (UIR_STALL && UIE_STALL) {usb_isr_stall();} //a stall handshake was sent
if (UIR_TRN && UIE_TRN) {
usb_isr_tok_dne();
UIR_TRN=0; // clear the token done interrupt., 0x190.3
} //a token has been detected (majority of isrs)
}
}
//SOF interrupt not handled. user must add this depending on application
void usb_isr_sof(void) {
debug_usb(debug_putc,"
SOF"
;
UIR_SOF=0;
}
/*******************************************************************************
/* usb_disable_endpoints()
/*
/* Summary: Disables endpoints 1 thru 15
/*
/********************************************************************************/
void usb_disable_endpoints(void) {
int8 i;
for (i=1;i<16;i++) {
UEP(i)=ENDPT_DISABLED;
}
__usb_kbhit_status=0;
}
/*******************************************************************************
/* usb_isr_rst()
/*
/* Summary: The host (computer) sent us a RESET command. Reset USB device
/* and token handler code to initial state.
/*
/********************************************************************************/
void usb_isr_rst() {
debug_usb(debug_putc,"R"
;
UEIR=0;
UIR=0;
UEIE=0x9F;
UIE=STANDARD_INTS & ~__USB_UIF_ACTIVE;
UADDR=0;
usb_token_reset();
usb_disable_endpoints();
UEP(0)=ENDPT_CONTROL | 0x10;
while (UIR_TRN) {
UIR_TRN=0; //do this to clear out the ustat fifo
}
UCON_PKTDIS=0; //SIE token and packet processing enabled
usb_init_ep0_setup();
usb_state=USB_STATE_DEFAULT; //put usb mcu into default state
}
/*****************************************************************************
/* usb_init_ep0_setup()
/*
/* Summary: Configure EP0 to receive setup packets
/*
/*****************************************************************************/
void usb_init_ep0_setup(void) {
EP_BDxCNT_O(0) = USB_MAX_EP0_PACKET_LENGTH;
EP_BDxADR_O(0) = 0x500;
#if USB_IGNORE_RX_DTS
EP_BDxST_O(0) = 0x80; //give control to SIE, data toggle synch off
#else
EP_BDxST_O(0) = 0x88; //give control to SIE, DATA0, data toggle synch on
#endif
EP_BDxST_I(0) = 0;
EP_BDxADR_I(0) = 0x500 + (int16)USB_MAX_EP0_PACKET_LENGTH;
}
/*******************************************************************************
/* usb_isr_uerr()
/*
/* Summary: The USB peripheral had an error. If user specified, error counter
/* will incerement. If having problems check the status of these 8 bytes.
/*
/* NOTE: This code is not enabled by default.
/********************************************************************************/
void usb_isr_uerr() {
#if USB_USE_ERROR_COUNTER
int ints;
#endif
debug_usb(debug_putc,"E %X ",UEIR);
#if USB_USE_ERROR_COUNTER
ints=UEIR & UEIE; //mask off the flags with the ones that are enabled
if ( bit_test(ints,0) ) { //increment pid_error counter
debug_usb(debug_putc,"PID "
;
ERROR_COUNTER[0]++;
}
if ( bit_test(ints,1) ) { //increment crc5 error counter
debug_usbdebug_putc,"CRC5 "
;
ERROR_COUNTER[1]++;
}
if ( bit_test(ints,2) ) { //increment crc16 error counter
debug_usb(debug_putc,"CRC16 "
;
ERROR_COUNTER[2]++;
}
if ( bit_test(ints,3) ) { //increment dfn8 error counter
debug_usb(debug_putc,"DFN8 "
;
ERROR_COUNTER[3]++;
}
if ( bit_test(ints,4) ) { //increment bto error counter
debug_usb(debug_putc,"BTO "
;
ERROR_COUNTER[4]++;
}
if ( bit_test(ints,7) ) { //increment bts error counter
debug_usb(debug_putc,"BTS "
;
ERROR_COUNTER[5]++;
}
#endif
UEIR=0;
UIR_UERR=0;
}
/*******************************************************************************
/* usb_isr_uidle()
/*
/* Summary: USB peripheral detected IDLE. Put the USB peripheral to sleep.
/*
/********************************************************************************/
void usb_isr_uidle() {
debug_usb(debug_putc,"I"
;
UIE_ACTV=1; //enable activity interrupt flag. (we are now suspended until we get an activity interrupt. nice)
UIR_IDLE=0; //clear idle interrupt flag
UCON_SUSPND=1; //set suspend. we are now suspended
}
/*******************************************************************************
/* usb_isr_activity()
/*
/* Summary: USB peripheral detected activity on the USB device. Wake-up the USB
/* peripheral.
/*
/********************************************************************************/
void usb_isr_activity() {
debug_usb(debug_putc,"A"
;
UCON_SUSPND=0; //turn off low power suspending
UIE_ACTV=0; //clear activity interupt enabling
UIR_ACTV=0;
}
/*******************************************************************************
/* usb_isr_stall()
/*
/* Summary: Stall handshake detected.
/*
/********************************************************************************/
void usb_isr_stall(void) {
debug_usb(debug_putc,"S"
;
if (bit_test(UEP(0),0)) {
usb_init_ep0_setup();
bit_clear(UEP(0),0);
}
UIR_STALL=0;
}
/*******************************************************************************
/* usb_isr_tok_dne()
/*
/* Summary: A Token (IN/OUT/SETUP) has been received by the USB peripheral.
/* If a setup token on EP0 was received, run the chapter 9 code and
/* handle the request.
/* If an IN token on EP0 was received, continue transmitting any
/* unfinished requests that may take more than one packet to transmit
/* (if necessary).
/* If an OUT token on any other EP was received, mark that EP as ready
/* for a usb_get_packet().
/* Does not handle any IN or OUT tokens on EP0.
/*
/********************************************************************************/
void usb_isr_tok_dne() {
int8 en;
en=USTAT>>3;
debug_usb(debug_putc,"T "
;
debug_usb(debug_putc,"%X ", USTAT);
if (USTAT==USTAT_OUT_SETUP_E0) { //new out or setup token in the buffer
debug_usb(debug_putc,"%X ", EP_BDxST_O(0));
if ((EP_BDxST_O(0) & 0x3C)==USB_PIC_PID_SETUP) {
__setup_0_tx_size=0xFF;
debug_usb(debug_putc,"(%U) ", EP_BDxCNT_O(0));
EP_BDxST_I(0)=0; // return the in buffer to us (dequeue any pending requests)
debug_display_ram(EP_BDxCNT_O(0), usb_ep0_rx_buffer);
usb_isr_tok_setup_dne();
//clear the OUT buffer, make it ready for more packets - or stall
if (__setup_0_tx_size==0)
usb_flush_out(0,USB_DTS_DATA1);
else if (__setup_0_tx_size==0xFF)
usb_flush_out(0,USB_DTS_STALL);
else
usb_flush_out(0,USB_DTS_IGNORE);
//if a packet is going out, mark the IN buffer as ready
if (__setup_0_tx_size!=0xFF) {
debug_usb(debug_putc, "
PUT "
;
debug_display_ram(__setup_0_tx_size, usb_ep0_tx_buffer);
EP_BDxCNT_I(0)=__setup_0_tx_size;
EP_BDxST_I(0)=0xC8;
}
UCON_PKTDIS=0; // UCON,PKT_DIS ; Assuming there is nothing to dequeue, clear the packet disable bit
}
else if ((EP_BDxST_O(0) & 0x3C)==USB_PIC_PID_OUT) {
usb_isr_tok_out_dne(0);
}
}
else if (USTAT==USTAT_IN_E0) { //pic -> host transfer completed
__setup_0_tx_size=0xFF;
usb_isr_tok_in_dne(0);
if (__setup_0_tx_size!=0xFF) {
debug_usb(debug_putc, "
PUT "
;
debug_display_ram(__setup_0_tx_size, usb_ep0_tx_buffer);
EP_BDxCNT_I(0)=__setup_0_tx_size;
en=EP_BDxST_I(0);
if (bit_test(en,6)) {EP_BDxST_I(0)=0x88;}
else {EP_BDxST_I(0)=0xC8;}
}
else {
usb_init_ep0_setup();
}
}
else {
if (!bit_test(USTAT,2)) {
bit_set(__usb_kbhit_status,en);
}
}
}
/// END USB Interrupt Service Routine
#ENDIF
Con respecto a la funcion, tu lo que quieres(o eso entendido yo jeje) es comunicacion via usb PC con el pic...para ello deberas programar en tu programa en c(software a nivel de PC) una instruccion que al ser utilizada mande por el puerto usb una orden que el pic entienda a que la funcion a realizar es la multiplicacion.....vamos en resumen lo que tienes es programar y ordenar un medio externo(el pic en cuestion).......suerte!!!