setfilepointer - FileFile asíncrono funciona solo en la depuración paso a paso
createfile delphi (2)
La biblioteca de terceros funciona según lo diseñado, pero la está utilizando incorrectamente.
La biblioteca libserialport
es multiplataforma y proporciona semántica de E / S sin bloqueo en lugar de semántica de E / S asincrónica. Estos son bastante diferentes. Cuando emite una escritura sin bloqueo, solo se escribirá la parte de la información que se puede enviar inmediatamente.
Eso significa que es su responsabilidad realizar un seguimiento de cuántos bytes (si los hay) se han escrito y emitir otra operación de escritura en un punto posterior en el tiempo para el resto de los datos. En la actualidad, su código ignora por completo el valor de retorno que le indica cuántos bytes se escribieron, por lo que no es nada sorprendente que algunos o todos los datos puedan perderse.
En este caso particular, está llamando a sp_drain
inmediatamente después de la operación de escritura. Bloquea hasta que se complete la escritura, haciendo que el uso de una escritura sin bloqueo sea inútil. Entonces, la forma más fácil de resolver su problema será llamar a sp_blocking_write
lugar de a sp_nonblocking_write
.
Es probable que esta biblioteca proporcione semántica de E / S de bloqueo porque este es el enfoque con el que los programadores de Linux están más familiarizados. También puede ser algo más fácil emular la semántica de bloqueo en Windows que emular la semántica de E / S asincrónica en Linux.
Si está más cómodo con E / S asincrónicas, y si su código no pretende ser multiplataforma, es posible que prefiera buscar otra biblioteca de terceros diseñada específicamente para Windows.
Estoy usando una biblioteca de C que usa operaciones de E / S sincrónicas y asíncronas.
Cuando trato de usar la operación de escritura asincrónica, la función que llama a WriteFile no asegurará que se escriban todos los bytes a menos que realice una depuración paso a paso (y esto es muy extraño). aquí está la función de escritura:
SP_API enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_t count)
{
TRACE("%p, %p, %d", port, buf, count);
CHECK_OPEN_PORT();
if (!buf)
RETURN_ERROR(SP_ERR_ARG, "Null buffer");
DEBUG_FMT("Writing up to %d bytes to port %s", count, port->name);
if (count == 0)
RETURN_INT(0);
#ifdef _WIN32
DWORD written = 0;
BYTE *ptr = (BYTE *) buf;
/* Check whether previous write is complete. */
if (port->writing) {
if (HasOverlappedIoCompleted(&port->write_ovl)) {
DEBUG("Previous write completed");
port->writing = 0;
} else {
DEBUG("Previous write not complete");
/* Can''t take a new write until the previous one finishes. */
RETURN_INT(0);
}
}
/* Set timeout. */
if (port->timeouts.WriteTotalTimeoutConstant != 0) {
port->timeouts.WriteTotalTimeoutConstant = 0;
if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
RETURN_FAIL("SetCommTimeouts() failed");
}
/*
* Keep writing data until the OS has to actually start an async IO
* for it. At that point we know the buffer is full.
*/
while (written < count) {
/* Copy first byte of user buffer. */
port->pending_byte = *ptr++;
/* Start asynchronous write. */
if (WriteFile(port->hdl, &port->pending_byte, 1, NULL, &port->write_ovl) == 0) {
if (GetLastError() == ERROR_IO_PENDING) {
if (HasOverlappedIoCompleted(&port->write_ovl)) {
DEBUG("Asynchronous write completed immediately");
port->writing = 0;
written++;
continue;
} else {
DEBUG("Asynchronous write running");
port->writing = 1;
RETURN_INT(++written);
}
} else {
/* Actual failure of some kind. */
RETURN_FAIL("WriteFile() failed");
}
} else {
DEBUG("Single byte written immediately");
written++;
}
}
DEBUG("All bytes written immediately");
RETURN_INT(written);
#else
/* Returns the number of bytes written, or -1 upon failure. */
ssize_t written = write(port->fd, buf, count);
if (written < 0)
RETURN_FAIL("write() failed");
else
RETURN_INT(written);
#endif
}
No pude encontrar ninguna explicación a este extraño comportamiento. Esto realmente me está volviendo loco.
Cual podría ser el problema ?
Gracias por su comprensión.
EDIT1: Me estoy ejecutando en Windows XP SP3 32 Bit Guest en Linux Mint 18 64 Bit en VMware Workstation 12 y usando Mingw-W64 i686-7.1.0-release-win32-sjlj-rt_v5-rev0 y Code :: Blocks IDE
EDIT2: uso una biblioteca de puerto serie C llamada libserialport https://sigrok.org/wiki/Libserialport , sus API Docs: http://sigrok.org/api/libserialport/unstable/index.html
mi porción de código es:
printf("Opening port ''%s'' /n", desired_port);
error = sp_get_port_by_name(desired_port,&port);
if (error == SP_OK)
{
error = sp_open(port,SP_MODE_READ_WRITE);
if (error == SP_OK)
{
sp_flush(port, SP_BUF_BOTH);
char tosend[] = "AT+CIMI/r";
error = sp_flush(port, SP_BUF_BOTH);
error = sp_nonblocking_write(port, tosend, strlen(tosend));
sp_drain(port);
wxSleep(3);
char byte_buff[128];
memset(byte_buff, 0, sizeof(byte_buff));
int byte_num = 0;
byte_num = sp_blocking_read(port,byte_buff, 127, 100);
error = sp_input_waiting(port);
wxMessageBox(byte_buff);
sp_close(port);
}
else
{
printf("Error opening serial device/n");
}
}
else
{
printf("Error finding serial device/n");
}
Resulta que tengo que ensuciarme los dedos y volver a implementar sp_nonblocking_write para solucionar el problema. aquí está mi re-implementación, que funciona como un encanto:
SP_API enum sp_return sp_nonblocking_write(struct sp_port *port,
const void *buf, size_t count)
{
TRACE("%p, %p, %d", port, buf, count);
CHECK_OPEN_PORT();
if (!buf)
RETURN_ERROR(SP_ERR_ARG, "Null buffer");
DEBUG_FMT("Writing up to %d bytes to port %s", count, port->name);
if (count == 0)
RETURN_INT(0);
#ifdef _WIN32
DWORD bytes_written = 0;
/* Check whether previous write is complete. */
if (port->writing) {
if (GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, FALSE) == 0) {
if (GetLastError() == ERROR_IO_INCOMPLETE) {
DEBUG("Previous write incomplete");
/* Can''t take a new write until the previous one finishes. */
RETURN_INT(0);
} else
RETURN_FAIL("GetOverlappedResult() failed");
} else {
DEBUG("Previous write completed");
port->writing = 0;
}
}
/* Set timeout. */
if (port->timeouts.WriteTotalTimeoutConstant != 0) {
port->timeouts.WriteTotalTimeoutConstant = 0;
if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
RETURN_FAIL("SetCommTimeouts() failed");
}
/* Do write. */
if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl) == 0)
if (GetLastError() != ERROR_IO_PENDING)
RETURN_FAIL("WriteFile() failed");
/* Get number of bytes written. */
if (GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, FALSE) == 0) {
if (GetLastError() == ERROR_IO_INCOMPLETE) {
DEBUG("Asynchronous write running");
port->writing = 1;
}
else /* GetLastError() != ERROR_IO_INCOMPLETE */
RETURN_FAIL("GetOverlappedResult() failed");
}
else {
DEBUG("Asynchronous write completed immediately");
port->writing = 0;
}
DEBUG_FMT("%d bytes written immediately", bytes_written);
RETURN_INT(bytes_written);
#else
ssize_t bytes_written;
/* Returns the number of bytes written, or -1 upon failure. */
if ((bytes_written = write(port->fd, buf, count)) < 0) {
if (errno == EAGAIN)
/* No bytes written. */
bytes_written = 0;
else
/* This is an actual failure. */
RETURN_FAIL("write() failed");
}
RETURN_INT(bytes_written);
#endif
}
Gracias a todos por su apoyo y contribución.