Why are seek events failing with my GStreamer app? - c

This is my seeking function:
gboolean seek(CustomData* data)
{
gint64 position;
GstFormat format = GST_FORMAT_TIME;
GstEvent *seek_event;
/* Obtain the current position, needed for the seek event */
if (!gst_element_query_position(data->pipeline, &format, &position))
{
g_printerr("Unable to retrieve current position.\n");
return FALSE;
}
/* Create the seek event */
if (data->rate > 0)
{
seek_event = gst_event_new_seek(data->rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
position, GST_SEEK_TYPE_NONE, 0);
}
else if (data->rate < 0)
{
seek_event = gst_event_new_seek(data->rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, 0,
GST_SEEK_TYPE_SET, position);
}
else
{
g_printerr("Rate is set to 0.\n");
return FALSE;
}
/* Check that seek_event was created */
if (seek_event == NULL) {
g_printerr("Could not create seek event.\n");
return FALSE;
}
/* Send the event */
if (!gst_element_send_event(data->autovideosink, seek_event))
{
g_printerr("Could not perform seek event.\n");
return FALSE;
}
g_print("Current rate: %gx\n", data->rate);
return TRUE;
}
But it fails at sending the seek event. This code is pertty much just slightly modified from the GStreamer tutorials, but I'm playing a .vob file and I have a custom pipeline instead of playbin2. I'm also using appsrc so I'm feeding the buffers from a file, but I don't imagine that would cause any problems with fast forwarding. However, I can't seek either forward or backward (setting the rate to 2x or .5x fails at the same spot).

I have same problem and I've found this on debug output:
0:00:49.048266933 4480 03B05000 DEBUG basesrc gstbasesrc.c:1972:gst_base_src_default_event:<app_source> is not seekable
0:00:49.048386221 4480 03B05000 DEBUG basesrc gstbasesrc.c:2000:gst_base_src_event:<app_source> subclass refused event
0:00:49.048515238 4480 03B05000 DEBUG GST_PADS gstpad.c:5050:gst_pad_send_event_unchecked:<app_source:src> sent event, ret error
It looks like appsrc element does not support seeking or event is sending upstream instead downstream.

Related

HAL_UART_Transmit_IT sending data twice

I am trying to establish UART communication between a PC and a STM32f407-DISC1 board using an arduino nano as a middle man.
The PC sends 'r' to the arduino to indicate a request.
The request is then communicated to the stm32 with a GPIO interrupt, which then should be transmitting 480 bytes of data using HAL_UART_Transmit_IT.
It however sends the data twice, with only a single request made.
The code on the STM32 is generated by STM32CubeMX
Data request made by the arduino
void loop() {
digitalWrite(4, 0); // Clear EXTI11 line.
if (mySerial.available() && received < 480) { // STM32 sending data and is not done.
buff[received] = mySerial.read(); // Append received data to the buffer.
received++;
}
if (received >= 480) { // If the buffer is full
received = 0; // transmit it to PC.
Serial.println(buff);
}
if (Serial.available()) {
if (Serial.read() == 'r') { // PC requests data from the STM32
digitalWrite(4, 1); // Triggers STM32 EXTI11 line.
while (Serial.available()) // Empty the buffer.
Serial.read();
}
}
}
data transmission on the STM32
void EXTI15_10_IRQHandler(void)
{
// Make sure that the interrupt is the good one.
if (HAL_GPIO_ReadPin(data_req_IRQ_GPIO_Port, data_req_IRQ_Pin)) {
if (is_sending_data == FALSE) // If no transmission is happening
should_send_data = TRUE; // raise transmission flag.
}
// IRQ handling stuff...
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef * huart) {
is_sending_data = FALSE; // Transmition is completed, unblock requests.
}
void main(void){
// Init and other stuff...
while (1) {
if (should_send_data == TRUE) { // If data was requested
HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_RESET);
HAL_UART_Transmit_IT(&huart3, matrice, 480); // Start transmission by interrupt.
is_sending_data = TRUE; // Block requests.
should_send_data = FALSE; // Clear flag.
}
// matrice acquisition stuff here
}
}
Alright so I found a solution, but it involved just rethinking my approach, so sorry for those looking for an answer to this problem.
I removed the arduino middle man by replacing it with a USB to RS232 converter and made UART reception work by interrupt. The STM detects the 'r' character which triggers the data communication.
Here is the interrupt part:
void USART3_IRQHandler(void)
{
if (USART3->SR & UART_IT_RXNE) { // If a byte is received
rxBuff[0] = (uint8_t) (huart3.Instance->DR & (uint8_t) 0xFF); // Read it.
__HAL_UART_FLUSH_DRREGISTER(&huart3); // Clear the buffer to avoid errors.
rx_new_char_flag = TRUE; // Raise the new_char flag.
return; // Stops the IRQHandler from disabling interrupts.
}
}
and the gestion of that in the main
while (1) {
if (rx_new_char_flag == TRUE) {
rx_new_char_flag = FALSE;
if (rxBuff[0] == 'r') {
rxBuff[0] = 0;
HAL_UART_Transmit_IT(&huart3, matrice, 480); // Start transmission by interrupt.
}
}
On the PC side, to optimize performance, instead of waiting for the full 480 bytes, I wait for only one character, if one is received I keep reading the serial port, as shown in the code bellow
int i = 0;
do {
ReadFile(m_hSerial, &temp_rx[i], 1, &dwBytesRead, NULL);
i++;
} while (dwBytesRead > 0 && i < 480);
for (int j = i; j < 480; j++) // If the transmission is incomplete, fill the buffer with 0s to avoid garbage data.
temp_rx[j] = 0;
if(i>=480) // If all the bytes has been received, copy the data in the working buffer.
std::copy(std::begin(temp_rx), std::end(temp_rx), std::begin(m_touch_state));
This works well with pretty decent performance, so that may be a permanent solution to my problem.

Simple sdl game very slow while cpu at 1.2%

I wrote a simple 2d tile based game and ran it on 2 computers. On comp1 it's very slow, on comp2 it's lightening fast.
Comp1's cpu is a little slower, but it can play other sdl games (even inside emulaters) and simple 3d games, fast enough.
So I ran the game on both computers using only cpu rendering: both ran at the same speed.
Then I switched to gpu rendering and the 2nd computer went really fast (200+fps) but the first stayed at the same pace, around 20fps.
So I assumed either the hw acceleration is not working on comp1 or the cpu is clogged with my calculations.
I logged all the error handling and can confirm both computers support the hw acceleration and the texture sizes (i know this for a fact because the cpu bound version of the game has no flip and so the character always faces the same way ;)
So then it has to be a slow cpu on the first computer, right? But when I check the cpu stats the game only takes 1,2% cpu, and overall load is around 2% cpu
So the cpu is sitting mostly idle while my game crawls along :(
The game is a few 1000 lines of code now, so here are some of the statements that I think pertain to this problem:
Main game loop:
while (!quit)
{
GameEngine_Tick(gameType->fps, false, 0);
if (SDL_PollEvent(&event) != 0))
{
int windowID = event.window.windowID;
if (event.window.event == SDL_WINDOWEVENT_CLOSE &&
event.window.windowID == screens[0].windowID) quit = true;
switch (event.type)
{
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_LEFT) { Key_Left(); }
if (event.key.keysym.sym == SDLK_RIGHT) { Key_Right();}
if (event.key.keysym.sym == SDLK_UP) { Key_Up(); }
if (event.key.keysym.sym == SDLK_DOWN) { Key_Down(); }
break; // end key_down.
} // switch event type
}
GameEngine_Render();
}
Frame rate limiting in GameEngine_Tick:
void GameEngine_Tick(int fps, bool bIsRegTestStep, Uint8 TDir)
{
unsigned int frametime = 1000 / fps;
unsigned int currentTime;
const Uint8* keystates = SDL_GetKeyboardState(NULL); // do not free.
SDL_PumpEvents(); // upd keystates to get keyboard inputs.
// Get KB input - todo: later GetInputFromSelectedInputDevice (checks kb/xbox etc)
if (keystates[SDL_SCANCODE_LEFT]) GameLeft();
else if (keystates[SDL_SCANCODE_RIGHT]) GameRight();
Sprites_Tick();
// set framerate by waiting if needed.
currentTime = SDL_GetTicks();
if (currentTime - prevTime < (frametime))
{
//Sleep the remaining frame time
if (fps > 0) SDL_Delay((frametime)-(currentTime - prevTime)); /* fps-1 == MAX == no delay*/
}
prevTime = currentTime;
}
create renderer:
ren = nullptr;
if (bForceCPURender == false) ren = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);// | SDL_RENDERER_PRESENTVSYNC);
if (nullptr == ren)
{
if (bForceCPURender == false)
{
Log("Info: SDL_CreateRenderer with SDL_RENDERER_ACCELERATED failed. Trying default.");
}
bForceCPURender = true;
ren = SDL_CreateRenderer(window, -1, 0);
if (nullptr == ren)
{
Log("Info: SDL_CreateRenderer with default also failed.");
SDLDestroy();
return -1;
}
else Logs("Info: success using default renderer.");
}
else Logs("Info: success, using SDL_CreateRenderer with SDL_RENDERER_ACCELERATED.");
Creating textures or surfaces:
spriteMapTexture = SDL_CreateTexture(ren, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
x_pixPerCharInStageMap * roomWidthInChars * gameRoomMatrix_w,
y_pixPerCharInStageMap * roomHeightInChars * gameRoomMatrix_h);
// If GPU cannot handle size of stage map: try to do CPU preRendering. (gpu is texture, cpu is surface).
if (NULL == spriteMapTexture || bForceCPUStageRenderAnyway == true)
{
spriteMapSurface = GameEngine_CreateRGBSurface(x_pixPerCharInStageMap * roomWidthInChars * gameRoomMatrix_w, y_pixPerCharInStageMap * roomHeightInChars * gameRoomMatrix_h);
}
while (!quit)
{
GameEngine_Tick(gameType->fps, false, 0);
if (SDL_PollEvent(&event) != 0))
^^ wat
{
// process event
}
GameEngine_Render();
}
Right now you're only processing a single event each frame. Used to be SDL could only buffer 128 events before dropping them, nowadays I think they're up to 64k. So if, for example, you have a high-report-rate gaming mouse (500-1000 Hz sampling) your event queue will get backed up far faster than a regular mouse (125 Hz). Same for any other event type SDL can generate; some systems will have different event generation rates than others.
You want to process every event in the queue before rendering a frame:
while (!quit)
{
GameEngine_Tick(gameType->fps, false, 0);
// NOTE: if -> while
while( SDL_PollEvent(&event) )
{
// process event
}
GameEngine_Render();
}

XCB – Not receiving motion notify events on all windows

I am trying to be notified about any pointer motion. Since I don't want to run as the window manager, I need to set XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION on all windows which I do both on startup and when I get a create notify event.
This seems to work fine in general and I receive motion notify events on all windows. However, somehow, this isn't true for Google Chrome windows. I checked the event mask by explicitly querying it afterwards and it is correctly set. I also don't see anything unusual in the propagation mask.
What could cause Google Chrome to not report motion notify events? AFAIK, the X protocol doesn't allow that except for active pointer grabs which Chrome surely doesn't have.
Here is how I register myself on all existing windows. I call register_events on the root window and whenever I receive a create notify event as well:
static void register_events(xcb_window_t window) {
xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(connection,
window, XCB_CW_EVENT_MASK, (uint32_t[]) { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_LEAVE_WINDOW });
xcb_generic_error_t *error = xcb_request_check(connection, cookie);
if (error != NULL) {
xcb_disconnect(connection);
errx(EXIT_FAILURE, "could not subscribe to events on a window, bailing out");
}
}
static void register_existing_windows(void) {
xcb_query_tree_reply_t *reply;
if ((reply = xcb_query_tree_reply(connection, xcb_query_tree(connection, root), 0)) == NULL) {
return;
}
int len = xcb_query_tree_children_length(reply);
xcb_window_t *children = xcb_query_tree_children(reply);
for (int i = 0; i < len; i++) {
register_events(children[i]);
}
xcb_flush(connection);
free(reply);
}
The Chrome windows appear to be comprised of quite the tree of nested child windows. It appears you'll need to walk the tree of windows and monitor them all. This code picks up pointer motion events across the entirety of my Chrome windows:
#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
#include <X11/Xlib.h>
static void register_events(xcb_connection_t *conn,
xcb_window_t window) {
xcb_void_cookie_t cookie =
xcb_change_window_attributes_checked(conn,
window, XCB_CW_EVENT_MASK,
(uint32_t[]) {
XCB_EVENT_MASK_POINTER_MOTION });
xcb_generic_error_t *error = xcb_request_check(conn, cookie);
if (error != NULL) {
xcb_disconnect(conn);
exit(-1);
}
}
static void register_existing_windows(xcb_connection_t *conn,
xcb_window_t root) {
int i, len;
xcb_window_t *children;
xcb_query_tree_reply_t *reply;
if ((reply = xcb_query_tree_reply(conn,
xcb_query_tree(conn, root), 0))
== NULL)
{
return;
}
len = xcb_query_tree_children_length(reply);
children = xcb_query_tree_children(reply);
for (i = 0; i < len; i++) {
register_events(conn, children[i]);
register_existing_windows(conn, children[i]);
}
xcb_flush(conn);
}
void main(void) {
int i=0;
/* Open the connection to the X server */
xcb_connection_t *conn = xcb_connect (NULL, NULL);
/* Get the first screen */
xcb_screen_t *screen = xcb_setup_roots_iterator (xcb_get_setup (conn)).data;
register_existing_windows(conn, screen->root);
while(1) {
xcb_generic_event_t *evt;
evt = xcb_wait_for_event(conn);
printf("%i\n", i++);
}
}
(That's just intended as proof of concept, and not very nice.)
While #Jay Kominek's answer was helpful and valid, I've come to realize now that using the Xinput extension provides a much better approach as it won't interfere with applications whatsoever.
Simply selecting on the entire tree causes all kinds of issues, e.g., hover doesn't work in Chrome anymore.
xcb provides xcb_grab_pointer to capture pointer event without registe on specific window.
#include <stdlib.h>
#include <stdio.h>
#include <xcb/xcb.h>
void
print_modifiers (uint32_t mask)
{
const char **mod, *mods[] = {
"Shift", "Lock", "Ctrl", "Alt",
"Mod2", "Mod3", "Mod4", "Mod5",
"Button1", "Button2", "Button3", "Button4", "Button5"
};
printf ("Modifier mask: ");
for (mod = mods ; mask; mask >>= 1, mod++)
if (mask & 1)
printf(*mod);
putchar ('\n');
}
int
main ()
{
xcb_connection_t *c;
xcb_screen_t *screen;
xcb_window_t win;
xcb_generic_event_t *e;
uint32_t mask = 0;
/* Open the connection to the X server */
c = xcb_connect (NULL, NULL);
/* Get the first screen */
screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
mask = XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION;
xcb_grab_pointer(c, false, screen->root, mask, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_CURRENT_TIME);
xcb_flush (c);
while ((e = xcb_wait_for_event (c))) {
switch (e->response_type & ~0x80) {
case XCB_BUTTON_PRESS: {
xcb_button_press_event_t *ev = (xcb_button_press_event_t *)e;
print_modifiers(ev->state);
switch (ev->detail) {
case 4:
printf ("Wheel Button up in window %ld, at coordinates (%d,%d)\n",
ev->event, ev->event_x, ev->event_y);
break;
case 5:
printf ("Wheel Button down in window %ld, at coordinates (%d,%d)\n",
ev->event, ev->event_x, ev->event_y);
break;
default:
printf ("Button %d pressed in window %ld, at coordinates (%d,%d)\n",
ev->detail, ev->event, ev->event_x, ev->event_y);
}
break;
}
case XCB_BUTTON_RELEASE: {
xcb_button_release_event_t *ev = (xcb_button_release_event_t *)e;
print_modifiers(ev->state);
printf ("Button %d released in window %ld, at coordinates (%d,%d)\n",
ev->detail, ev->event, ev->event_x, ev->event_y);
break;
}
case XCB_MOTION_NOTIFY: {
xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *)e;
printf ("Mouse moved in window %ld, at coordinates (%d,%d)\n",
ev->event, ev->event_x, ev->event_y);
break;
}
default:
/* Unknown event type, ignore it */
printf("Unknown event: %d\n", e->response_type);
break;
}
/* Free the Generic Event */
free (e);
}
return 0;
}

X: trigger events at fixed intervals

What's the best way of waiting a finite a mount of time for an expose event on X, then waking up and doing a redraw, even if not expose event has been received? The purpose is to have an opengl animation running at sometimes where at others I simply want to redraw if needed. Here is my code as I have it now, check below for pseudo-code of what I'm looking for:
do {
XNextEvent(dpy, &event);
switch(event.type) {
...
case Expose:
need_redraw = True;
break;
}
} while(XPending(dpy)); /* loop to compress events */
if ( need_redraw )
{
// do redraw
}
And this is a pseudo-example of what I would like:
bool animation_enabled = true;
XPostTimeoutEventEvery( 0.3 ); // <-- X will send a "Timeout"
// event each 0.3 seconds.
do {
XNextEvent(dpy, &event);
switch(event.type) {
...
case Expose:
// Redraw if it is required
need_redraw = True;
break;
// -- here --
case Timeout:
// Otherwise, after 0.3 seconds, redraw anyway if
// the animation is running
if ( animation_enabled )
{
need_redraw = True;
}
break;
}
} while(XPending(dpy)); /* loop to compress events */
if ( need_redraw )
{
// do redraw
// potentially change "animation_enabled" value
}
Just use a regular system timer; if a desired event doesn't arrive in time, just do whatever you want to do.
X is not an application framework, it's a display protocol. Timers are outside (of that) scope of X11.
Check here and the link provided in that answer.
XLib does not offer a "timed out" version of XNextEvent.
But, a timed out version can be easily implemented.
You will need a function
that checks if a file has been updated
within a given timeout,
you can implement it using select:
#include <sys/select.h>
static int wait_fd(int fd, double seconds)
{
struct timeval tv;
fd_set in_fds;
FD_ZERO(&in_fds);
FD_SET(fd, &in_fds);
tv.tv_sec = trunc(seconds);
tv.tv_usec = (seconds - trunc(seconds))*1000000;
return select(fd+1, &in_fds, 0, 0, &tv);
}
Then, you can use wait_fd
in the file descriptor returned by
ConnectionNumber(display)
to wait for an event
within a given time limit:
int XNextEventTimeout(Display *display, XEvent *event, double seconds)
{
if (XPending(display) || wait_fd(ConnectionNumber(display),seconds)) {
XNextEvent(display, event);
return 0;
} else {
return 1;
}
}
In your main loop,
you can use the XNextEventTimeout function
to wait for events within a given timeout.
If the timeout expires, you can simulate the desired event,
in you case an Expose event:
for (;;) {
if (XNextEventTimeout(dpy, &event, 1.)) {
/* Handle timeout "event"
* one option is to simulate an Expose event */
e.type = Expose;
e.xexpose.count = 0;
}
switch (event.type) {
case Expose:
/* Handle expose event */
break;
/* ... */
/* Handle other events */
}
}
A simpler solution is to use the non-blocking Xlib equivalents to XNextEvent. Here's what I use to check for X events each time through the frame loop:
mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask;
while (XCheckWindowEvent(xDisplay, xWin, mask, &evt) ||
XCheckTypedWindowEvent(xDisplay, xWin, ClientMessage, &evt)) {
/* Handle event */
}
Hope this helps. The full code is in my demo OpenGL/GLX program
http://cs.anu.edu.au/~Hugh.Fisher/3dteach/glxcube.tar

How to detect if a Bluetooth HID device was disconnected?

I'm using CreateFile to open an asynchronous file handle to a Bluetooth HID device on the system. The device will then start streaming data, and I use ReadFile to read data from the device. The problem is, that if the Bluetooth connection is dropped, ReadFile just keeps giving ERROR_IO_PENDING instead of reporting a failure.
I cannot rely on timeouts, because the device doesn't send any data if there is nothing to report. I do not want it to time out if the connection is still alive, but there is simply no data for a while.
Still, the Bluetooth manager (both the Windows one and the Toshiba one) do immediately notice that the connection was lost. So this information is somewhere inside the system; it's just not getting through to ReadFile.
I have available:
the file handle (HANDLE value) to the device,
the path that was used to open that handle (but I don't want to attempt to open it another time, creating a new connection...)
an OVERLAPPED struct used for asynchronous ReadFile.
I am not sure if this issue is Bluetooth-specific, HID-specific, or occurs with devices in general. Is there any way that I can either
get ReadFile to return an error when the connection was dropped, or
detect quickly upon a timeout from ReadFile whether the connection is still alive (it needs to be fast because ReadFile is called at least 100 times per second), or
solve this problem in another way I haven't thought of?
You are going to have to have some sort of polling to check. Unless there is a event you can attach (I'm not familiar with the driver), the simplest way is to poll your COM port by doing a ReadFile and check is dwBytesRead > 0 when you send a command. There should be some status command you can send or you can check if you can write to the port and copy those bytes written to dwBytesWrite using WriteFile, for instance, and check if that is equal to the length of bytes you are sending. For instance:
WriteFile(bcPort, cmd, len, &dwBytesWrite, NULL);
if (len == dwBytesWrite) {
// Good! Return true
} else
// Bad! Return false
}
This is how I do it in my application. Below may seem like a bunch of boilerplate code, but I think it will help you get to the root of your problem. I first open the Comm Port in the beginning.
I have an array of COM ports that I maintain and check to see if they are open before writing to a particular COM port. For instance, they are opened in the beginning.
int j;
DWORD dwBytesRead;
if (systemDetect == SYS_DEMO)
return;
if (port <= 0 || port >= MAX_PORT)
return;
if (hComm[port]) {
ShowPortMessage(true, 20, port, "Serial port already open:");
return;
}
wsprintf(buff, "COM%d", port);
hComm[port] = CreateFile(buff,
GENERIC_READ | GENERIC_WRITE,
0, //Set of bit flags that specifies how the object can be shared
0, //Security Attributes
OPEN_EXISTING,
0, //Specifies the file attributes and flags for the file
0); //access to a template file
if (hComm[port] != INVALID_HANDLE_VALUE) {
if (GetCommState(hComm[port], &dcbCommPort)) {
if(baudrate == 9600) {
dcbCommPort.BaudRate = CBR_9600;//current baud rate
} else {
if(baudrate == 115200) {
dcbCommPort.BaudRate = CBR_115200;
}
}
dcbCommPort.fBinary = 1; //binary mode, no EOF check
dcbCommPort.fParity = 0; //enable parity checking
dcbCommPort.fOutxCtsFlow = 0; //CTS output flow control
dcbCommPort.fOutxDsrFlow = 0; //DSR output flow control
// dcbCommPort.fDtrControl = 1; //DTR flow control type
dcbCommPort.fDtrControl = 0; //DTR flow control type
dcbCommPort.fDsrSensitivity = 0;//DSR sensitivity
dcbCommPort.fTXContinueOnXoff = 0; //XOFF continues Tx
dcbCommPort.fOutX = 0; //XON/XOFF out flow control
dcbCommPort.fInX = 0; //XON/XOFF in flow control
dcbCommPort.fErrorChar = 0; //enable error replacement
dcbCommPort.fNull = 0; //enable null stripping
//dcbCommPort.fRtsControl = 1; //RTS flow control
dcbCommPort.fRtsControl = 0; //RTS flow control
dcbCommPort.fAbortOnError = 0; //abort reads/writes on error
dcbCommPort.fDummy2 = 0; //reserved
dcbCommPort.XonLim = 2048; //transmit XON threshold
dcbCommPort.XoffLim = 512; //transmit XOFF threshold
dcbCommPort.ByteSize = 8; //number of bits/byte, 4-8
dcbCommPort.Parity = 0; //0-4=no,odd,even,mark,space
dcbCommPort.StopBits = 0; //0,1,2 = 1, 1.5, 2
dcbCommPort.XonChar = 0x11; //Tx and Rx XON character
dcbCommPort.XoffChar = 0x13; //Tx and Rx XOFF character
dcbCommPort.ErrorChar = 0; //error replacement character
dcbCommPort.EofChar = 0; //end of input character
dcbCommPort.EvtChar = 0; //received event character
if (!SetCommState(hComm[port], &dcbCommPort)) {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 21, port, "Cannot set serial port state information:");
if (!CloseHandle(hComm[port])) {
//ShowPortMessage(true, 22, port, "Cannot close serial port:");
}
hComm[port] = NULL;
return;
}
} else {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 29, port, "Cannot get serial port state information:");
if (!CloseHandle(hComm[port])) {
//ShowPortMessage(true, 22, port, "Cannot close serial port:");
}
hComm[port] = NULL;
return;
}
if (!SetupComm(hComm[port], 1024*4, 1024*2)) {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 23, port, "Cannot set serial port I/O buffer size:");
if (!CloseHandle(hComm[port])) {
//ShowPortMessage(true, 22, port, "Cannot close serial port:");
}
hComm[port] = NULL;
return;
}
if (GetCommTimeouts(hComm[port], &ctmoOld)) {
memmove(&ctmoNew, &ctmoOld, sizeof(ctmoNew));
//default setting
ctmoNew.ReadTotalTimeoutConstant = 100;
ctmoNew.ReadTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(hComm[port], &ctmoNew)) {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 24, port, "Cannot set serial port timeout information:");
if (!CloseHandle(hComm[port])) {
//ShowPortMessage(true, 22, port, "Cannot close serial port:");
}
hComm[port] = NULL;
return;
}
} else {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 25, port, "Cannot get serial port timeout information:");
if (!CloseHandle(hComm[port])) {
//ShowPortMessage(true, 22, port, "Cannot close serial port:");
}
hComm[port] = NULL;
return;
}
for (j = 0; j < 255; j++) {
if (!ReadFile(hComm[port], buff, sizeof(buff), &dwBytesRead, NULL)) {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 26, port, "Cannot read serial port:");
j = 999; //read error
break;
}
if (dwBytesRead == 0) //No data in COM buffer
break;
Sleep(10); //Have to sleep certain time to let hardware flush buffer
}
if (j != 999) {
setBit(pcState[port], PORT_OPEN);
}
} else {
setBit(SystemState, SYSTEM_PORT_ERROR);
//ShowPortMessage(true, 28, port, "Cannot open serial port:");
hComm[port] = NULL;
}
HANDLE TCommPorts::OpenCommPort(void) {
// OPEN THE COMM PORT.
if (hComm)
return NULL; // if already open, don't bother
if (systemDetect == SYS_DEMO)
return NULL;
hComm = CreateFile(port,
GENERIC_READ | GENERIC_WRITE,
0, //Set of bit flags that specifies how the object can be shared
0, //Security Attributes
OPEN_EXISTING,
0, //Specifies the file attributes and flags for the file
0);//access to a template file
// If CreateFile fails, throw an exception. CreateFile will fail if the
// port is already open, or if the com port does not exist.
// If the function fails, the return value is INVALID_HANDLE_VALUE.
// To get extended error information, call GetLastError.
if (hComm == INVALID_HANDLE_VALUE) {
// throw ECommError(ECommError::OPEN_ERROR);
return INVALID_HANDLE_VALUE;
}
// GET THE DCB PROPERTIES OF THE PORT WE JUST OPENED
if (GetCommState(hComm, &dcbCommPort)) {
// set the properties of the port we want to use
dcbCommPort.BaudRate = CBR_9600;// current baud rate
//dcbCommPort.BaudRate = CBR_115200;
dcbCommPort.fBinary = 1; // binary mode, no EOF check
dcbCommPort.fParity = 0; // enable parity checking
dcbCommPort.fOutxCtsFlow = 0; // CTS output flow control
dcbCommPort.fOutxDsrFlow = 0; // DSR output flow control
//dcbCommPort.fDtrControl = 1; // DTR flow control type
dcbCommPort.fDtrControl = 0; // DTR flow control type
dcbCommPort.fDsrSensitivity = 0;// DSR sensitivity
dcbCommPort.fTXContinueOnXoff = 0; // XOFF continues Tx
dcbCommPort.fOutX = 0; // XON/XOFF out flow control
dcbCommPort.fInX = 0; // XON/XOFF in flow control
dcbCommPort.fErrorChar = 0; // enable error replacement
dcbCommPort.fNull = 0; // enable null stripping
//dcbCommPort.fRtsControl = 1; // RTS flow control
dcbCommPort.fRtsControl = 0; // RTS flow control
dcbCommPort.fAbortOnError = 0; // abort reads/writes on error
dcbCommPort.fDummy2 = 0; // reserved
dcbCommPort.XonLim = 2048; // transmit XON threshold
dcbCommPort.XoffLim = 512; // transmit XOFF threshold
dcbCommPort.ByteSize = 8; // number of bits/byte, 4-8
dcbCommPort.Parity = 0; // 0-4=no,odd,even,mark,space
dcbCommPort.StopBits = 0; // 0,1,2 = 1, 1.5, 2
dcbCommPort.XonChar = 0x11; // Tx and Rx XON character
dcbCommPort.XoffChar = 0x13; // Tx and Rx XOFF character
dcbCommPort.ErrorChar = 0; // error replacement character
dcbCommPort.EofChar = 0; // end of input character
dcbCommPort.EvtChar = 0; // received event character
}
else
{
// something is way wrong, close the port and return
CloseHandle(hComm);
throw ECommError(ECommError::GETCOMMSTATE);
}
// SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS TO OUR SETTINGS.
// REMEMBERTHAT THE ARGUMENT FOR BuildCommDCB MUST BE A POINTER TO A STRING.
// ALSO NOTE THAT BuildCommDCB() DEFAULTS TO NO HANDSHAKING.
// wsprintf(portSetting, "%s,%c,%c,%c", baud, parity, databits, stopbits);
dcbCommPort.DCBlength = sizeof(DCB);
// BuildCommDCB(portSetting, &dcbCommPort);
if (!SetCommState(hComm, &dcbCommPort)) {
// something is way wrong, close the port and return
CloseHandle(hComm);
throw ECommError(ECommError::SETCOMMSTATE);
}
// set the intial size of the transmit and receive queues.
// I set the receive buffer to 32k, and the transmit buffer
// to 9k (a default).
if (!SetupComm(hComm, 1024*32, 1024*9))
{
// something is hay wire, close the port and return
CloseHandle(hComm);
throw ECommError(ECommError::SETUPCOMM);
}
// SET THE COMM TIMEOUTS.
if (GetCommTimeouts(hComm,&ctmoOld)) {
memmove(&ctmoNew, &ctmoOld, sizeof(ctmoNew));
//default settings
ctmoNew.ReadTotalTimeoutConstant = 100;
ctmoNew.ReadTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutMultiplier = 0;
ctmoNew.WriteTotalTimeoutConstant = 0;
if (!SetCommTimeouts(hComm, &ctmoNew)) {
// something is way wrong, close the port and return
CloseHandle(hComm);
throw ECommError(ECommError::SETCOMMTIMEOUTS);
}
} else {
CloseHandle(hComm);
throw ECommError(ECommError::GETCOMMTIMEOUTS);
}
return hComm;
}

Resources