Bueno, y yo segui buscando la forma de tratar la interrupcion...
Hasta ahora, solo e estado metido en la mpusbapi.dll (si, me baje el builder c++ 6 y todo). Y, por dar informacion, ahi usan las funciones del API de windows como ReadFile, WriteFile, CreateFile, etc. Tambien me encontre con formas para poder "esperar" a la interrupcion con funciones como WaitForSingleObject, WaitCommEvent,... que siendo este ultimo el q mas me llamo la atencion porq es muy utilizado para el puerto serie. Pero (si, siempre lo hay u.u'), no funciono.
Y esq, para los q conoscan sobre estas funciones API del Windows (yaq esto es un mundo nuevo para mi tb), usando el WaitCommEvent, siempre me debuelve FALSE (ese y toda su familia, ocea: SetCommMask (poniendo este antes, claro), ClearCommError, etc). Parece ser q al poner el handle, q me da CreateEvent(...) en MPUSBOpen(...), no lo reconociera o algo, porq GetLasError me devuelve ERROR_INVALID_FUNCTION enves de ERROR_INVALID_HANDLE, y nose que pensar
Quiza falte especificar algo en el CreateEvent(...) como un flag pero nose que pueda ser.
Con WaitForSingleObject pasa lo mismo; pense en poner en su 1er parametro el handle de MPUSBOpen pero no es algo q se pueda señalar (como lo hace con el evento de la estructura OverLapped).
Estuve echando una mirada tambien a MPUSBReadInt y pues hay algo en la funcion q usa: DeviceIoControl que pueda ser de ayuda. Pero (u.u') probando con al handle normal (yaq, en la decripcion del paramtro pEP del MPUSBOpen dice que hay q cambiar este valor por otro, indicando que quieres la pipe del tipo de transferencia: Interrupcion) no funciono. Y, ahi si, me devuelve GetLastError: ERROR_INVALID_HANDLE... Lo q me hace pensar esto, esq si la transferencia por Interrupcion tiene un handle especifico (porq el de Bulk fallo), donde indica una espera (ocea interrupcion) de byte almacenado en el buffer del Host (IOCTL_MCHPUSB_WAIT_INTERRUPT), pues entonces el Bulk tb lo tendra. Pero nose cual, ademas q su 2do parametro lo hace mas complicado aun, porq hace llamado a un tal CTL_CODE q crea una nueva funcion para el DeviceIoControl, o algo en un nivel mas bajo aun permitido legalmente en el windows. Esto si ya es demasiado.
Con todo esto y arta compilacion en el builder c++ 6... Encontre una forma, muy poco elegante (yaq todo lo q intentaba con esas funciones de comunicacion(WaitCommEVENT, ... de la libreria Kernel32.dll, me fallaba) de esperar, por asi decirlo (porq realmente espera) a la interrupcion esta. Y es combinado con el VC#. Ocea, a de crear un Thread (un subprocedimiento) que se encarge de una espera, fuera del programa principal, del buffer del Host. Asi, cuando aya llegado un dato, aparte de guardarlo (porq es muy poco elegante ya dije
) realizara algun otro evento enviando este byte a procesarlo o lo q sea.
Bueno, todo esto ultimo en codigos es asi:
VC#:
Primero, agregar a algunas funciones y varaibles el
static. Exactamente a: vid_pid_norm, out_pipe, in_pipe, myOutPipe, myInPipe, OpenPipes() y ClosePipes(). Esto devido a que el Thread, encargado de la tarea de esperar la interrupcion sin colgar nuestro programa principal, solo es creado con static y, por ende, solo puede llamar a funciones static (Open/ClosePipes()). Los demas string's y void's es porque estos son llamados desde un metodo, ahora, static, ocea OpenPipes y ClosePipes.
Luego, crear el Thread, fuera del main porque se necesitara luego para cerrarla desde otro evento (aunq hay errores con esto porq la DLL nunca se cierra). Pero, sera iniciada desde el Main, eso si.
Y, por ultimo, hacer lo que el Thread hara ni bien se inicia el programa. Este, llama a _MPUSBEsperarInterrupcionYLeer(...) (si, yo lo cree
), que, es muy similar a _MPUSBRead pero que en la funcion WaitFosSingleObject(...) se queda indefinidamente esperando hasta que el evento Overlaped sea señalado (ocea que haya un dato en el buffer). Asiq dejo tambien la DLL modificada con esa sola funcion que le puse para lograr tal cometido
Ahora, si. Todo esto en codigo es asi:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices; // Clase para importar DLL
using System.Threading; //Clase para subprocesos.
using PVOID = System.IntPtr;
using DWORD = System.UInt32;
namespace PicUSB
{
unsafe public class PicUSBAPI
{
#region Definición de los Strings: EndPoint y VID_PID
static string vid_pid_norm = "vid_04d8&pid_0011"; //AHORA ES STATIC.
static string out_pipe = "\\MCHP_EP1"; //AHORA ES STATIC.
static string in_pipe = "\\MCHP_EP1"; //AHORA ES STATIC.
#endregion
#region Funciones importadas de la DLL: mpusbapi.dll
.
.
.
[DllImport("mpusbapi.dll")]
private static extern void* _MPUSBOpen(DWORD instance, string pVID_PID, string pEP, DWORD dwDir, DWORD dwReserved);
//LA NUEVA n.n'
[DllImport("mpusbapi.dll")]
private static extern DWORD _MPUSBEsperarInterrupcionYLeer(void* handle, void* pData, DWORD dwLen, DWORD* pLength);
[DllImport("mpusbapi.dll")]
private static extern DWORD _MPUSBRead(void* handle, void* pData, DWORD dwLen, DWORD* pLength, DWORD dwMilliseconds);
.
.
.
#endregion
static void* myOutPipe; //AHORA ES STATIC.
static void* myInPipe; //AHORA ES STATIC.
//Creo un nuevo subproceso.
static ThreadStart clase = new ThreadStart(Work);
static Thread subprocedimiento = new Thread(clase);
static void Main()
{
//Inicializo el subprocedimiento.
subprocedimiento.Start();
Application.EnableVisualStyles();
Application.Run(new PicUSB());
}
public static void OpenPipes() //AHORA ES STATIC.
{
DWORD selection = 0;
myOutPipe = _MPUSBOpen(selection, vid_pid_norm, out_pipe, 0, 0);
myInPipe = _MPUSBOpen(selection, vid_pid_norm, in_pipe, 1, 0);
}
public static void ClosePipes() //AHORA ES STATIC.
{
_MPUSBClose(myOutPipe);
_MPUSBClose(myInPipe);
}
//Lo q quieras hacer cuando halla llegado el mensaje
public static void RutinaISR(byte DatoLeido)
{
MessageBox.Show("Aja! Encontre un dato x) \r\n" + DatoLeido.ToString());
}
//Codigo del Subproceso:
public static void Work()
{
while (true)
{
DWORD OcurrioInterrupcion = 0, LongitudDelDato;
byte* BuferDeDatos = stackalloc byte[1];
OpenPipes();
OcurrioInterrupcion = _MPUSBEsperarInterrupcionYLeer(myInPipe, (void*)BuferDeDatos, 1, &LongitudDelDato);
//Verifico si realmente es correcto si regreso con datos. Porq no regresara hasta que los tenga.
if ((OcurrioInterrupcion == 1) && (LongitudDelDato != 0))
{
RutinaISR(BuferDeDatos[0]); //Ejecuto lo q quiero hacer cuando es pase.
}
ClosePipes();
}
}
public void CerarHilo()
{
subprocedimiento.Abort();
}
}
}
Cuando llamo a _MPUSBEsperarInterrupcionYLeer(...) el subproceso se queda dormido, yaq ReadFile devuelve ERROR_IO_PENDING y la estructura overlapped es la encargada ahora de esperar que se lea algo en el buffer de entrada del host. Esto hace que no se gasten recursos del sistema.
Y la funcion CerrarHilo, es pues, para terminar con el Thread que se esta ejecutando en segundo plano. Esto simplemente llamadola desde el evento cuando se cierra la aplicacion (PicUSB_FormClosing):
(Esto va en el PicUSB.cs)
private void PicUSB_FormClosing(object sender, FormClosingEventArgs e)
{
usbapi.CerarHilo();
}
CCS C:
Aqui, nada. Solo envia un byte mientras el programa este abierto y lo detectara. Puede ser con un boton o lo q sea =)
Y nada mas. Decir que hay errores, y feos:
-Cuando cierro el programa, el subproceso (o mas bien dicho la DLL) sige ejecutandose en espera de algun dato, aunq le diga q cierre el hilo sige igual.
-No llega a encontrar una seria asincrona de datos enviados desde el PIC. Esto me molesta porque se supone que si se especifica en el ultimo argumento de ReadFile alguna estructura Overlapeed, es porque quieres una lectura asincrona y, como comentario, encima de esa funcion, el creador del codigo, pones: // attempt an asynchronous read operation.
-El nombre de ...YLeer(...) es por una limitacion, yaque no encontre la forma de ver antes cuantos bytes hay por lee. Pense hacerlo con ClearCommError(...) pero, como dije, esta familia de comunicacion me devuelve errores.
-Hay veces que se "autodesconecta" el dispositivo cuando intento capturar unos 10 datos enviados simultaneamente desde el pic a la PC.
-No se puede escribir, yaq el Thread esta manteniendo el handle de Read abierto y esperando
.
.
.
Si, lose. Es horrible. Pero como primer paso va bien, el programa detecta siquiera un dato y lo devuelve inmediatamente.
Por otro lado, me dijieron que para hacer tal "catch" a la interrupcion no es necesario de modifcar nada en el driver, yaq esta solo es para definir la comunicacion y esas cosas, ustedes saben... la pipe de control y eso. Y de que, es la DLL en si la q se dedica a ello.
Lo q podria ser de muy buena ayuda es, como ya dije, la funcion de la API: DeviceIoControl. Pero, hay algunos parametros que nose q especificar, yaq solo funciona para la pipe de interupcion y no reconoce el handle del bulk. Aunq encontre algunos ejemplos en la DDK que usa J1M para la instalacion de la clase y eso, donde hacen uso de esta funcion y trata, en esta misma, al usb y verificacion de alguna interrupcion (la testmcro.cpp, la funcion GetInterruptEvent (helper)). No la e visto mucho pero puede ser de gran ayuda. En si, creo q todo se torna a esta funcion pero nose que tanto se podria hacer.
Algo mas q me dijieron era usar unas funciones (o la verdad q nose q son) llamadas: BEGIN_MESSAGE_MAP y END_MESSAGE_MAP. Que sirven para rastrear algun evento en particular. Algo asi mas o menos estoy entendiendo, la verdad que es muy nuevo esto del API y sus funciones y todo, en si todo
Bueno, espero q alguien mas se suba al carro porque ando solo en esto y ya me esta dando miedo
Un saludo para todos.
PD: En el archivo adjunto esta la DLL modificada y los 2 archivos (el .cpp y el .h) que tuve q agregarle la nueva funcion, esa si, la fea
... por si se quiere recompilar o lo q sea.