📄 os_cpu_c.c
字号:
/*
*********************************************************************************************************
* uC/OS-II
* The Real-Time Kernel (by Jean J. Labrosse)
*
* WIN32 PORT
*
* (c) Copyright 2004-... Werner.Zimmermann@fht-esslingen.de
* All Rights Reserved
*
* File : OS_CPU_C.C
* By : Werner Zimmermann
*
* Changes: 1.40 Fixed a bug in OS_log(), thanks to Hu JW. 13 Jul 2004
* 1.50 Substituted DWORD by INT32U, BOOL by BOOLEAN
* 1.60 Changes in the PC_Elapsed... functions in the Cygwin and Linux port. Use direct reads
* for the Pentium time stamp counter. No change in the Visual C++ port.
* 1.70 Changes to OSScheduleThread for detecting tasks deleted by OSTaskDel in the WIN32 port.
* Suggested by Hu JW.
* 2.00 Modifications in the Linux port, no changes in the WIN32 ports, 18 Mar 2005
* 2.10 Include paths modified to work with uCOS-II 2.70
* 3.00 Modifications to work with uCOS-II 2.80, 30 May 2006, OSTimeTickCallback removed,
* made OSTaskIdleHook() and OSTaskCreateHook() instead of OSTCBInitHook() user callable.
*
*********************************************************************************************************
*/
#define OS_PORT_VERSION 300 //Version number of the uCOS-II WIN32 port
/*
*********************************************************************************************************
Includes
*********************************************************************************************************
*/
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <winbase.h>
#include <mmsystem.h>
#include <stdio.h>
#include <stdlib.h>
#if (OS_VERSION <= 270)
#include "os_cpu.h"
#include "os_cfg.h"
#include "ucos_ii.h"
#else
#include "ucos_ii.h"
#endif
/*
*********************************************************************************************************
Global variables
*********************************************************************************************************
*/
HANDLE hScheduleEvent, hScheduleThread; //Scheduler thread variables
HANDLE hTaskThread[OS_LOWEST_PRIO + 2]; //Map uCOS tasks to WIN32 threads
INT8S taskSuspended[OS_LOWEST_PRIO + 2]; //Suspend status of mapped tasks/threads
#define NINTERRUPTS 8 //Number of interrupt events (DO NOT CHANGE)
HANDLE hInterruptEvent[NINTERRUPTS], hInterruptThread; //Interrupt handling thread variables
void (*interruptTable[NINTERRUPTS])();
BOOLEAN virtualInterruptFlag=TRUE;
INT32U interruptThreadId = 0;
CRITICAL_SECTION criticalSection; //Used to protect critical sections
BOOLEAN idleTrigger = TRUE; //Trigger a message, when the idle task is
//invoked (used for debugging purposes)
#define NLOG 16 //Log last scheduled tasks (used for
INT16U taskLog[NLOG]; //... debugging purposes)
/*
*********************************************************************************************************
Port-specific functions
*********************************************************************************************************
*/
// DBGPRINT ******************************************************************
// Debug output
void DBGPRINT(INT32U debugLevel, const char *fmt,...)
{ va_list argptr;
FILE *fd;
if ((debugLevel & DEBUGLEVEL) == 0) //Debug output selection
return;
if (DEBUGLEVEL < 0x10000000UL) //Screen output (does influence real-time performance!)
{ va_start(argptr, fmt);
vprintf(fmt, argptr);
va_end(argptr);
} else //File output (does influence real-time performance!)
{ va_start(argptr, fmt);
if ((fd = fopen("ucos.log","a+"))!=NULL)
{ vfprintf(fd, fmt, argptr);
fclose(fd);
}
va_end(argptr);
}
}
// OSLog *********************************************************************
// Log the last NLOG scheduled tasks in taskLog (with taskLog[0] = last task)
void OSLog(INT16U prio)
{ int i;
for (i=NLOG-1; i > 0; i--) //Shift the previous logged values by one
taskLog[i]=taskLog[i-1];
taskLog[0]=prio; //Log the last one into taskLog[0]
}
// OSPortVersion *************************************************************
// Return the version number of the uCOS-II WIN32 port
INT16U OSPortVersion(void)
{ return OS_PORT_VERSION;
}
BOOLEAN CtrlBreakHandler(INT32U ctrl)
{ if (ctrl==CTRL_C_EVENT) //Handler if CTRL-C is pressed
{ printf("---Exiting OSPrioCur=%u-------------\n", OSPrioCur); //---Display current task priority
} else if (ctrl==CTRL_BREAK_EVENT) //Handler if CTRL-BREAK is pressed
{ printf("---Exiting OSPrioCur=%u-------------\n", OSPrioCur); //---Display current task priority and exit
exit(0);
}
return TRUE;
}
// OSEnableInterruptFlag ****************************************************
// Enable the interrupt flag
void OSEnableInterruptFlag(void)
{
if (virtualInterruptFlag==FALSE) //If the timer interrupt previously was disabled,
{ virtualInterruptFlag=TRUE;
if (GetCurrentThreadId()!=interruptThreadId)
ResumeThread(hInterruptThread); //... resume the interrupt thread
}
DBGPRINT(0x00000080, ">>> ODEnableInterruptFlag %2d\n", virtualInterruptFlag);
}
// OSDisableInterruptFlag ****************************************************
// Disable the Interrupt Flag
void OSDisableInterruptFlag(void)
{
if (virtualInterruptFlag==TRUE) //If the timer interrupt previously was enabled,
{ if (GetCurrentThreadId()!=interruptThreadId) //... suspend the interrupt thread ...
SuspendThread(hInterruptThread);
virtualInterruptFlag=FALSE;
}
DBGPRINT(0x00000080, ">>> OSDisableInterrupts %2d\n", virtualInterruptFlag);
}
void OSDummyISR(void)
{ MessageBox(NULL, "Got unsupported interrupt", "uCOS-II WIN32", MB_OK | MB_SETFOREGROUND | MB_ICONERROR);
}
// OSScheduleThread ***********************************************************
// Start tasks, triggered by hScheduleEvent
void OSScheduleThread(INT32U param)
{ char temp[256];
INT16U oldPrio, nextPrio;
DBGPRINT(0x00000001, "*** OSScheduleThread First Call\n");
while (1)
{ if (WaitForSingleObject(hScheduleEvent, OS_SCHEDULER_TIMEOUT) == WAIT_TIMEOUT) //Wait for a scheduler event (with timeout)
{ sprintf(temp, "ERROR: Scheduler timed out in OSScheduleThread %u --> %u IF=%u <-%u<%u<%u<%u<%u<%u<%u<%u<-\n",
OSPrioCur, OSPrioHighRdy, virtualInterruptFlag,
taskLog[0], taskLog[1], taskLog[2], taskLog[3],
taskLog[4], taskLog[5], taskLog[6], taskLog[7]
);
DBGPRINT(0x00000040, temp);
MessageBox(NULL, temp, "UCOS-II WIN32", MB_OK | MB_SETFOREGROUND | MB_ICONERROR); //In case of timeout, display an error message ...
OSRunning=0;
SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlBreakHandler, FALSE);
return; //... and exit (will return to OSStartHighRdy())
}
OSTaskSwHook(); //Call the task switch hook function
EnterCriticalSection(&criticalSection);
oldPrio = OSPrioCur;
nextPrio = OSPrioHighRdy;
OSTCBCur = OSTCBHighRdy; //Now logically switch to the new task
OSPrioCur = OSPrioHighRdy;
idleTrigger = TRUE;
DBGPRINT(0x00000001, "*** OSScheduleThread from %2u to %2u\n", oldPrio, nextPrio);
if (OSTCBPrioTbl[oldPrio] == NULL) //If a task has been deleted
{ if (hTaskThread[oldPrio]) //... remove it
{ TerminateThread(hTaskThread[oldPrio], 0);
CloseHandle(hTaskThread[oldPrio]);
}
hTaskThread[oldPrio] = NULL;
taskSuspended[oldPrio]=0;
} else if (oldPrio != nextPrio && taskSuspended[oldPrio]==0) //If switching context to a new task ...
{ SuspendThread(hTaskThread[oldPrio]); //... suspend the thread associated with the current task
taskSuspended[oldPrio]++; //(update suspend counter to avoid multiple suspends of the same task)
}
if (taskSuspended[nextPrio])
{ taskSuspended[nextPrio]--; //(updates suspend counter to avoid multiple resumes of the same task)
if (taskSuspended[nextPrio] < 0)
taskSuspended[nextPrio]=0;
if (virtualInterruptFlag==FALSE)
OSEnableInterruptFlag();
OSLog(nextPrio);
ResumeThread(hTaskThread[nextPrio]); //... and resume the thread associated with the new task
} else
{ if (virtualInterruptFlag==FALSE)
OSEnableInterruptFlag();
}
LeaveCriticalSection(&criticalSection);
}
}
// OSInterruptThread **********************************************************
// Time tick interrupt processing
void OSInterruptThread(INT32U param)
{ char temp[256];
INT32U eventType;
DBGPRINT(0x00000001, "*** OSInterruptThread First Call\n");
while (1)
{ //if (WaitForSingleObject(hInterruptEvent, OS_INTERRUPT_TIMEOUT) == WAIT_TIMEOUT) //Wait for a timer interrupt event
eventType=WaitForMultipleObjects(NINTERRUPTS, hInterruptEvent, FALSE, OS_INTERRUPT_TIMEOUT);
if (eventType == WAIT_TIMEOUT) //Wait for a timer interrupt event
{ sprintf(temp, "ERROR: Interrupt timed out in OSInterruptThread IF=%u\n", virtualInterruptFlag);
DBGPRINT(0x00000040, temp);
MessageBox(NULL, temp, "UCOS-II WIN32", MB_OK | MB_SETFOREGROUND | MB_ICONERROR); //In case of timeout, display an error message ...
OSRunning=0;
SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlBreakHandler, FALSE);
exit(-1); //... and exit
}
EnterCriticalSection(&criticalSection);
DBGPRINT(0x00000001, "*** OSInterruptThread\n");
if (virtualInterruptFlag==FALSE)
DBGPRINT(0x00000001, "*** virtualInteruptFlag disabled when calling OSInterruptThread XXX %d\n", virtualInterruptFlag);
DBGPRINT(0x00000001, "--- OSIntEnter\n");
OSIntEnter();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -