📄 thrcontrol.c
字号:
/*
* Copyright 2003 by Texas Instruments Incorporated.
* All rights reserved. Property of Texas Instruments Incorporated.
* Restricted rights to use, duplicate or disclose this code are
* granted through contract.
*
*/
/* "@(#) ReferenceFrameworks 2.20.00.08 07-18-03 (swat-f02)" */
/*
* ======== thrControl.c ========
*
* Procedures for the control ISR and the control thread
*
* The purpose of the control thread is to detect hardware events such
* as user's presses on device's buttons and other controls, and apply
* them to data processing. (For example, changing the volume, modifying
* filter parameters, cancelling a channel etc.)
*
* The mechanism is the following: a hardware event such as button press
* trigers an interrupt, serviced by thrControlIsr() procedure below.
* That procedure quickly reads the hardware parameters, interprets them,
* stores the result of the interpretation in thrControl thread's data
* structure, posts the swiControl thread and exits. It does not modify
* any of the data processing parameters itself.
*
* Thread swiControl is a SWI like the processing SWIs, and has exactly
* the same priority; it executes thread function thrControlRun().
* Function thrControlRun(), based on the data presented by thrControlIsr(),
* modified processing thread's data and/or XDAIS algorithms' parameters.
*
* The reason we encapsulate processing parameters modification logic
* in a separate SWI thread is twofold:
*
* 1) We want to keep the time spent in a hardware interrupt at a
* minimum;
* 2) thrControlIsr() most likely interrupted a data processing thread;
* we don't want to modify processing parameters in the middle of
* processing activity.
*
* By having swiControl have the same priority as the processing threads,
* we ensure that it does not prevent them, nor gets starved by them,
* so it has a low latency. Thread swiControl should thus have the
* priority of the lowest-priority thread whose data parameters it
* modifies.
*
* An alternative approach may be to check the device controls every
* certain period (for example, 20 ms), if there's no interrupt that
* would inform us about the hardware event. This choice depends
* on the application and the device.
*
* In our example the host writes into an area of memory that simulates
* I/O area where the buttons and other controls are, and we have
* a clkControl object that runs thrControlIsr() function; that is a
* timer interrupt which simulates a device control interrupt -- this
* we use if we develop and test applications on a board such as
* DSK5402, where no buttons are connected to any interrupt lines.
*/
#include <std.h>
#include <hwi.h>
#include <swi.h>
#include <utl.h> /* debug/diagnostics utility functions */
#include "appResources.h" /* application-wide common info */
#include "appThreads.h" /* thread-wide common info */
#include "thrAudioproc.h" /* definition of thrAudioproc thread data */
#include "thrControl.h" /* definition of thrControl thread data */
#include "thrTxJoin.h" /* definition of thrTxJoin thread data */
/*
* Above we included header files with data structure definitions
* of all the threads whose data we may modify. This is the only
* procedure in the system that should attempt to write to other
* threads' private data.
*/
/*
* Static initialization
*/
/*
* We simulate reading the device's controls by having an area
* in memory that we will read whenever this function is posted to
* run, and the host will write to it using a GEL script. This simulates
* an I/O area where values of buttons and sliders can be read.
* The map of the area is the following:
*
* Word 0: flag indicating whether new values have been written by the
* user. The GEL script, when changing anything, sets this to
* TRUE (1), and the control ISR, if finds this to be TRUE,
* reads all the other values and then sets this flag to FALSE;
* otherwise (if it is already FALSE) it knows no new user
* input has been made and therefore takes no action
* Word 1: number of the channel whose output should be sent to the codec
* Word 2: ch#0 volume gain; 0-200; 100 normal
* Word 3: ch#1 0:filter disabled, 1:enabled
* etc. Host's GEL file writes to this array directly.
*
* Note: this array and the first if() clause in thrControlIsr() are
* the only portions of code that are here due to the fact that in this
* application we simulate device buttons from a GEL file on the host.
*/
Int deviceControlsIOArea[] = {
FALSE, /* initially, no user action */
0, /* default active channel */
100, /* default volume for channel #0 */
100, /* default volume for channel #1 */
};
/*
* Control thread's data structure. (We don't have to initialize it since
* control ISR will write to it before posting the thread. However, if it
* had some other, persistent data, we could initialize it here.)
*/
ThrControl thrControl;
/*
* ========= thrControlIsr ========
* Interrupt Service Routine for the Control thread
*
* reads the values of buttons/knobs from the device, stores the
* interpreted information in control thread's data structure and
* posts the thread
*/
Void thrControlIsr( Void ) {
Int i;
static Uns activationCount = 0;
/*
* We are really called from the CLK object upon every timer interrupt
* whereas user's action would occur after relatively long intervals,
* so we try to simulate that, too. Since interrupts occur every
* 1ms (based on the BIOS config), we arbitrarily decide to actually
* do anything in this procedure every 20 interrupts, i.e. every 20 ms.
* If the if() clause below is removed, then the response to the user's
* action could happen in one millisecond. That would be the case with
* control ISR activated by a separate interrupt line. Such ISR would
* not need the if() clause below.
*/
if (++activationCount < 20) { /* 20 ms */
return;
} else {
activationCount = 0;
}
/* now proceed with regular "I/O memory" reading actions */
/* check if there has been any unread user input */
if (deviceControlsIOArea[0] == FALSE) {
return; /* there has not; return */
}
/* read "channel selection" switch */
thrControl.outputChannel = deviceControlsIOArea[1];
/*
* Read "volume" value for all channels and store
* the information in control thread's data structure. Interpretation
* is trivial in this case, we just copy host's data to control thread's
* data structure.
*/
for (i = 0; i < NUMCHANNELS; i++) {
/* read "slider" for volume */
thrControl.outputVolume[i] = deviceControlsIOArea[ 2 + i ];
}
/* now post the control thread */
SWI_post( &swiControl );
/* and clear the "user input" flag */
deviceControlsIOArea[0] = FALSE;
}
/*
* ========= thrControlInit ========
* Initialization of data structures for the thread, called from
* appThreads.c:thrInit() at init time.
*/
Void thrControlInit( Void )
{
}
/*
* ========= thrControlRun ========
* The body of the control thread (SWI).
*
* Reads the channel selection/filter enable/volume values
* and applies them to data processing
*/
Void thrControlRun( Void )
{
Int i;
Uns interruptState;
/* a local copy of all thrControlIsr-writable variables: */
Int outputChannel;
Int outputVolume[ NUMCHANNELS ];
/*
* Disable the control ISR, make a local copy of all the variables
* that the conrol ISR can write to, and restore interrupts. After
* that we will use local copies only; that is to prevent the ISR
* partially overwriting our current set of values (i.e. to prevent
* race conditions).
*/
interruptState = HWI_disable();
outputChannel = thrControl.outputChannel;
for (i = 0; i < NUMCHANNELS; i++) {
outputVolume[i] = thrControl.outputVolume[i];
}
HWI_restore( interruptState );
/* now use the local copies to change threads' parameters */
/* Instruct thrTxJoin thread which channel to output */
thrTxJoinSetOutputChannel( outputChannel );
/* set the new volume value for all the channels */
for (i = 0; i < NUMCHANNELS; ++i) {
thrAudioprocSetOutputVolume( i, outputVolume[i] );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -