📄 keyboard_example.c
字号:
DEV_Resume();
#endif
LED_INIT();
LED_ON(LED_POWER);
LED_OFF(LED_USB);
LED_OFF(LED_MEM);
}
//------------------------------------------------------------------------------
//! \brief Callback invoked when a new SETUP request is received
//!
//! The new request if forwarded to the standard request handler,
//! which performs the enumeration of the device.
//! \param pUsb Pointer to a S_usb instance
//------------------------------------------------------------------------------
static void CBK_NewRequest(const S_usb *pUsb)
{
KBD_RequestHandler(&sKbd);
}
//------------------------------------------------------------------------------
//! \brief Resets a timer when a new report has been sent.
//!
//! This is necessary to comply with the configured Idle rate set by
//! the host. When the timer expires, this means the report has been
//! unchanged and that the device should resent it once.
//------------------------------------------------------------------------------
static void ResetTimer()
{
// Check that Idle rate is not null (infinite)
if (sKbd.bIdleRate > 0) {
dTimerTicks = 0;
AT91C_BASE_TC0->TC_RC = (AT91C_MASTER_CLOCK / 2) / 1000;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
}
}
//------------------------------------------------------------------------------
//! \brief Called when the timer expires after a new input report has been sent
//!
//! The same report is sent one more time to indicate that it is
//! unchanged.
//------------------------------------------------------------------------------
static void TimerExpired()
{
unsigned char bStatus;
TRACE_DEBUG_H("Expired\n\r");
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
// Send current report once
do {
bStatus = KBD_SendReport(&sKbd, 0, 0);
}
while (bStatus != USB_STATUS_SUCCESS);
}
//------------------------------------------------------------------------------
//! \brief Called when a timer tick occurs, every 1ms.
//!
//! When the current Idle rate has been reached, the TimerExpired method
//! is triggered.
//------------------------------------------------------------------------------
static void TimerTick()
{
volatile unsigned int dDummy;
// Increase tick count
dTimerTicks++;
// Check if Idle rate has been reached
if (dTimerTicks >= (sKbd.bIdleRate*4)) {
TimerExpired();
}
// Clear interrupt
dDummy = AT91C_BASE_TC0->TC_SR;
}
//------------------------------------------------------------------------------
//! \brief Called when the host has sent an output report to the device.
//------------------------------------------------------------------------------
static void ReportReceived()
{
// Check the bmLEDs field
if (ISSET(sKbd.sOutputReport.bmLeds, 1)) {
LED_ON(LED_MEM);
}
else {
LED_OFF(LED_MEM);
}
}
//------------------------------------------------------------------------------
//! \brief Receive loop for output report sent by the host.
//!
//! When a new report is received, the KBD_ReceiveReport function is
//! called again to start a new transfer immediately.
//------------------------------------------------------------------------------
static void ReceiveReports()
{
unsigned char bStatus;
do {
bStatus = KBD_ReceiveReport(&sKbd, (Callback_f) ReportReceived, 0);
}
while (bStatus != USB_STATUS_SUCCESS);
}
//------------------------------------------------------------------------------
// Main
//------------------------------------------------------------------------------
int main()
{
unsigned int dPioStatus;
bool isChanged;
unsigned int dNumPressedKeys;
unsigned int dKey;
S_kbd_input_report *pInputReport = &(sKbd.sInputReport);
unsigned char bStatus;
TRACE_INIT();
TRACE_INFO("\n\rMain HID keyboard\n\r");
// Configure timer 0
// 1 ms precision
AT91F_TC0_CfgPMC();
AT91C_BASE_TC0->TC_CMR = AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO;
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC,
AT91C_ID_TC0,
AT91C_AIC_PRIOR_LOWEST,
0,
TimerTick);
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_TC0);
// Initialize switches
AT91F_BUTTON_Init();
// Initialize the HID driver
KBD_Init(&sKbd, &sUsb, (Callback_f) ReportReceived);
TRACE_INFO("Connecting ... ");
// Wait for the device to be powered before connecting it
while (!ISSET(USB_GetState(&sUsb), USB_STATE_POWERED));
USB_Connect(&sUsb);
TRACE_INFO("OK\n\r");
// Wait for the device to be configured
while (!ISSET(USB_GetState(&sUsb), USB_STATE_CONFIGURED));
// Start receiving reports on the Interrupt OUT pipe
ReceiveReports();
// Main loop
while (1) {
isChanged = false;
dNumPressedKeys = 0;
// Retrieve PIO status change
dPioStatus = SWITCH_PIO->PIO_PDSR;
// Check standard keys
for (dKey = 0; dKey < NUM_NORMAL_KEYS; dKey++) {
// Check for status mismatch
if (ISCLEARED(dPioStatus, pKeyPios[dKey]) != pKeyPressed[dKey]) {
// Update status
pKeyPressed[dKey] = ISCLEARED(dPioStatus, pKeyPios[dKey]);
// Check if key has been pressed or released
if (pKeyPressed[dKey]) {
// Update input report
pInputReport->pPressedKeys[dNumPressedKeys] = pKeyCodes[dKey];
dNumPressedKeys++;
}
isChanged = true;
}
}
// Check modifier keys
for (dKey = NUM_NORMAL_KEYS; dKey < NUM_KEYS; dKey++) {
// Check for status mismatch
if (ISCLEARED(dPioStatus, pKeyPios[dKey]) != pKeyPressed[dKey]) {
// Update status
pKeyPressed[dKey] = ISCLEARED(dPioStatus, pKeyPios[dKey]);
// Check if key has been pressed or released
if (pKeyPressed[dKey]) {
// Update input report
SET(pInputReport->bmModifierKeys, pKeyCodes[dKey]);
}
else {
// Update input report
CLEAR(pInputReport->bmModifierKeys, pKeyCodes[dKey]);
}
isChanged = true;
}
}
// Report status change
if (isChanged) {
// Clear remaining keys
for (dKey = dNumPressedKeys; dKey < NUM_KEYS; dKey++) {
pInputReport->pPressedKeys[dKey] = 0;
}
// Send new report
do {
bStatus = KBD_SendReport(&sKbd, (Callback_f) ResetTimer, 0);
}
while (bStatus != USB_STATUS_SUCCESS);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -