He estado yendo y viniendo entre el software de escritura para mi dispositivo y la aplicación de la PC tratando de hacer el protocolo correcto.
Tengo un pic18f4550 hablando sobre transferencias de interrupción. Debe enviar regularmente el estado de hasta 128 interruptores y también mantener el estado de las salidas de pines en función de los comandos de la PC (encendido / apagado, pulso, parpadeo, etc.).
Muchos de los ejemplos que encontré colocan transferencias IN dentro de un bloque que aseguran que una transferencia OUT siempre ocurra primero, así ejemplo de libUSBDotNet . Si no hay datos de salida listos, tampoco se realizará una solicitud de entrada. La plantilla del firmware se configuró inicialmente para manejar algo similar: siempre esperaría a que haya datos en el búfer de SALIDA, manejar eso, luego configurar el búfer de EN y enviar.
Cuando empecé, pensé que estaba sobrevalorado, porque mi dispositivo siempre iba a enviar el estado del conmutador si tenía la información y siempre estaba listo para los comandos, si hubiera alguno. Ajusté mi aplicación para enviar transferencias OUT y solicitudes de IN de forma independiente, y el firmware para manejar cada una de forma independiente. Pero a medida que mi código se vuelve más complejo, me pregunto si me estaba perdiendo algo.
Si me aseguré de que la estructura back-to-back OUT-IN, podría reservar uno o dos bytes OUT iniciales para incluir un comando para enviar la actualización del conmutador. También me permitiría dejar de solicitar datos fácilmente. Por supuesto, podría dejarlo como está y tener ciertos comandos reservados para establecer indicadores que habilitarían / deshabilitarían cierto comportamiento en el lado de la recopilación / transferencia de datos. Todavía no sé qué podría ser necesario al final de este proyecto, así que supongo que estoy buscando consejos para las mejores prácticas y los pros / contras de los enfoques. O tal vez estoy pensando demasiado en esto.
Gracias.
EDITAR: Además, el modo de búfer de ping-pong está desactivado en mi chip, por lo que hay buffers dedicados para el EP ENTRADO y el EP EXTERNO, si no me equivoco.
Código C # (también he portado esto en pyUSB). Compare con la muestra libUSBDotNet a la que he enlazado. Ejecutar cada 10 ms con un temporizador
private static void RunUSB(Object source, ElapsedEventArgs e)
{
ErrorCode ec = ErrorCode.None;
if (true) // for now always do this. In future only if we have commands to send.
{
int bytesWritten;
ec = writer.Write (commands, 0, 3, 2000, out bytesWritten);
if (ec != ErrorCode.None)
throw new Exception (UsbDevice.LastErrorString);
}
int bytesRead;
byte[] readBuffer = new byte[64];
ec = reader.Read(readBuffer, 2000, out bytesRead);
if (bytesRead != 0)
{
//handle input data
}
}
Código de firmware (utilizando mStack )
// initialize endpoint 1 IN buffer
unsigned char *INPacket = usb_get_in_buffer(1);
memset(INPacket, 0, EP_1_IN_LEN);
while (1) {
if (usb_is_configured())
{
// get data from PC
if (usb_out_endpoint_has_data(1))
{
unsigned char OUTLen;
const unsigned char *OUTPacket;
/* Data received from host */
OUTLen = usb_get_out_buffer(1, &OUTPacket);
// do stuff with OUT data
// rearm for out data
usb_arm_out_endpoint(1);
}
// send data to PC
if (!usb_in_endpoint_halted(1))
{
/* Wait for EP 1 IN to become free then send. This of
* course only works using interrupts. */
if(!usb_in_endpoint_busy(1))
{
// fill INPacket with data
usb_send_in_buffer(1, byteCount);
} else {
// send something
INPacket[0] = 0;
usb_send_in_buffer(1, 1);
}
}
}
}
Tenga en cuenta que el if (!usb_in_endpoint_halted(1))
estaba originalmente dentro del bloque if (usb_out_endpoint_has_data(1))