/************************************************************************** Главный заголовочный файл для матлаба. Включает дейфайны для S-Function, объявляет базовые функции для симуляции МК и подключает базовые библиотеки: для S-Function "simstruc.h" для МК "main.h" для симуляции "stm32f4xx_matlab_conf.h" **************************************************************************/ #ifndef _CONTROLLER_H_ #define _CONTROLLER_H_ typedef void* HANDLE; #include "mcu_wrapper_conf.h" // For stm simulate functions #include "simstruc.h" // For S-Function variables #include // For threads // Parameters of S_Function #define NPARAMS 1 // number of input parametrs (only Ts) #define PORT_WIDTH 16 // width of one port #define PORT_NUMB 2 // amount of ports // Parametrs of MCU simulation #define MAX_STACK_SIZE 0xFFFF // If stack is bigger than this number - exit simulations. #define MAX_WHILE_TIMEOUT 0xFFF // timeout for while. If after this amount of cycles app stil in while - stop app and go to wrapper #define TIME_FOR_MCU_APP 0xFF // /** MCU HANDLE STRUCTURE */ /** * @brief MCU handle Structure definition. * @var pStackPtr_Origin - pointer to the "beginning" of the stack (RSP before go to MCU app) * @vars Main stop context - context of MCU app at stop point. Included: registers, pointer to stack and saved stack. * @var Main start context - context of wrapper, before go to MCU app @ref setjmp/longjmp. * @vars Flags and counters - flags and counter that control MCU app. * @note Do not change stucrure before Stack_Buff, the assembly code uses fixed address offsets. */ typedef struct _DEL_MCUHandleTypeDef { uint64_t* pStackPtr_Origin; /* указатель на "начало" стека - конец стека у управляющей МКом функции */ // Main stop context _JUMP_BUFFER REGS; /* регистры во время приостановки программы МК */ int long Stack_Size; /* размер стека - от "начала" до "верхнушки" */ uint64_t* pStackPtr_Current; /* указатель на последний элемент стека */ uint64_t Stack_Buff[MAX_STACK_SIZE]; /* содержимое стека от "начала" до "верхнушки" во время приостановки */ // Main start context jmp_buf main_start; /* буффер, для выхода из программы МК - longjmp(main_start) */ // Flags and counters int While_Timeout; /* счетчик, после истечения которого while прерывается */ unsigned Stop_MCU_App : 1; /* флаг для остановки программы МК */ unsigned Resume_MCU_App : 1; /* флаг для возобновления работы программы МК */ unsigned Get_RSP_Origin : 1; /* флаг для получения указателя на "начало" стека */ }DEL_MCUHandleTypeDef; extern DEL_MCUHandleTypeDef hmcu; /* extern для видимости переменной во всех файлах */ // Variable for param of S-Function extern double SIM_Sample_Time; // sample time //-------------------------------------------------------------// //------------------- SAVE CONTEXT DEFINES ------------------// /** SAVE STACK */ /** * @brief Save stack of running program. * @param _hmcu_ - MCU Handle structure with registers and stack buff for filling. * * @code @ref _SAVE_STACK_CODE_ to see for replace _SAVE_STACK_ macros (for debug). */ #define _SAVE_STACK_(_hmcu_) if(1){ \ /* Сброс индекса буфера для стека */ _hmcu_.Stack_Size = 0; \ /* Пока весь необходимый стек не сохранен */ native_while( _hmcu_.pStackPtr_Current != _hmcu_.pStackPtr_Origin) \ /* Если буфер не переполнен: */ if(_hmcu_.Stack_Size <= MAX_STACK_SIZE) \ /* Сохранение стека */ _hmcu_.Stack_Buff[_hmcu_.Stack_Size++] = *_hmcu_.pStackPtr_Current++; \ /* Если буфер переполнен: */ else { \ /* Сообщение об ошибке и выход из программы */ printf("Max stack size is reached\n"); \ exit(0); \ }}else /***************************************************************/ /** SAVE PROGRAMM COUNTER */ /** * @brief Save programm counter (RIP register) of running program. * @param _hmcu_ - MCU Handle structure with registers and stack buff for filling * @note Используется вместе с @ref _SAVE_CONTEXT_ для определения точки возврата. * Вызывается до или после _SAVE_CONTEXT_, как вам нужно. * @ret Store address of next instruction after this macros in Rip */ #define _SAVE_RIP_(_hmcu_) _hmcu_.REGS.Rip = getNextAddr() /***************************************************************/ //------------------- SAVE CONTEXT DEFINES ------------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //------------------ SIMULINK WHILE DEFINES -----------------// /** DEFINE TO WHILE WITH SIMULINK WHILE */ /** * @brief Redefine C while statement with sim_while() macro. * @param _expression_ - expression for while. * @note @ref sim_while для подробностей. */ #define while(_expression_) sim_while(_expression_) /* while который будет использоваться в симулинке */ /** DEFAULT WHILE */ /** * @brief Default/Native C while statement. * @param _expression_ - expression for while. * @note Данный while - аналог обычного while, без дополнительного функционала. */ #define native_while(_expression_) for(; (_expression_); ) /***************************************************************/ /** SIMULINK WHILE */ /** * @brief While statement for emulate MCU code in Simulink. * @param _expression_ - expression for while. * @note Данный while, при условии, что программа в него входит (_expression_ != 0) * сохраняет контекст программы и устанавливает таймаут (определенное кол-во циклов). * Если таймаут истекает происходит прерывание программы. И она возвращается в оболочку, * которая перейдет на следующий такт и снова попробует пройти условие. И так далее * Таким образом программа МК зависнет на этом while, но перефирия продолжит работать. * * @code @ref sim_while_CODE_ to see for replace while sim_while (for debug). */ extern unsigned flag_to_end; #define sim_while(_expression_) while((_expression_)&&(flag_to_end == 0)) //#define sim_while(_expression_) while(0);if(_expression_&&(hmcu.While_Timeout>-5)){ \ ///* Установка таймаута для while */ hmcu.While_Timeout = MAX_WHILE_TIMEOUT; \ // } \ ///* Цикл while - for(;_expression_;) */ native_while(_expression_) \ ///* Если таймаут истек */ if(hmcu.While_Timeout-- < 0 ) { \ ///* Cброс таймаута, чтобы на след шаге войти в тело цикла */ hmcu.While_Timeout = 0; \ ///* Установка флага для остановки программы */ hmcu.Stop_MCU_App = 1; \ ///* Установка флага для возврата в код МК на след шаге */ hmcu.Resume_MCU_App = 1; \ ///* Сохранение контекста */ saveProgramContext(); \ // if(hmcu.Stop_MCU_App) \ ///* Возврат в оболочку */ longjmp(hmcu.main_start, 1); \ // } \ ///* Иначе - выполнение тела цикла */ else //------------------ SIMULINK WHILE DEFINES -----------------// //-------------------------------------------------------------// //-------------------------------------------------------------// //---------------- SIMULATE FUNCTIONS PROTOTYPES -------------// /** MCU STEP SIMULATION */ /** * @brief Read from simulink S-Block Inputs and write to MCU I/O ports. * @param in - inputs of S-Function. * @param disc - discrete array of S-Function. Outputs would be written from disc. * @param time - current time of simulation (in second). * @note Вызывает главную функцию main из пользовательского кода и управляет её ходом: * Прерывает её, если она попала в бесконечный while, симулирует периферию * и возвращает в точку остановки на следующем шаге. */ /* simulate controller step */ void MCU_Step_Simulation(SimStruct *S, const real_T *in, real_T *disc, time_T time); /* step simulation */ /** SIMULATE MCU PERIPHERAL */ /** * @brief Simulate peripheral of MCU * @note Пользовательский код, который симулирует работу периферии МК. */ void MCU_Periph_Simulation(void); /* MCU peripheral simulation */ /** MCU WRAPPER INITIALIZATION */ /** * @brief Initialize structures and variables for simulating MCU. * @note Пользовательский код, который будет настраивать все структуры. */ void SIM_Initialize_Simulation(void); /* initialize MCU simulation */ /** MCU WRAPPER DEINITIALIZATION */ /** * @brief Deinitialize structures and variables for simulating MCU. * @note Пользовательский код, который будет очищать все структуры. */ void SIM_deInitialize_Simulation(void); /* SIM_deInitialize_Simulation MCU simulation */ /** READ INPUTS S-FUNCTION */ /** * @brief Read from simulink S-Block Inputs and write to MCU I/O ports. * @param in - inputs of S-Function. * @note Пользовательский код, который записывает в порты ввода-вывода из disc. */ void MCU_readInputs(real_T* in); /** WRITE OUTPUTS S-FUNCTION */ /** * @brief Read from MCU I/O ports and write to simulink S-Block Outputs. * @param disc - discrete array of S-Function. Outputs would be written from disc. * @note Пользовательский код, который записывает в disc порты ввода-вывода. */ void MCU_writeOutputs(real_T* disc); /** SAVE CONTEXT OF PROGRAMM */ /** * @brief Save context (stack, registers) of running program. * @note Данная функция устанавливает счетчик комманд на начало функции. * Так что возврат будет произведен в начало этой функции. */ void saveProgramContext(void); /** GET NEXT INSTRUCTION ADDRESS */ /** * @brief Gives the address where this function will return. */ void* getNextAddr(void); //---------------- SIMULATE FUNCTIONS PROTOTYPES -------------// //-------------------------------------------------------------// #endif // _CONTROLLER_H_ /** MACROSES REPLACEMENT CODE */ /** _SAVE_STACK_CODE_ * CODE TO REPLACE _SAVE_STACK_() MACROS (FOR DEBUG) */ /* hmcu.Stack_Size = 0; // Сброс индекса буфера для стека // Пока весь необходимый стек не сохранен native_while(hmcu.pStackPtr_Current != hmcu.pStackPtr_Origin) if (hmcu.Stack_Size <= MAX_STACK_SIZE) // Если буфер не переполнен hmcu.Stack_Buff[hmcu.Stack_Size++] = *hmcu.pStackPtr_Current++; // Сохранение стека else { // Если буфер переполнен printf("Max stack size is reached\n"); // Сообщение об ошибке и выход из программы exit(0); } */ /***************************************************************/ /** sim_while_CODE_ * CODE TO REPLACE sim_while() MACROS (FOR DEBUG) */ /* while(0);if(_expression_&&(hmcu.While_Timeout>-5)){ hmcu.While_Timeout = MAX_WHILE_TIMEOUT; // Установка таймаута для while } native_while(_expression_) // Цикл while - for(;_expression_;) if (hmcu.While_Timeout-- < 0) { // Если таймаут истек hmcu.While_Timeout = 0; // Сброс таймаута, чтобы на след шаге войти в тело цикла hmcu.Stop_MCU_App = 1; // Установка флага для остановки программы hmcu.Resume_MCU_App = 1; // Установка флага для возврата в код МК на след шаге saveProgramContext(); // Сохранение контекста if(hmcu.Stop_MCU_App) // Если приложение было остановлено longjmp(hmcu.main_start, 1); // Возврат в оболочку // иначе (при возвращении в код МК) продолжить выполнение кода } else // Иначе - выполнение тела цикла */ /***************************************************************/