Scheduled events to ALSA sequencer are not being outputted - c

In this example code I set up an ALSA client, create a sequencer queue and output port. Then I output a scheduled note on and note off event to this port and wait for a keystroke. At this point I set up midisnoop to read from the port.
When keystroke arrives I start the queue and read the realtime ticks. I am expecting the note to show on the output port which I am monitoring. Nothing appears.
#include <stdio.h>
#include <alsa/asoundlib.h>
int queue, out_port;
snd_seq_t *seq_handle;
snd_seq_tick_time_t current_tick;
snd_seq_queue_status_t *status;
int main (int argc, char **argv) {
// open sequencer and create queue
snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT | SND_SEQ_OPEN_OUTPUT, 0);
queue = snd_seq_alloc_queue( seq_handle );
fprintf(stderr,"queue id=%d\n", queue);
// create an output port
out_port = snd_seq_create_simple_port(seq_handle, "test:out",
SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
SND_SEQ_PORT_TYPE_APPLICATION);
if( out_port < 0 ) return 1;
// set up a midi event for scheduling noteon and noteoff
snd_seq_event_t event;
snd_seq_ev_clear( &event );
// set up source address
snd_seq_addr_t addr;
addr.client = snd_seq_client_id( seq_handle);
addr.port = out_port;
event.source = addr;
// set destination addressing to all subscribers
snd_seq_ev_set_subs( &event );
// note specifics
int chan = 0;
int note = 64;
int veloc = 127;
int tick = 0;
// note on at zero
snd_seq_ev_set_noteon( &event, chan, note, veloc);
snd_seq_ev_schedule_tick( &event, queue, 0, tick );
snd_seq_event_output( seq_handle, &event );
// note off at 96
tick = 96;
snd_seq_ev_set_noteoff( &event, chan, note, veloc);
snd_seq_ev_schedule_tick( &event, queue, 0, tick );
snd_seq_event_output( seq_handle, &event );
// drain output
snd_seq_drain_output( seq_handle );
// wait here for keystroke, so we can set up midisnoop
fgetc( stdin );
// start queue and read ticks
snd_seq_start_queue( seq_handle, queue, NULL );
snd_seq_drain_output( seq_handle );
for(int i=0;i<4;i++) {
snd_seq_queue_status_malloc(&status);
snd_seq_get_queue_status(seq_handle, queue, status);
current_tick = snd_seq_queue_status_get_tick_time(status);
snd_seq_queue_status_free(status);
fprintf(stderr,"tick=%d\n", current_tick );
sleep(1);
}
snd_seq_stop_queue( seq_handle, queue, NULL );
snd_seq_free_queue( seq_handle, queue );
return 0;
}

Starting a queue clears it.
You must send the queue start event before the actual events. (You do not need to drain it separately.)

Related

Signals not being masked/becoming unmasked during a critical section (POSIX pthreads)?

Preface - i use "task" and "thread" interchangeably here even though i know they are different. In my program a task is wrapped in a thread - the latter constantly waiting for an cond event to awaken the task.
During a context switch, the ContextSwitchHandler checks the incoming task for invalid info. However, it is returning a failure for tasks even when they have valid data.
By putting an infinite loop inside the task-data check, and then placing another in the signal handler, i can see that signals are interrupting this execution - even though i have supposedly masked signals before entering the ContextSwitchHandler.
This where the context switch starts:
void vPortYieldWithinAPI( void )
{
portUnsignedBaseType xInterruptsAlreadyMasked;
portcompatASSERT_PRIVILEGED_MODE(); // currently defined as nothing
xInterruptsAlreadyMasked = uxPortSetInterruptMaskFromISR();
vPortSwitchContext();
vPortClearInterruptMaskFromISR( xInterruptsAlreadyMasked );
}
and here is the implementation of the signal mask function - xPortIsrNormalSignalMask is a full signal mask except SIGINT being unblocked, as is shown further down.
portUnsignedBaseType uxPortSetInterruptMaskFromISR( void )
{
sigset_t xOriginalMask;
portUnsignedBaseType uxOriginalPriority;
pthread_sigmask( SIG_BLOCK, &xPortIsrNormalSignalMask, &xOriginalMask );
if( sigismember( &xOriginalMask, configPORT_SIGNAL_FOR_IRQ ) )
{
uxOriginalPriority = 1U; /* interrupts were originally masked */
}
else
{
uxOriginalPriority = 0U; /* interrupts were originally unmasked */
}
return uxOriginalPriority;
}
During the context switch, the task validity check is performed (signals should still be masked at this point).
KERNEL_FUNCTION portBaseType xPortIsTaskHandleValid( portTaskHandleType xTaskToCheck )
{
portBaseType xReturn;
const xTCB *pxTCB;
static portUInt32Type ulFailCount = 0;
/* THIS FUNCTION MUST ONLY BE CALLED FROM WITHIN A CRITICAL SECTION. */
/* First, ensure we've not been given a NULL pointer to check. */
if( NULL == xTaskToCheck )
{
xReturn = pdFALSE;
}
else
{
/* Set a pointer to the TCB buffer. */
pxTCB = ( const xTCB * ) xTaskToCheck;
if( ( portDataAddressType )( pxTCB->pxStackLimit ) != ~( pxTCB->uxStackLimitMirror ) )
{
/* The stack limit mirror is not as expected. */
xReturn = pdFALSE;
}
else if( ( portDataAddressType )( pxTCB->pxTopOfStack ) != ~( pxTCB->uxTopOfStackMirror ) )
{
/* The top of stack mirror is not as expected. */
xReturn = pdFALSE;
/* I have tried adding another signal mask here before i enter the while
* loop, but this also doesn't seem to prevent the SIGALARM from firing. */
sigset_t set;
sigemptyset(&set); /* initialize the signal set */
sigaddset(&set, SIGALRM); /* add SIGALRM to the set */
pthread_sigmask( SIG_BLOCK, &set, NULL );
/* */
while( 1 )
{
/* put a breakpoint here... to check if we are getting interrupts */
xReturn++;
xReturn--;
}
}
...
return xReturn;
}
What im finding is the incoming task fails this second check, even though when i inspect the data the mirror is indeed correct for the stack address. So my belief is that interrupts are occurring and messing with the statement.
As i said, if i place a breakpoint in this while loop, run to that point and the put another in the signal handler, i can still see signals occurring.
My configuration of the signals and signal handlers is as follows:
portBaseType iPortIsrSetupDefaultThreadSignalMask( void )
{
portBaseType xReturn;
/* Disable all signals except SIGINT. From main thread, other threads
* should inherit this. We leave SIGINT so we can stop it. */
xReturn = ( portBaseType )sigfillset( &xPortIsrNormalSignalMask );
if( 0 == xReturn )
{
xReturn = ( portBaseType )sigdelset( &xPortIsrNormalSignalMask, SIGINT );
}
if( 0 == xReturn )
{
xReturn = ( portBaseType )pthread_sigmask( SIG_SETMASK, &xPortIsrNormalSignalMask, &xPortOriginalSignalMask );
}
return xReturn;
}
/*---------------------------------------------------------------------------*/
void vPortInitialiseINTC( void )
{
struct sigaction xSigActIRQ, xTestSigActIRQ;
if( iPortIsrSetupDefaultThreadSignalMask() != 0 )
{
portERRORHOOKSTR( NULL, "Failed to set up default signal mask", errINVALID_PARAMETERS );
}
xSigActIRQ.sa_flags = SA_SIGINFO;
xSigActIRQ.sa_sigaction = vPortIsrIRQHandler;
// we set two sigmasks, one here and one in iPortIsrSetupDefaultThreadSignalMask(), which one is actually masking irq's?
sigemptyset( &xSigActIRQ.sa_mask );
if( sigaction( configPORT_SIGNAL_FOR_IRQ, &xSigActIRQ, NULL ) )
{
portERRORHOOKSTR( NULL, "Failed to set up simulated interrupt system", errINVALID_PARAMETERS );
}
}
/*---------------------------------------------------------------------------*/
portWEAK_FUNCTION void vApplicationSetupTickInterruptHook( portUInt32Type ulClockHz, portUInt32Type ulRateHz )
{
struct sigevent xTimerEv;
struct itimerspec xSysTickTimerSpec;
int iSysRet;
long lNanosecondsPerTick;
( void )ulClockHz; /* Unused in this port */
portcompatASSERT_PRIVILEGED_MODE();
lNanosecondsPerTick = ( long ) PORT_ONE_SECOND_IN_NS / ( long ) ulRateHz;
vPortDisableInterrupts();
xTimerEv.sigev_notify = SIGEV_SIGNAL;
xTimerEv.sigev_signo = configPORT_SIGNAL_FOR_IRQ;
xTimerEv.sigev_value.sival_int = configPORT_SYSTICK_INTERRUPT_NUM; // defined as 14, same as SIGALARM
xTimerEv.sigev_notify_function = NULL;
iSysRet = timer_create( CLOCK_MONOTONIC, &xTimerEv, &xPortSysTickTimer );
if(iSysRet)
{
portERRORHOOKSTR( NULL, "Failed to create tick timer", errINVALID_PARAMETERS );
}
xSysTickTimerSpec.it_interval.tv_sec = 0;
xSysTickTimerSpec.it_interval.tv_nsec = lNanosecondsPerTick;
xSysTickTimerSpec.it_value.tv_sec = 0;
xSysTickTimerSpec.it_value.tv_nsec = lNanosecondsPerTick;
iSysRet = timer_settime( xPortSysTickTimer, 0, &xSysTickTimerSpec, NULL );
if(iSysRet)
{
portERRORHOOKSTR( NULL, "failed to set & start tick timer", errINVALID_PARAMETERS );
}
}
Is there some point in my configuration that isnt setting up the signal masks properly? Signals and threads are quite new to me so please feel free to ask for extra info or clarification if required.
Thank you

How to update the LED on a TI board and report to the server every second via UART

I am modifying a code in embedded C language and trying to make it to where it checks buttons every 200ms, checks the temperature every 500ms, and update the LED and report to the server every second. My code appears to be complete but when I run it, nothing outputs to the console, and my LED light neither turns off or on when I press either buttons on the side of the TI board. Is there something wrong with my nested while loop? Here is my code:
/*
* ======== gpiointerrupt.c ========
*/
#include <stdint.h>
#include <stddef.h>
/* Driver Header files */
#include <ti/drivers/GPIO.h>
#include <ti/drivers/I2C.h>
#include <ti/drivers/UART.h>
/* Driver configuration */
#include "ti_drivers_config.h"
/* Driver timer */
#include <ti/drivers/Timer.h>
#define TRUE 1
#define FALSE 0
#define NUMBER_OF_TASKS 3
#define GLOBAL_PERIOD 100 //milliseconds
#define DISPLAY(x) UART_write(uart, &output, x);
// UART Global Variables
char output[64];
int bytesToSend;
// Driver Handles - Global variables
UART_Handle uart;
// Init variables
int buttonCheckTime = 0;
int tempCheckTime = 0;
int displayCheckTime = 0;
int buttonCheckPeriod = 200;
int tempCheckPeriod = 500;
int displayCheckPeriod = 1000;
int setpoint = 25;
int heat = 0;
int seconds = 0;
int temperature = 0;
int firstButtonWasPressed = FALSE; // It is initally false that the button was pressed
int secondButtonWasPressed = FALSE; // It is initally false that the button was pressed
int global_period = GLOBAL_PERIOD; // Global period to be used initTimer()
void initUART(void)
{
UART_Params uartParams;
// Init the driver
UART_init();
// Configure the driver
UART_Params_init(&uartParams);
uartParams.writeDataMode = UART_DATA_BINARY;
uartParams.readDataMode = UART_DATA_BINARY;
uartParams.readReturnMode = UART_RETURN_FULL;
uartParams.baudRate = 115200;
// Open the driver
uart = UART_open(CONFIG_UART_0, &uartParams);
if (uart == NULL)
{
/* UART_open() failed */
while (1)
;
}
}
// I2C Global Variables
static const struct
{
uint8_t address;
uint8_t resultReg;
char *id;
} sensors[3] = { { 0x48, 0x0000, "11X" }, { 0x49, 0x0000, "116" }, { 0x41,
0x0001,
"006" } };
uint8_t txBuffer[1];
uint8_t rxBuffer[2];
I2C_Transaction i2cTransaction;
// Driver Handles - Global variables
I2C_Handle i2c;
// Initialize the I2C peripheral
// Make sure you call initUART() before calling this function.
void initI2C(void)
{
int8_t i, found;
I2C_Params i2cParams;
DISPLAY(snprintf(output, 64, "Initializing I2C Driver - "))
// Init the driver
I2C_init();
// Configure the driver
I2C_Params_init(&i2cParams);
i2cParams.bitRate = I2C_400kHz;
// Open the driver
i2c = I2C_open(CONFIG_I2C_0, &i2cParams);
if (i2c == NULL)
{
DISPLAY(snprintf(output, 64, "Failed\n\r"))
while (1)
;
}
DISPLAY(snprintf(output, 32, "Passed\n\r"))
// Boards were shipped with different sensors.
// Welcome to the world of embedded systems.
// Try to determine which sensor we have.
// Scan through the possible sensor addresses
/* Common I2C transaction setup */
i2cTransaction.writeBuf = txBuffer;
i2cTransaction.writeCount = 1;
i2cTransaction.readBuf = rxBuffer;
i2cTransaction.readCount = 0;
found = false;
for (i = 0; i < 3; ++i)
{
i2cTransaction.slaveAddress = sensors[i].address;
txBuffer[0] = sensors[i].resultReg;
DISPLAY(snprintf(output, 64, "Is this %s? ", sensors[i].id))
if (I2C_transfer(i2c, &i2cTransaction))
{
DISPLAY(snprintf(output, 64, "Found\n\r"))
found = true;
break;
}
DISPLAY(snprintf(output, 64, "No\n\r"))
}
if (found)
{
DISPLAY(snprintf(output, 64, "Detected TMP%s I2C address: %x\n\r",
sensors[i].id, i2cTransaction.slaveAddress))
}
else
{
DISPLAY(snprintf(output, 64,
"Temperature sensor not found, contact professor\n\r"))
}
}
int16_t readTemp(void)
{
int j;
int16_t temperature = 0;
i2cTransaction.readCount = 2;
if (I2C_transfer(i2c, &i2cTransaction))
{
/*
* Extract degrees C from the received data;
* see TMP sensor datasheet
*/
temperature = (rxBuffer[0] << 8) | (rxBuffer[1]);
temperature *= 0.0078125;
/*
* If the MSB is set '1', then we have a 2's complement
* negative value which needs to be sign extended
*/
if (rxBuffer[0] & 0x80)
{
temperature |= 0xF000;
}
}
else
{
DISPLAY(snprintf(output, 64, "Error reading temperature sensor (%d)\n\r", i2cTransaction.status))
DISPLAY(snprintf(output,64, "Please power cycle your board by unplugging USB and plugging back in.\n\r"))
}
return temperature;
}
// Driver Handles - Global variables
Timer_Handle timer0;
volatile unsigned char TimerFlag = 0;
// A single task in the task list.
struct task_entry
{
void (*f)(); // Function to call to perform the task
int elapsed_time; // Amount of time since last triggered
int period; // Period of the task in ms
char triggered; // Whether or not the task was triggered
};
// Forward declaration
void task_one();
void task_two();
void task_three();
void task_one()
{
// Processing for task_one takes place
/* Every 200ms, check button presses */
if (buttonCheckTime >= buttonCheckPeriod) // Button check time equals or exceeds period
{
if (firstButtonWasPressed == TRUE) // Button on one side raises setpoint (thermostat setting) by 1
{
setpoint += 1; // Increment thermostat
firstButtonWasPressed = FALSE; // Reset button to FALSE
}
if (secondButtonWasPressed == TRUE) // Button on the other side lowers setpoint (thermostat setting) by 1
{
setpoint -= 1; // Decrement thermostat
secondButtonWasPressed = FALSE; // Reset button to FALSE
}
}
}
void task_two()
{
// Processing for task_two takes place
if (tempCheckTime >= tempCheckPeriod) // Temperature check time equals or exceeds period
{
temperature = readTemp();
if (temperature > setpoint) {
GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_OFF);
heat = 0;
}
else {
GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
heat = 1;
}
}
}
void task_three()
{
// Processing for task_three takes place
if (displayCheckTime == displayCheckPeriod) {
DISPLAY(snprintf(output, 64, "<%02d,%02d,%d,%04d>\n\r", temperature,
setpoint, heat, seconds));
++seconds;
}
}
// The task list
struct task_entry tasks[NUMBER_OF_TASKS] = { { FALSE, &task_one, 500, 500 }, {FALSE, &task_two, 1500, 1500 }, { FALSE, &task_three, 2000, 2000 } };
void timerCallback(Timer_Handle myHandle, int_fast16_t status)
{
int x = 0;
// Walk through each task.
for (x = 0; x < NUMBER_OF_TASKS; x++)
{
// Check if task's interval has expire
if (tasks[x].elapsed_time >= tasks[x].period)
{
// Bing! This task's timer is up
// Set it's flag, and the global flag
tasks[x].triggered = TRUE;
TimerFlag = TRUE;
// Reset the elapsed_time
tasks[x].elapsed_time = 0;
}
else
{
tasks[x].elapsed_time += global_period;
}
}
}
void initTimer(void)
{
Timer_Params params;
// Init the driver
Timer_init();
// Configure the driver
Timer_Params_init(&params);
params.period = 1000000;
params.periodUnits = Timer_PERIOD_US;
params.timerMode = Timer_CONTINUOUS_CALLBACK;
params.timerCallback = timerCallback;
// Open the driver
timer0 = Timer_open(CONFIG_TIMER_0, &params);
if (timer0 == NULL)
{
/* Failed to initialized timer */
while (1)
{
}
}
if (Timer_start(timer0) == Timer_STATUS_ERROR)
{
/* Failed to start timer */
while (1)
{
}
}
}
/*
* ======== gpioButtonFxn0 ========
* Callback function for the GPIO interrupt on CONFIG_GPIO_BUTTON_0.
*
* Note: GPIO interrupts are cleared prior to invoking callbacks.
*/
void gpioButtonFxn0(uint_least8_t index)
{
/* Toggle an LED */
//GPIO_toggle(CONFIG_GPIO_LED_0);
firstButtonWasPressed = TRUE; // It is true that the button was pressed
}
/*
* ======== gpioButtonFxn1 ========
* Callback function for the GPIO interrupt on CONFIG_GPIO_BUTTON_1.
* This may not be used for all boards.
*
* Note: GPIO interrupts are cleared prior to invoking callbacks.
*/
void gpioButtonFxn1(uint_least8_t index)
{
/* Toggle an LED */
//GPIO_toggle(CONFIG_GPIO_LED_1);
secondButtonWasPressed = TRUE;
}
/*
* ======== mainThread ========
*/
void* mainThread(void *arg0)
{
/* Call driver init functions */
GPIO_init();
/* Configure the LED and button pins */
GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
//GPIO_setConfig(CONFIG_GPIO_BUTTON_0;
//GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);
/* Turn on user LED */
GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
/* Install Button callback */
GPIO_setCallback(CONFIG_GPIO_BUTTON_0, gpioButtonFxn0);
/* Enable interrupts */
GPIO_enableInt(CONFIG_GPIO_BUTTON_0);
/*
* If more than one input pin is available for your device, interrupts
* will be enabled on CONFIG_GPIO_BUTTON1.
*/
if (CONFIG_GPIO_BUTTON_0 != CONFIG_GPIO_BUTTON_1)
{
/* Configure BUTTON1 pin */
GPIO_setConfig(CONFIG_GPIO_BUTTON_1,
GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);
/* Install Button callback */
GPIO_setCallback(CONFIG_GPIO_BUTTON_1, gpioButtonFxn1);
/* Enable interrupts */
GPIO_enableInt(CONFIG_GPIO_BUTTON_1);
}
// Call driver init functions
initUART(); // The UART must be initialized before calling initI2C()
initI2C();
initTimer();
// Loop Forever
while (TRUE)
{
readTemp();
// Every 200ms check the button flags
task_one();
// Every 500ms read the temperature and update the LED
task_two();
// Every second output the following to the UART
// "<%02d,%02d,%d,%04d>, temperature, setpoint, heat, seconds
task_three();
// Wait for task intervals (periods) to elapse
while (!TimerFlag)
{
} // Wait for timer period
// Process the tasks for which the interval has expired
int x = 0;
for (x = 0; x < NUMBER_OF_TASKS; x++)
{
if (tasks[x].triggered)
{
tasks[x].f();
// reset
tasks[x].triggered = FALSE;
}
}
// Reset everything (e.g. flags) and go back to the beginning
TimerFlag = FALSE; // Lower flag raised by timer
++global_period;
}
}

Is there any method to wait until task catch SIGALRM signal in intel arch?

I'm programming iwth gcc version 4.4.3 on Ubuntu 10.04
I don't know how to catch SIGALRM with sigtimedwait(),sigwait().
If timer handler is set , sigtimedwait(),sigwait() always returns EINTR(4).
If timer handler is not set, SIGALRM never received.
Is there any method to wait until task catch SIGALRM signal in intel arch?
void handler( int signo )
{
...
}
int main( void )
{
timer_t timer_id;
struct sigaction sigact;
struct itimerspec itval;
int ret;
struct timespec pTimeout;
siginfo_t pInfo;
pTimeout.tv_sec = 10;
pTimeout.tv_nsec = 0;
// set signal handler for SIGALRM
sigact.sa_handler = handler;
sigact.sa_flags = 0;
sigemptyset( &sigact.sa_mask );
sigaction( SIGALRM, &sigact, NULL );
// create timer
timer_create( CLOCK_REALTIME, NULL, &timer_id );
itval.it_value.tv_sec = 3;
itval.it_value.tv_nsec = 0;
itval.it_interval.tv_sec = 0;
itval.it_interval.tv_nsec = 250 * 1000 * 1000;
// set timer
timer_settime( timer_id, 0, &itval, NULL );
int count;
for ( count = 0; count < 10; count++ )
{
// wait for SIGALRM
ret = sigtimedwait
(
&sigact.sa_mask, /* the signal mask while suspended */
&pInfo, /* return value */
&pTimeout
);
.....
}
Is this helpful?
do {
ret = sigtimedwait(&sigact.sa_mask, &pInfo, &pTimeout);
} while (ret < 0 && errno == EINTR);
Similar question.
Some of the 'wait until a signal is received' functions are:
pause()
sigsuspend()
sigpause()
The sigpause() function is actually part of a deprecated set of functions; it is best not to use it in new code.
There is also:
sigtimedwait()
which may do what you want more directly.

need programs that illustrate use of settimer and alarm functions in GNU C

Can anyone illustrate the use of settimer or alarm function in gnu C , with some program examples ,please ?
I have a program that continuously processes some data , and i need to set a timer / alarm that goes off every t seconds , in response to which , i need to store the processed data into a file. This file writing has to be asynchronous < i.e. the data processing and file writing must not wait for each other > . I went through the GNU C Library pages , but i couldn't understand much..
[EDIT]
I got this program :
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#define INTERVAL 1
int howmany = 0;
void alarm_wakeup (int i)
{
struct itimerval tout_val;
signal(SIGALRM,alarm_wakeup);
howmany += INTERVAL;
printf("\n%d sec up partner, Wakeup!!!\n",howmany);
tout_val.it_interval.tv_sec = 0;
tout_val.it_interval.tv_usec = 0;
tout_val.it_value.tv_sec = INTERVAL; /* 10 seconds timer */
tout_val.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &tout_val,0);
}
void exit_func (int i)
{
signal(SIGINT,exit_func);
printf("\nBye Bye!!!\n");
exit(0);
}
int main ()
{
struct itimerval tout_val;
tout_val.it_interval.tv_sec = 0;
tout_val.it_interval.tv_usec = 0;
tout_val.it_value.tv_sec = INTERVAL; /* 10 seconds timer */
tout_val.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &tout_val,0);
signal(SIGALRM,alarm_wakeup); /* set the Alarm signal capture */
signal(SIGINT,exit_func);
while (1)
{
//printf("!");
}
return 0;
}
But seems like i cannot do anything while the timer is on..
What should i modify to suit my needs ? Pl suggest..
[/EDIT]
Here's an example from here which uses setitimer() to periodically call DoStuff().
The key here is that calling setitimer() results in the OS scheduling a SIGALRM to be sent to your process after the specified time has elapsed, and it is up to your program to handle that signal when it comes. You handle the signal by registering a signal handler function for the signal type (DoStufF() in this case) after which the OS will know to call that function when the timer expires.
You can read the setitimer() man page to figure out what the arguments are and how to cancel a timer.
Note: if you want the timer to trigger only once, you will have to call alarm() or ualarm() instead of setitimer().
/*
* setitimer.c - simple use of the interval timer
*/
#include <sys/time.h> /* for setitimer */
#include <unistd.h> /* for pause */
#include <signal.h> /* for signal */
#define INTERVAL 500 /* number of milliseconds to go off */
/* function prototype */
void DoStuff(void);
int main(int argc, char *argv[]) {
struct itimerval it_val; /* for setting itimer */
/* Upon SIGALRM, call DoStuff().
* Set interval timer. We want frequency in ms,
* but the setitimer call needs seconds and useconds. */
if (signal(SIGALRM, (void (*)(int)) DoStuff) == SIG_ERR) {
perror("Unable to catch SIGALRM");
exit(1);
}
it_val.it_value.tv_sec = INTERVAL/1000;
it_val.it_value.tv_usec = (INTERVAL*1000) % 1000000;
it_val.it_interval = it_val.it_value;
if (setitimer(ITIMER_REAL, &it_val, NULL) == -1) {
perror("error calling setitimer()");
exit(1);
}
while (1)
pause();
}
/*
* DoStuff
*/
void DoStuff(void) {
printf("Timer went off.\n");
}

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