Tab. 1. Błędy logiczne sygnalizowane wyjątkami
Klasa wyjątku | Opis |
logic_error | Klasa bazowa dla pozostałych błędów logicznych wywodząca się z exception. |
domain_error | Liczba poza dziedziną. |
invalid_argument | Błędny argument przekazany do funkcji. |
length_error | Błąd rozmiaru. Np przy próbie zmiany rozmiaru wektora. |
out_of range | Wartość poza zakresem. |
Tab. 2. Błędy wykonania sygnalizowane wyjątkami
Klasa wyjątku | Opis |
runtime_error | Klasa bazowa dla pozostałych błędów wykonania wywodząca się z exception. |
range_error | Błąd zakresu. |
overflow_error | Błąd przepełnienia. |
underflow_error | Błąd niedomiaru. |
Oczywiście każdy z tych wyjątków może być zgłaszany nie tylko przez bibliotekę standardową, ale także przez kod użytkownika. Bazując na powyższych klasach, hierarchia wyjątków może być rozbudowywana w razie potrzeb przez użytkownika.
Przykład praktyczny: obsługa wyjątków w ISIX-RTOS
Po zapoznaniu się z podstawowymi wiadomościami teoretycznymi na temat wyjątków w C++ , pokażemy, że mogą być stosowane z powodzeniem również w przypadku nieco większych mikrokontrolerów. Pozwalając na znaczące podniesienie niezawodności działania programu, oraz przy stosowaniu z umiarem zapewniają również podniesienie ogólnej wydajności aplikacji.
Posłużmy się teraz prostym przykładem (platforma STM32Butterfly), w którym jeden wątek będzie odpowiedzialny za mruganie diodą D1, i sygnalizował będzie jedynie prawidłowe działanie systemu operacyjnego. Natomiast drugi wątek, będzie zmieniał stan diody D2 na przeciwny w przypadku wciśnięcia klawisza joysticka OK. W przypadku wciśnięcia klawisza DOWN, lub UP, zgłaszany będzie wyjątek, który będzie symulował wystąpienie, błędu. Dodatkowo na linii PE0 wystawiany będzie stan 1 przez czas od momentu zgłoszenia wyjątku, do jego przechwycenia co pozwoli na zbadanie ogólnej wydajności obsługi wyjątków w GCC na architekturze CORTEX-M3. Kod programu przedstawiono na poniższym listingu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
namespace app { class ledblink: public isix::task_base { public: //Constructor ledblink() : task_base(STACK_SIZE,TASK_PRIO), LED_PORT(GPIOE) { using namespace stm32; //Enable PE in APB2 RCC->APB2ENR |= RCC_APB2Periph_GPIOE; io_config(LED_PORT,LED_PIN,GPIO_MODE_10MHZ,GPIO_CNF_GPIO_PP); } protected: //Main function virtual void main() { while(true) { //Enable LED stm32::io_clr( LED_PORT, LED_PIN ); //Wait time isix::isix_wait( isix::isix_ms2tick(BLINK_TIME) ); //Disable LED stm32::io_set( LED_PORT, LED_PIN ); //Wait time isix::isix_wait( isix::isix_ms2tick(BLINK_TIME) ); } } private: static const unsigned STACK_SIZE = 256; static const unsigned TASK_PRIO = 3; GPIO_TypeDef * const LED_PORT; static const unsigned LED_PIN = 14; static const unsigned BLINK_TIME = 500; }; /* ------------------------------------------------------------------ */ class ledkey: public isix::task_base { public: //Constructor ledkey() : task_base(STACK_SIZE,TASK_PRIO), is_enabled(false), KEY_PORT(GPIOE), LED_PORT(GPIOE) { using namespace stm32; //Enable PE in APB2 RCC->APB2ENR |= RCC_APB2Periph_GPIOE; io_config(LED_PORT,LED_PIN,GPIO_MODE_10MHZ,GPIO_CNF_GPIO_PP); io_config(LED_PORT,NOTIFY_PIN,GPIO_MODE_10MHZ,GPIO_CNF_GPIO_PP); } protected: //Main function virtual void main() { //Last key state bool state = true; //Task/thread main loop try { while(true) { execute_keycheck(state); } } catch( int &val) { stm32::io_clr( LED_PORT,NOTIFY_PIN ); dbprintf("INT exception [%d]", val); } catch( const std::exception &e ) { stm32::io_clr( LED_PORT,NOTIFY_PIN ); dbprintf("std::exception [%s]", e.what()); } } private: //Execute keycheck function void execute_keycheck(bool &p_state) { //Change state on rising edge if(stm32::io_get(KEY_PORT, KEY_PIN) && !p_state) { is_enabled = !is_enabled; } //Get previous state p_state = stm32::io_get(KEY_PORT, KEY_PIN); //If enabled change state if(is_enabled) stm32::io_clr( LED_PORT, LED_PIN ); else stm32::io_set( LED_PORT, LED_PIN ); //Wait short time isix::isix_wait( isix::isix_ms2tick(DELAY_TIME) ); if( !stm32::io_get(KEY_PORT, KEY_RAISE_LOGIC )) { /** From raise to catch 151us **/ stm32::io_set( LED_PORT,NOTIFY_PIN ); throw(std::logic_error("critical error raised")); } if( !stm32::io_get(KEY_PORT, KEY_RAISE_INT )) { /** From raise to catch 108us **/ stm32::io_set( LED_PORT,NOTIFY_PIN ); throw(-1); } } private: static const unsigned STACK_SIZE = 2048; static const unsigned TASK_PRIO = 3; bool is_enabled; GPIO_TypeDef * const KEY_PORT; GPIO_TypeDef * const LED_PORT; static const unsigned LED_PIN = 15; static const unsigned KEY_PIN = 8; static const unsigned NOTIFY_PIN = 0; static const unsigned KEY_RAISE_LOGIC = 9; static const unsigned KEY_RAISE_INT = 10; static const unsigned DELAY_TIME = 25; }; } /* ------------------------------------------------------------------ */ //App main entry point int main() { dblog_init( stm32::usartsimple_putc, NULL, stm32::usartsimple_init, USART2,115200,true, config::PCLK1_HZ, config::PCLK2_HZ ); dbprintf(" Exceptions presentation app using ISIXRTOS "); //The blinker class static app::ledblink led_blinker; //The ledkey class static app::ledkey led_key; //Start the isix scheduler isix::isix_start_scheduler(); } |