├── 007ClockAlarm_V2.zip ├── Course_Exercises ├── 001LightControlMealy │ └── 001LightControlMealy.ino ├── 002LightControlMoore │ └── 002LightControlMoore.ino ├── 003Protimer │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── src │ │ ├── lcd.cpp │ │ ├── lcd.h │ │ ├── main.cpp │ │ ├── main.h │ │ └── protimer_state_mach.cpp │ └── test │ │ └── README ├── 004Protimer_SH │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── src │ │ ├── lcd.cpp │ │ ├── lcd.h │ │ ├── main.cpp │ │ ├── main.h │ │ └── protimer_state_mach.cpp │ └── test │ │ └── README ├── 005Protimer_ST │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── src │ │ ├── lcd.cpp │ │ ├── lcd.h │ │ ├── main.cpp │ │ ├── main.h │ │ └── protimer_state_mach.cpp │ └── test │ │ └── README ├── 006QHsmTest │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── qm │ │ ├── .qhsmtst │ │ └── qhsmtst.qm │ ├── src │ │ ├── QHSM_Test.cpp │ │ ├── QHSM_Test.h │ │ ├── bsp.cpp │ │ ├── bsp.h │ │ └── main.cpp │ └── test │ │ └── README ├── 007ClockAlarm │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── qm │ │ ├── .ClockAlarm │ │ └── ClockAlarm.qm │ ├── src │ │ ├── ClockAlarm_SM.cpp │ │ ├── ClockAlarm_SM.h │ │ ├── lcd.cpp │ │ ├── lcd.h │ │ ├── main.cpp │ │ └── main.h │ └── test │ │ └── README ├── 008ClockAlarm_AO │ ├── .gitignore │ ├── .vscode │ │ └── extensions.json │ ├── include │ │ └── README │ ├── lib │ │ └── README │ ├── platformio.ini │ ├── qm │ │ ├── .ClockAlarm │ │ └── ClockAlarm.qm │ ├── src │ │ ├── ClockAlarm_SM.cpp │ │ ├── ClockAlarm_SM.h │ │ ├── alarm.cpp │ │ ├── alarm.h │ │ ├── button_SM.cpp │ │ ├── button_SM.h │ │ ├── lcd.cpp │ │ ├── lcd.h │ │ ├── main.cpp │ │ └── main.h │ └── test │ │ └── README ├── ClockAlarm_SM_TODO.cpp └── workspace.code-workspace ├── EmbeddedUMLStateMachines.pdf ├── LICENSE ├── README.md └── protimer_v1.pdf /007ClockAlarm_V2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niekiran/EmbeddedUMLStateMachines/50021be17ab068f87d13522036ce20316effe1c5/007ClockAlarm_V2.zip -------------------------------------------------------------------------------- /Course_Exercises/001LightControlMealy/001LightControlMealy.ino: -------------------------------------------------------------------------------- 1 | 2 | enum event{ 3 | ON, 4 | OFF 5 | }; 6 | 7 | typedef enum { 8 | LIGHT_OFF, 9 | LIGHT_DIM, 10 | LIGHT_MEDIUM, 11 | LIGHT_FULL 12 | }light_state_t; 13 | 14 | light_state_t curr_state = LIGHT_OFF; 15 | 16 | 17 | #define PIN_LED 9 18 | 19 | #define LIGHT_BRIGHT_DIM 25 20 | #define LIGHT_BRIGHT_MED 85 21 | #define LIGHT_BRIGHT_FULL 255 22 | #define LIGHT_BRIGHT_OFF 0 23 | 24 | void light_state_machine(uint8_t event); 25 | void light_change_intensity(uint8_t pin, uint8_t intensity); 26 | 27 | void setup() { 28 | // put your setup code here, to run once: 29 | Serial.begin(115200); 30 | Serial.println("Light control application"); 31 | Serial.println("-------------------------"); 32 | Serial.println("Send 'x' or 'o'"); 33 | } 34 | 35 | void loop() { 36 | uint8_t event; 37 | // put your main code here, to run repeatedly: 38 | if(Serial.available() > 0){ 39 | event = Serial.read(); 40 | if(event == 'o'){ 41 | light_state_machine(ON); 42 | }else if(event == 'x'){ 43 | light_state_machine(OFF); 44 | } 45 | } 46 | 47 | } 48 | 49 | void light_state_machine(uint8_t event) 50 | { 51 | 52 | switch(curr_state) 53 | { 54 | case LIGHT_OFF:{ 55 | switch(event){ 56 | case ON:{ 57 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_DIM); 58 | curr_state = LIGHT_DIM; 59 | break; 60 | } 61 | } 62 | break; 63 | } 64 | case LIGHT_DIM:{ 65 | switch(event){ 66 | case ON:{ 67 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_MED); 68 | curr_state = LIGHT_MEDIUM; 69 | break; 70 | } 71 | case OFF:{ 72 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_OFF); 73 | curr_state = LIGHT_OFF; 74 | break; 75 | } 76 | } 77 | break; 78 | } 79 | case LIGHT_MEDIUM:{ 80 | switch(event){ 81 | case ON:{ 82 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_FULL); 83 | curr_state = LIGHT_FULL; 84 | break; 85 | } 86 | case OFF:{ 87 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_OFF); 88 | curr_state = LIGHT_OFF; 89 | break; 90 | } 91 | } 92 | break; 93 | } 94 | case LIGHT_FULL:{ 95 | switch(event){ 96 | case ON:{ 97 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_DIM); 98 | curr_state = LIGHT_DIM; 99 | break; 100 | } 101 | case OFF:{ 102 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_OFF); 103 | curr_state = LIGHT_OFF; 104 | break; 105 | } 106 | } 107 | break; 108 | } 109 | } 110 | } 111 | 112 | void light_change_intensity(uint8_t pin, uint8_t intensity) 113 | { 114 | analogWrite(pin,intensity); 115 | } 116 | -------------------------------------------------------------------------------- /Course_Exercises/002LightControlMoore/002LightControlMoore.ino: -------------------------------------------------------------------------------- 1 | 2 | enum event{ 3 | ON, 4 | OFF, 5 | }; 6 | 7 | typedef enum { 8 | LIGHT_OFF, 9 | LIGHT_DIM, 10 | LIGHT_MEDIUM, 11 | LIGHT_FULL 12 | }light_state_t; 13 | 14 | light_state_t curr_state; 15 | 16 | 17 | #define PIN_LED 9 18 | 19 | #define LIGHT_BRIGHT_DIM 25 20 | #define LIGHT_BRIGHT_MED 85 21 | #define LIGHT_BRIGHT_FULL 255 22 | #define LIGHT_BRIGHT_OFF 0 23 | 24 | void light_state_machine(uint8_t event); 25 | void light_change_intensity(uint8_t pin, uint8_t intensity); 26 | void run_entry_action(light_state_t state); 27 | 28 | void light_init(void) 29 | { 30 | curr_state = LIGHT_OFF; 31 | run_entry_action(LIGHT_OFF); 32 | } 33 | void setup() { 34 | // put your setup code here, to run once: 35 | Serial.begin(115200); 36 | Serial.println("Light control application"); 37 | Serial.println("-------------------------"); 38 | Serial.println("Send 'x' or 'o'"); 39 | 40 | light_init(); 41 | } 42 | 43 | void loop() { 44 | uint8_t event; 45 | // put your main code here, to run repeatedly: 46 | if(Serial.available() > 0){ 47 | event = Serial.read(); 48 | if(event == 'o'){ 49 | light_state_machine(ON); 50 | }else if(event == 'x'){ 51 | light_state_machine(OFF); 52 | } 53 | } 54 | 55 | } 56 | 57 | void light_state_machine(uint8_t event) 58 | { 59 | light_state_t prev_state; 60 | 61 | prev_state = curr_state; 62 | switch(curr_state) 63 | { 64 | case LIGHT_OFF:{ 65 | switch(event){ 66 | case ON:{ 67 | curr_state = LIGHT_DIM; 68 | break; 69 | } 70 | } 71 | break; 72 | } 73 | case LIGHT_DIM:{ 74 | switch(event){ 75 | case ON:{ 76 | curr_state = LIGHT_MEDIUM; 77 | break; 78 | } 79 | case OFF:{ 80 | curr_state = LIGHT_OFF; 81 | break; 82 | } 83 | } 84 | break; 85 | } 86 | case LIGHT_MEDIUM:{ 87 | switch(event){ 88 | case ON:{ 89 | curr_state = LIGHT_FULL; 90 | break; 91 | } 92 | case OFF:{ 93 | curr_state = LIGHT_OFF; 94 | break; 95 | } 96 | } 97 | break; 98 | } 99 | case LIGHT_FULL:{ 100 | switch(event){ 101 | case ON:{ 102 | curr_state = LIGHT_DIM; 103 | break; 104 | } 105 | case OFF:{ 106 | curr_state = LIGHT_OFF; 107 | break; 108 | } 109 | } 110 | break; 111 | } 112 | } 113 | 114 | if(prev_state != curr_state) 115 | run_entry_action(curr_state); 116 | } 117 | 118 | void run_entry_action(light_state_t state) 119 | { 120 | switch(state) 121 | { 122 | case LIGHT_OFF:{ 123 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_OFF); 124 | break; 125 | } 126 | case LIGHT_DIM:{ 127 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_DIM); 128 | break; 129 | } 130 | case LIGHT_MEDIUM:{ 131 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_MED); 132 | break; 133 | } 134 | case LIGHT_FULL:{ 135 | light_change_intensity(PIN_LED,LIGHT_BRIGHT_FULL); 136 | break; 137 | } 138 | } 139 | } 140 | 141 | void light_change_intensity(uint8_t pin, uint8_t intensity) 142 | { 143 | analogWrite(pin,intensity); 144 | } 145 | -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:uno] 12 | platform = atmelavr 13 | board = uno 14 | framework = arduino 15 | monitor_speed = 115200 16 | lib_deps = arduino-libraries/LiquidCrystal@^1.0.7 17 | -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/src/lcd.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "lcd.h" 4 | #include "main.h" 5 | #include 6 | 7 | LiquidCrystal lcd(PIN_LCD_RS,PIN_LCD_RW,PIN_LCD_EN,PIN_LCD_D4,PIN_LCD_D5,PIN_LCD_D6,PIN_LCD_D7); 8 | 9 | void lcd_clear(void){ 10 | lcd.clear(); 11 | } 12 | void lcd_print_char(char c){ 13 | lcd.print(c); 14 | } 15 | 16 | void lcd_scroll_left(void){ 17 | lcd.scrollDisplayLeft(); 18 | } 19 | void lcd_scroll_right(void){ 20 | lcd.scrollDisplayRight(); 21 | } 22 | void lcd_set_cursor(int c, int r){ 23 | lcd.setCursor(c,r); 24 | } 25 | void lcd_no_auto_scroll(void){ 26 | lcd.noAutoscroll(); 27 | } 28 | void lcd_begin(uint8_t cols , uint8_t rows){ 29 | lcd.begin(cols,rows); 30 | } 31 | void lcd_move_cursor_R_to_L(void){ 32 | lcd.rightToLeft(); 33 | } 34 | void lcd_move_cursor_L_to_R(void){ 35 | lcd.leftToRight(); 36 | } 37 | void lcd_cursor_off(void){ 38 | lcd.noCursor(); 39 | } 40 | void lcd_cursor_blinkoff(void){ 41 | lcd.noBlink(); 42 | } 43 | void lcd_print_number(int num){ 44 | lcd.print(num); 45 | } 46 | void lcd_print_string(String s){ 47 | lcd.print(s); 48 | } -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/src/lcd.h: -------------------------------------------------------------------------------- 1 | #ifndef LCD_H 2 | #define LCD_H 3 | #include 4 | 5 | void lcd_clear(void); 6 | void lcd_print_char(char c); 7 | void lcd_scroll_left(void); 8 | void lcd_scroll_right(void); 9 | void lcd_set_cursor(int c, int r); 10 | void lcd_no_auto_scroll(void); 11 | void lcd_begin(uint8_t cols, uint8_t rows); 12 | void lcd_move_cursor_R_to_L(void); 13 | void lcd_move_cursor_L_to_R(void); 14 | void lcd_cursor_off(void); 15 | void lcd_cursor_blinkoff(void); 16 | void lcd_print_number(int num); 17 | void lcd_print_string(String s); 18 | 19 | #endif -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "main.h" 4 | #include "lcd.h" 5 | 6 | static void protimer_event_dispatcher(protimer_t *const mobj,event_t const *const e); 7 | static uint8_t process_button_pad_value(uint8_t btn_pad_value); 8 | static void display_init(void); 9 | 10 | /*Main application object */ 11 | static protimer_t protimer; 12 | 13 | void setup() { 14 | // put your setup code here, to run once: 15 | Serial.begin(115200); 16 | display_init(); 17 | Serial.println("Productive timer application"); 18 | Serial.println("==========================="); 19 | pinMode(PIN_BUTTON1,INPUT); 20 | pinMode(PIN_BUTTON2,INPUT); 21 | pinMode(PIN_BUTTON3,INPUT); 22 | 23 | protimer_init(&protimer); 24 | } 25 | 26 | void loop() { 27 | 28 | uint8_t b1,b2,b3,btn_pad_value; 29 | protimer_user_event_t ue; 30 | static uint32_t current_time = millis(); 31 | static protimer_tick_event_t te; 32 | 33 | //1. read the button pad status 34 | b1 = digitalRead(PIN_BUTTON1); 35 | b2 = digitalRead(PIN_BUTTON2); 36 | b3 = digitalRead(PIN_BUTTON3); 37 | 38 | btn_pad_value = (b1<<2)|(b2<<1)|b3; 39 | 40 | //software button de-bouncing 41 | btn_pad_value = process_button_pad_value(btn_pad_value); 42 | 43 | //2. make an event 44 | if(btn_pad_value){ 45 | if(btn_pad_value == BTN_PAD_VALUE_INC_TIME){ 46 | ue.super.sig = INC_TIME; 47 | }else if(btn_pad_value == BTN_PAD_VALUE_DEC_TIME){ 48 | ue.super.sig = DEC_TIME; 49 | }else if(btn_pad_value == BTN_PAD_VALUE_SP){ 50 | ue.super.sig = START_PAUSE; 51 | }else if(btn_pad_value == BTN_PAD_VALUE_ABRT){ 52 | ue.super.sig = ABRT; 53 | } 54 | //3. send it to event dispatcher 55 | protimer_event_dispatcher(&protimer,&ue.super); 56 | } 57 | 58 | //4. dispatch the time tick event for every 100ms 59 | if(millis() - current_time >= 100){ 60 | //100ms has passed 61 | current_time = millis(); 62 | te.super.sig = TIME_TICK; 63 | if(++te.ss > 10) te.ss = 1; 64 | protimer_event_dispatcher(&protimer,&te.super); 65 | } 66 | 67 | } 68 | 69 | 70 | static void protimer_event_dispatcher(protimer_t *const mobj,event_t const *const e){ 71 | 72 | event_status_t status; 73 | protimer_state_t source, target; 74 | 75 | source = mobj->active_state; 76 | status = protimer_state_machine(mobj,e); 77 | 78 | if(status == EVENT_TRANSITION){ 79 | target = mobj->active_state; 80 | event_t ee; 81 | //1. run the exit action for the source state 82 | ee.sig = EXIT; 83 | mobj->active_state = source; 84 | protimer_state_machine(mobj,&ee); 85 | 86 | //2. run the entry action for the target state 87 | ee.sig = ENTRY; 88 | mobj->active_state = target; 89 | protimer_state_machine(mobj,&ee); 90 | } 91 | 92 | } 93 | 94 | 95 | static uint8_t process_button_pad_value(uint8_t btn_pad_value) 96 | { 97 | static button_state_t btn_sm_state = NOT_PRESSED; 98 | static uint32_t curr_time = millis(); 99 | 100 | switch(btn_sm_state){ 101 | case NOT_PRESSED:{ 102 | if(btn_pad_value){ 103 | btn_sm_state = BOUNCE; 104 | curr_time = millis(); 105 | } 106 | break; 107 | } 108 | case BOUNCE:{ 109 | if(millis() - curr_time >= 50 ){ 110 | //50ms has passed 111 | if(btn_pad_value){ 112 | btn_sm_state = PRESSED; 113 | return btn_pad_value; 114 | } 115 | else 116 | btn_sm_state = NOT_PRESSED; 117 | } 118 | break; 119 | } 120 | case PRESSED:{ 121 | if(!btn_pad_value){ 122 | btn_sm_state = BOUNCE; 123 | curr_time = millis(); 124 | } 125 | break; 126 | } 127 | 128 | } 129 | 130 | return 0; 131 | } 132 | 133 | static void display_init(void) 134 | { 135 | lcd_begin(16,2); 136 | lcd_clear(); 137 | lcd_move_cursor_L_to_R(); 138 | lcd_set_cursor(0,0); 139 | lcd_no_auto_scroll(); 140 | lcd_cursor_off(); 141 | } -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/src/main.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MAIN_H 3 | #define MAIN_H 4 | 5 | #include 6 | 7 | 8 | #define PIN_BUTTON1 2 9 | #define PIN_BUTTON2 3 10 | #define PIN_BUTTON3 4 11 | #define PIN_BUZZER 12 12 | 13 | //lcd connections 14 | #define PIN_LCD_RS 5 15 | #define PIN_LCD_RW 6 16 | #define PIN_LCD_EN 7 17 | #define PIN_LCD_D4 8 18 | #define PIN_LCD_D5 9 19 | #define PIN_LCD_D6 10 20 | #define PIN_LCD_D7 11 21 | 22 | #define BTN_PAD_VALUE_INC_TIME 4 23 | #define BTN_PAD_VALUE_DEC_TIME 2 24 | #define BTN_PAD_VALUE_ABRT 6 25 | #define BTN_PAD_VALUE_SP 1 26 | 27 | typedef enum{ 28 | NOT_PRESSED, 29 | BOUNCE, 30 | PRESSED 31 | }button_state_t; 32 | 33 | 34 | /* Signals of the application*/ 35 | typedef enum{ 36 | INC_TIME, 37 | DEC_TIME, 38 | TIME_TICK, 39 | START_PAUSE, 40 | ABRT, 41 | /* Internal activity signals */ 42 | ENTRY, 43 | EXIT 44 | }protimer_signal_t; 45 | 46 | /* Various States of the application*/ 47 | typedef enum{ 48 | IDLE, 49 | TIME_SET, 50 | COUNTDOWN, 51 | PAUSE, 52 | STAT 53 | }protimer_state_t; 54 | 55 | /* Main application structure */ 56 | typedef struct { 57 | uint32_t curr_time; 58 | uint32_t elapsed_time; 59 | uint32_t pro_time; 60 | protimer_state_t active_state; 61 | }protimer_t; 62 | 63 | /*Generic(Super) event structure */ 64 | typedef struct{ 65 | uint8_t sig; 66 | }event_t; 67 | 68 | /* For user generated events */ 69 | typedef struct{ 70 | event_t super; 71 | }protimer_user_event_t; 72 | 73 | /* For tick event */ 74 | typedef struct{ 75 | event_t super; 76 | uint8_t ss; 77 | }protimer_tick_event_t; 78 | 79 | typedef enum{ 80 | EVENT_HANDLED, 81 | EVENT_IGNORED, 82 | EVENT_TRANSITION 83 | }event_status_t; 84 | 85 | 86 | void protimer_init(protimer_t *mobj); 87 | event_status_t protimer_state_machine(protimer_t *const mobj, event_t const *const e); 88 | 89 | #endif -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/src/protimer_state_mach.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "main.h" 3 | #include "lcd.h" 4 | 5 | 6 | //prototypes of helper functions 7 | static void do_beep(void); 8 | static void display_clear(void); 9 | static void display_message(String s,uint8_t c , uint8_t r); 10 | static void display_time(uint32_t time); 11 | 12 | //prototypes of state handlers 13 | static event_status_t protimer_state_handler_IDLE(protimer_t *const mobj, event_t const *const e); 14 | static event_status_t protimer_state_handler_TIME_SET(protimer_t *const mobj, event_t const *const e); 15 | static event_status_t protimer_state_handler_COUNTDOWN(protimer_t *const mobj, event_t const *const e); 16 | static event_status_t protimer_state_handler_PAUSE(protimer_t *const mobj, event_t const *const e); 17 | static event_status_t protimer_state_handler_STAT(protimer_t *const mobj, event_t const *const e); 18 | 19 | void protimer_init(protimer_t *mobj){ 20 | event_t ee; 21 | ee.sig = ENTRY; 22 | mobj->active_state = IDLE; 23 | mobj->pro_time = 0; 24 | protimer_state_machine(mobj,&ee); 25 | } 26 | 27 | event_status_t protimer_state_machine(protimer_t *const mobj, event_t const *const e){ 28 | switch (mobj->active_state){ 29 | case IDLE: 30 | return protimer_state_handler_IDLE(mobj,e); 31 | case TIME_SET: 32 | return protimer_state_handler_TIME_SET(mobj,e); 33 | case COUNTDOWN: 34 | return protimer_state_handler_COUNTDOWN(mobj,e); 35 | case PAUSE: 36 | return protimer_state_handler_PAUSE(mobj,e); 37 | case STAT: 38 | return protimer_state_handler_STAT(mobj,e); 39 | }//END OF SWITCH 40 | return EVENT_IGNORED; 41 | } 42 | 43 | static event_status_t protimer_state_handler_IDLE(protimer_t *const mobj, event_t const *const e){ 44 | switch(e->sig){ 45 | case ENTRY:{ 46 | mobj->curr_time = 0; 47 | mobj->elapsed_time = 0; 48 | display_time(0); 49 | display_message("Set",0,0); 50 | display_message("time",0,1); 51 | return EVENT_HANDLED; 52 | } 53 | case EXIT:{ 54 | display_clear(); 55 | return EVENT_HANDLED; 56 | } 57 | case INC_TIME:{ 58 | mobj->curr_time += 60; 59 | mobj->active_state = TIME_SET; 60 | return EVENT_TRANSITION; 61 | } 62 | case START_PAUSE:{ 63 | mobj->active_state = STAT; 64 | return EVENT_TRANSITION; 65 | } 66 | case TIME_TICK:{ 67 | if( ((protimer_tick_event_t *)(e))->ss == 5){ 68 | do_beep(); 69 | return EVENT_HANDLED; 70 | } 71 | 72 | return EVENT_IGNORED; 73 | } 74 | }//END OF SWITCH 75 | 76 | return EVENT_IGNORED; 77 | } 78 | 79 | static event_status_t protimer_state_handler_TIME_SET(protimer_t *const mobj, event_t const *const e){ 80 | switch(e->sig){ 81 | case ENTRY:{ 82 | display_time(mobj->curr_time); 83 | return EVENT_HANDLED; 84 | } 85 | case EXIT:{ 86 | display_clear(); 87 | return EVENT_HANDLED; 88 | } 89 | case INC_TIME:{ 90 | mobj->curr_time += 60; 91 | display_time(mobj->curr_time); 92 | return EVENT_HANDLED; 93 | } 94 | case DEC_TIME:{ 95 | if(mobj->curr_time >=60){ 96 | mobj->curr_time -= 60; 97 | display_time(mobj->curr_time); 98 | return EVENT_HANDLED; 99 | } 100 | return EVENT_IGNORED; 101 | } 102 | case ABRT:{ 103 | mobj->active_state = IDLE; 104 | return EVENT_TRANSITION; 105 | } 106 | case START_PAUSE:{ 107 | if(mobj->curr_time >=60){ 108 | mobj->active_state = COUNTDOWN; 109 | return EVENT_TRANSITION; 110 | } 111 | return EVENT_IGNORED; 112 | } 113 | } 114 | 115 | return EVENT_IGNORED; 116 | } 117 | 118 | static event_status_t protimer_state_handler_COUNTDOWN(protimer_t *const mobj, event_t const *const e){ 119 | switch(e->sig){ 120 | case EXIT:{ 121 | mobj->pro_time += mobj->elapsed_time; 122 | mobj->elapsed_time = 0; 123 | return EVENT_HANDLED; 124 | } 125 | 126 | case TIME_TICK:{ 127 | if(((protimer_tick_event_t*)(e))->ss == 10){ 128 | --mobj->curr_time; 129 | ++mobj->elapsed_time; 130 | display_time(mobj->curr_time); 131 | if(!mobj->curr_time){ 132 | mobj->active_state = IDLE; 133 | return EVENT_TRANSITION; 134 | } 135 | return EVENT_HANDLED; 136 | } 137 | return EVENT_IGNORED; 138 | } 139 | case START_PAUSE:{ 140 | mobj->active_state = PAUSE; 141 | return EVENT_TRANSITION; 142 | } 143 | case ABRT:{ 144 | mobj->active_state = IDLE; 145 | return EVENT_TRANSITION; 146 | } 147 | } 148 | return EVENT_IGNORED; 149 | } 150 | 151 | 152 | static event_status_t protimer_state_handler_PAUSE(protimer_t *const mobj, event_t const *const e){ 153 | switch(e->sig){ 154 | case ENTRY:{ 155 | display_message("Paused",5,1); 156 | return EVENT_HANDLED; 157 | } 158 | case EXIT:{ 159 | display_clear(); 160 | return EVENT_HANDLED; 161 | } 162 | case INC_TIME:{ 163 | mobj->curr_time += 60; 164 | mobj->active_state = TIME_SET; 165 | return EVENT_TRANSITION; 166 | } 167 | case DEC_TIME:{ 168 | if(mobj->curr_time >= 60){ 169 | mobj->curr_time -= 60; 170 | mobj->active_state = TIME_SET; 171 | return EVENT_TRANSITION; 172 | } 173 | return EVENT_IGNORED; 174 | } 175 | case START_PAUSE:{ 176 | mobj->active_state = COUNTDOWN; 177 | return EVENT_TRANSITION; 178 | } 179 | case ABRT:{ 180 | mobj->active_state = IDLE; 181 | return EVENT_TRANSITION; 182 | } 183 | } 184 | return EVENT_IGNORED; 185 | } 186 | 187 | static event_status_t protimer_state_handler_STAT(protimer_t *const mobj, event_t const *const e){ 188 | static uint8_t tick_count; 189 | 190 | switch(e->sig){ 191 | case ENTRY:{ 192 | display_time(mobj->pro_time); 193 | display_message("Productive time",1,1); 194 | return EVENT_HANDLED; 195 | } 196 | case EXIT:{ 197 | display_clear(); 198 | return EVENT_HANDLED; 199 | } 200 | case TIME_TICK:{ 201 | if(++tick_count == 30){ 202 | tick_count = 0; 203 | mobj->active_state = IDLE; 204 | return EVENT_TRANSITION; 205 | } 206 | return EVENT_IGNORED; 207 | } 208 | } 209 | return EVENT_IGNORED; 210 | } 211 | 212 | //////////////////////////helper functions////////////////////////// 213 | static void display_time(uint32_t time){ 214 | char buf[7]; 215 | String time_msg; 216 | 217 | uint16_t m = time / 60; 218 | uint8_t s = time % 60; 219 | sprintf(buf,"%03d:%02d",m,s); 220 | 221 | time_msg = (String)buf; 222 | lcd_set_cursor(5,0); 223 | lcd_print_string(time_msg); 224 | } 225 | 226 | static void display_message(String s,uint8_t c , uint8_t r){ 227 | lcd_set_cursor(c,r); 228 | lcd_print_string(s); 229 | } 230 | 231 | static void display_clear(void){ 232 | lcd_clear(); 233 | } 234 | 235 | static void do_beep(void){ 236 | tone(PIN_BUZZER, 4000, 25); 237 | } -------------------------------------------------------------------------------- /Course_Exercises/003Protimer/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:uno] 12 | platform = atmelavr 13 | board = uno 14 | framework = arduino 15 | lib_deps = arduino-libraries/LiquidCrystal@^1.0.7 16 | -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/src/lcd.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "lcd.h" 4 | #include "main.h" 5 | #include 6 | 7 | LiquidCrystal lcd(PIN_LCD_RS,PIN_LCD_RW,PIN_LCD_EN,PIN_LCD_D4,PIN_LCD_D5,PIN_LCD_D6,PIN_LCD_D7); 8 | 9 | void lcd_clear(void){ 10 | lcd.clear(); 11 | } 12 | void lcd_print_char(char c){ 13 | lcd.print(c); 14 | } 15 | 16 | void lcd_scroll_left(void){ 17 | lcd.scrollDisplayLeft(); 18 | } 19 | void lcd_scroll_right(void){ 20 | lcd.scrollDisplayRight(); 21 | } 22 | void lcd_set_cursor(int c, int r){ 23 | lcd.setCursor(c,r); 24 | } 25 | void lcd_no_auto_scroll(void){ 26 | lcd.noAutoscroll(); 27 | } 28 | void lcd_begin(uint8_t cols , uint8_t rows){ 29 | lcd.begin(cols,rows); 30 | } 31 | void lcd_move_cursor_R_to_L(void){ 32 | lcd.rightToLeft(); 33 | } 34 | void lcd_move_cursor_L_to_R(void){ 35 | lcd.leftToRight(); 36 | } 37 | void lcd_cursor_off(void){ 38 | lcd.noCursor(); 39 | } 40 | void lcd_cursor_blinkoff(void){ 41 | lcd.noBlink(); 42 | } 43 | void lcd_print_number(int num){ 44 | lcd.print(num); 45 | } 46 | void lcd_print_string(String s){ 47 | lcd.print(s); 48 | } -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/src/lcd.h: -------------------------------------------------------------------------------- 1 | #ifndef LCD_H 2 | #define LCD_H 3 | #include 4 | 5 | void lcd_clear(void); 6 | void lcd_print_char(char c); 7 | void lcd_scroll_left(void); 8 | void lcd_scroll_right(void); 9 | void lcd_set_cursor(int c, int r); 10 | void lcd_no_auto_scroll(void); 11 | void lcd_begin(uint8_t cols, uint8_t rows); 12 | void lcd_move_cursor_R_to_L(void); 13 | void lcd_move_cursor_L_to_R(void); 14 | void lcd_cursor_off(void); 15 | void lcd_cursor_blinkoff(void); 16 | void lcd_print_number(int num); 17 | void lcd_print_string(String s); 18 | 19 | #endif -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "main.h" 4 | #include "lcd.h" 5 | 6 | static void protimer_event_dispatcher(protimer_t *const mobj,event_t const *const e); 7 | static uint8_t process_button_pad_value(uint8_t btn_pad_value); 8 | static void display_init(void); 9 | 10 | /*Main application object */ 11 | static protimer_t protimer; 12 | 13 | void setup() { 14 | // put your setup code here, to run once: 15 | Serial.begin(115200); 16 | display_init(); 17 | Serial.println("Productive timer application"); 18 | Serial.println("==========================="); 19 | pinMode(PIN_BUTTON1,INPUT); 20 | pinMode(PIN_BUTTON2,INPUT); 21 | pinMode(PIN_BUTTON3,INPUT); 22 | 23 | protimer_init(&protimer); 24 | } 25 | 26 | void loop() { 27 | 28 | uint8_t b1,b2,b3,btn_pad_value; 29 | protimer_user_event_t ue; 30 | static uint32_t current_time = millis(); 31 | static protimer_tick_event_t te; 32 | 33 | //1. read the button pad status 34 | b1 = digitalRead(PIN_BUTTON1); 35 | b2 = digitalRead(PIN_BUTTON2); 36 | b3 = digitalRead(PIN_BUTTON3); 37 | 38 | btn_pad_value = (b1<<2)|(b2<<1)|b3; 39 | 40 | //software button de-bouncing 41 | btn_pad_value = process_button_pad_value(btn_pad_value); 42 | 43 | //2. make an event 44 | if(btn_pad_value){ 45 | if(btn_pad_value == BTN_PAD_VALUE_INC_TIME){ 46 | ue.super.sig = INC_TIME; 47 | }else if(btn_pad_value == BTN_PAD_VALUE_DEC_TIME){ 48 | ue.super.sig = DEC_TIME; 49 | }else if(btn_pad_value == BTN_PAD_VALUE_SP){ 50 | ue.super.sig = START_PAUSE; 51 | }else if(btn_pad_value == BTN_PAD_VALUE_ABRT){ 52 | ue.super.sig = ABRT; 53 | } 54 | //3. send it to event dispatcher 55 | protimer_event_dispatcher(&protimer,&ue.super); 56 | } 57 | 58 | //4. dispatch the time tick event for every 100ms 59 | if(millis() - current_time >= 100){ 60 | //100ms has passed 61 | current_time = millis(); 62 | te.super.sig = TIME_TICK; 63 | if(++te.ss > 10) te.ss = 1; 64 | protimer_event_dispatcher(&protimer,&te.super); 65 | } 66 | 67 | } 68 | 69 | 70 | static void protimer_event_dispatcher(protimer_t *const mobj,event_t const *const e){ 71 | 72 | event_status_t status; 73 | protimer_state_t source, target; 74 | 75 | source = mobj->active_state; 76 | status = (*mobj->active_state)(mobj,e); 77 | 78 | if(status == EVENT_TRANSITION){ 79 | target = mobj->active_state; 80 | event_t ee; 81 | //1. run the exit action for the source state 82 | ee.sig = EXIT; 83 | (*source)(mobj,&ee); 84 | 85 | //2. run the entry action for the target state 86 | ee.sig = ENTRY; 87 | (*target)(mobj,&ee); 88 | } 89 | 90 | } 91 | 92 | 93 | static uint8_t process_button_pad_value(uint8_t btn_pad_value) 94 | { 95 | static button_state_t btn_sm_state = NOT_PRESSED; 96 | static uint32_t curr_time = millis(); 97 | 98 | switch(btn_sm_state){ 99 | case NOT_PRESSED:{ 100 | if(btn_pad_value){ 101 | btn_sm_state = BOUNCE; 102 | curr_time = millis(); 103 | } 104 | break; 105 | } 106 | case BOUNCE:{ 107 | if(millis() - curr_time >= 50 ){ 108 | //50ms has passed 109 | if(btn_pad_value){ 110 | btn_sm_state = PRESSED; 111 | return btn_pad_value; 112 | } 113 | else 114 | btn_sm_state = NOT_PRESSED; 115 | } 116 | break; 117 | } 118 | case PRESSED:{ 119 | if(!btn_pad_value){ 120 | btn_sm_state = BOUNCE; 121 | curr_time = millis(); 122 | } 123 | break; 124 | } 125 | 126 | } 127 | 128 | return 0; 129 | } 130 | 131 | static void display_init(void) 132 | { 133 | lcd_begin(16,2); 134 | lcd_clear(); 135 | lcd_move_cursor_L_to_R(); 136 | lcd_set_cursor(0,0); 137 | lcd_no_auto_scroll(); 138 | lcd_cursor_off(); 139 | } -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/src/main.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MAIN_H 3 | #define MAIN_H 4 | 5 | #include 6 | 7 | 8 | #define PIN_BUTTON1 2 9 | #define PIN_BUTTON2 3 10 | #define PIN_BUTTON3 4 11 | #define PIN_BUZZER 12 12 | 13 | //lcd connections 14 | #define PIN_LCD_RS 5 15 | #define PIN_LCD_RW 6 16 | #define PIN_LCD_EN 7 17 | #define PIN_LCD_D4 8 18 | #define PIN_LCD_D5 9 19 | #define PIN_LCD_D6 10 20 | #define PIN_LCD_D7 11 21 | 22 | #define BTN_PAD_VALUE_INC_TIME 4 23 | #define BTN_PAD_VALUE_DEC_TIME 2 24 | #define BTN_PAD_VALUE_ABRT 6 25 | #define BTN_PAD_VALUE_SP 1 26 | 27 | typedef enum{ 28 | NOT_PRESSED, 29 | BOUNCE, 30 | PRESSED 31 | }button_state_t; 32 | 33 | typedef enum { 34 | EVENT_HANDLED, 35 | EVENT_IGNORED, 36 | EVENT_TRANSITION 37 | }event_status_t; 38 | 39 | 40 | /* Signals of the application*/ 41 | typedef enum{ 42 | INC_TIME, 43 | DEC_TIME, 44 | TIME_TICK, 45 | START_PAUSE, 46 | ABRT, 47 | /* Internal activity signals */ 48 | ENTRY, 49 | EXIT 50 | }protimer_signal_t; 51 | 52 | //forward declarations 53 | struct protimer_tag; 54 | struct event_tag; 55 | 56 | typedef event_status_t (*protimer_state_t)(struct protimer_tag *const , struct event_tag const *const); 57 | 58 | 59 | /* Main application structure */ 60 | typedef struct protimer_tag { 61 | uint32_t curr_time; 62 | uint32_t elapsed_time; 63 | uint32_t pro_time; 64 | protimer_state_t active_state; 65 | }protimer_t; 66 | 67 | /*Generic(Super) event structure */ 68 | typedef struct event_tag{ 69 | uint8_t sig; 70 | }event_t; 71 | 72 | /* For user generated events */ 73 | typedef struct{ 74 | event_t super; 75 | }protimer_user_event_t; 76 | 77 | /* For tick event */ 78 | typedef struct{ 79 | event_t super; 80 | uint8_t ss; 81 | }protimer_tick_event_t; 82 | 83 | 84 | 85 | 86 | void protimer_init(protimer_t *mobj); 87 | event_status_t protimer_state_machine(protimer_t *const mobj, event_t const *const e); 88 | 89 | #endif -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/src/protimer_state_mach.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "main.h" 3 | #include "lcd.h" 4 | 5 | 6 | //prototypes of helper functions 7 | static void do_beep(void); 8 | static void display_clear(void); 9 | static void display_message(String s,uint8_t c , uint8_t r); 10 | static void display_time(uint32_t time); 11 | 12 | //prototypes of state handlers 13 | static event_status_t protimer_state_handler_IDLE(protimer_t *const mobj, event_t const *const e); 14 | static event_status_t protimer_state_handler_TIME_SET(protimer_t *const mobj, event_t const *const e); 15 | static event_status_t protimer_state_handler_COUNTDOWN(protimer_t *const mobj, event_t const *const e); 16 | static event_status_t protimer_state_handler_PAUSE(protimer_t *const mobj, event_t const *const e); 17 | static event_status_t protimer_state_handler_STAT(protimer_t *const mobj, event_t const *const e); 18 | 19 | 20 | #define IDLE &protimer_state_handler_IDLE 21 | #define TIME_SET &protimer_state_handler_TIME_SET 22 | #define COUNTDOWN &protimer_state_handler_COUNTDOWN 23 | #define PAUSE &protimer_state_handler_PAUSE 24 | #define STAT &protimer_state_handler_STAT 25 | 26 | void protimer_init(protimer_t *mobj){ 27 | event_t ee; 28 | ee.sig = ENTRY; 29 | mobj->active_state = IDLE; 30 | mobj->pro_time = 0; 31 | (*mobj->active_state)(mobj,&ee); //jump to IDLE handler 32 | } 33 | 34 | 35 | static event_status_t protimer_state_handler_IDLE(protimer_t *const mobj, event_t const *const e){ 36 | switch(e->sig){ 37 | case ENTRY:{ 38 | mobj->curr_time = 0; 39 | mobj->elapsed_time = 0; 40 | display_time(0); 41 | display_message("Set",0,0); 42 | display_message("time",0,1); 43 | return EVENT_HANDLED; 44 | } 45 | case EXIT:{ 46 | display_clear(); 47 | return EVENT_HANDLED; 48 | } 49 | case INC_TIME:{ 50 | mobj->curr_time += 60; 51 | mobj->active_state = TIME_SET; 52 | return EVENT_TRANSITION; 53 | } 54 | case START_PAUSE:{ 55 | mobj->active_state = STAT; 56 | return EVENT_TRANSITION; 57 | } 58 | case TIME_TICK:{ 59 | if( ((protimer_tick_event_t *)(e))->ss == 5){ 60 | do_beep(); 61 | return EVENT_HANDLED; 62 | } 63 | 64 | return EVENT_IGNORED; 65 | } 66 | }//END OF SWITCH 67 | 68 | return EVENT_IGNORED; 69 | } 70 | 71 | static event_status_t protimer_state_handler_TIME_SET(protimer_t *const mobj, event_t const *const e){ 72 | switch(e->sig){ 73 | case ENTRY:{ 74 | display_time(mobj->curr_time); 75 | return EVENT_HANDLED; 76 | } 77 | case EXIT:{ 78 | display_clear(); 79 | return EVENT_HANDLED; 80 | } 81 | case INC_TIME:{ 82 | mobj->curr_time += 60; 83 | display_time(mobj->curr_time); 84 | return EVENT_HANDLED; 85 | } 86 | case DEC_TIME:{ 87 | if(mobj->curr_time >=60){ 88 | mobj->curr_time -= 60; 89 | display_time(mobj->curr_time); 90 | return EVENT_HANDLED; 91 | } 92 | return EVENT_IGNORED; 93 | } 94 | case ABRT:{ 95 | mobj->active_state = IDLE; 96 | return EVENT_TRANSITION; 97 | } 98 | case START_PAUSE:{ 99 | if(mobj->curr_time >=60){ 100 | mobj->active_state = COUNTDOWN; 101 | return EVENT_TRANSITION; 102 | } 103 | return EVENT_IGNORED; 104 | } 105 | } 106 | 107 | return EVENT_IGNORED; 108 | } 109 | 110 | static event_status_t protimer_state_handler_COUNTDOWN(protimer_t *const mobj, event_t const *const e){ 111 | switch(e->sig){ 112 | case EXIT:{ 113 | mobj->pro_time += mobj->elapsed_time; 114 | mobj->elapsed_time = 0; 115 | return EVENT_HANDLED; 116 | } 117 | 118 | case TIME_TICK:{ 119 | if(((protimer_tick_event_t*)(e))->ss == 10){ 120 | --mobj->curr_time; 121 | ++mobj->elapsed_time; 122 | display_time(mobj->curr_time); 123 | if(!mobj->curr_time){ 124 | mobj->active_state = IDLE; 125 | return EVENT_TRANSITION; 126 | } 127 | return EVENT_HANDLED; 128 | } 129 | return EVENT_IGNORED; 130 | } 131 | case START_PAUSE:{ 132 | mobj->active_state = PAUSE; 133 | return EVENT_TRANSITION; 134 | } 135 | case ABRT:{ 136 | mobj->active_state = IDLE; 137 | return EVENT_TRANSITION; 138 | } 139 | } 140 | return EVENT_IGNORED; 141 | } 142 | 143 | 144 | static event_status_t protimer_state_handler_PAUSE(protimer_t *const mobj, event_t const *const e){ 145 | switch(e->sig){ 146 | case ENTRY:{ 147 | display_message("Paused",5,1); 148 | return EVENT_HANDLED; 149 | } 150 | case EXIT:{ 151 | display_clear(); 152 | return EVENT_HANDLED; 153 | } 154 | case INC_TIME:{ 155 | mobj->curr_time += 60; 156 | mobj->active_state = TIME_SET; 157 | return EVENT_TRANSITION; 158 | } 159 | case DEC_TIME:{ 160 | if(mobj->curr_time >= 60){ 161 | mobj->curr_time -= 60; 162 | mobj->active_state = TIME_SET; 163 | return EVENT_TRANSITION; 164 | } 165 | return EVENT_IGNORED; 166 | } 167 | case START_PAUSE:{ 168 | mobj->active_state = COUNTDOWN; 169 | return EVENT_TRANSITION; 170 | } 171 | case ABRT:{ 172 | mobj->active_state = IDLE; 173 | return EVENT_TRANSITION; 174 | } 175 | } 176 | return EVENT_IGNORED; 177 | } 178 | 179 | static event_status_t protimer_state_handler_STAT(protimer_t *const mobj, event_t const *const e){ 180 | static uint8_t tick_count; 181 | 182 | switch(e->sig){ 183 | case ENTRY:{ 184 | display_time(mobj->pro_time); 185 | display_message("Productive time",1,1); 186 | return EVENT_HANDLED; 187 | } 188 | case EXIT:{ 189 | display_clear(); 190 | return EVENT_HANDLED; 191 | } 192 | case TIME_TICK:{ 193 | if(++tick_count == 30){ 194 | tick_count = 0; 195 | mobj->active_state = IDLE; 196 | return EVENT_TRANSITION; 197 | } 198 | return EVENT_IGNORED; 199 | } 200 | } 201 | return EVENT_IGNORED; 202 | } 203 | 204 | //////////////////////////helper functions////////////////////////// 205 | static void display_time(uint32_t time){ 206 | char buf[7]; 207 | String time_msg; 208 | 209 | uint16_t m = time / 60; 210 | uint8_t s = time % 60; 211 | sprintf(buf,"%03d:%02d",m,s); 212 | 213 | time_msg = (String)buf; 214 | lcd_set_cursor(5,0); 215 | lcd_print_string(time_msg); 216 | } 217 | 218 | static void display_message(String s,uint8_t c , uint8_t r){ 219 | lcd_set_cursor(c,r); 220 | lcd_print_string(s); 221 | } 222 | 223 | static void display_clear(void){ 224 | lcd_clear(); 225 | } 226 | 227 | static void do_beep(void){ 228 | tone(PIN_BUZZER, 4000, 25); 229 | } -------------------------------------------------------------------------------- /Course_Exercises/004Protimer_SH/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:uno] 12 | platform = atmelavr 13 | board = uno 14 | framework = arduino 15 | lib_deps = arduino-libraries/LiquidCrystal@^1.0.7 16 | -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/src/lcd.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "lcd.h" 4 | #include "main.h" 5 | #include 6 | 7 | LiquidCrystal lcd(PIN_LCD_RS,PIN_LCD_RW,PIN_LCD_EN,PIN_LCD_D4,PIN_LCD_D5,PIN_LCD_D6,PIN_LCD_D7); 8 | 9 | void lcd_clear(void){ 10 | lcd.clear(); 11 | } 12 | void lcd_print_char(char c){ 13 | lcd.print(c); 14 | } 15 | 16 | void lcd_scroll_left(void){ 17 | lcd.scrollDisplayLeft(); 18 | } 19 | void lcd_scroll_right(void){ 20 | lcd.scrollDisplayRight(); 21 | } 22 | void lcd_set_cursor(int c, int r){ 23 | lcd.setCursor(c,r); 24 | } 25 | void lcd_no_auto_scroll(void){ 26 | lcd.noAutoscroll(); 27 | } 28 | void lcd_begin(uint8_t cols , uint8_t rows){ 29 | lcd.begin(cols,rows); 30 | } 31 | void lcd_move_cursor_R_to_L(void){ 32 | lcd.rightToLeft(); 33 | } 34 | void lcd_move_cursor_L_to_R(void){ 35 | lcd.leftToRight(); 36 | } 37 | void lcd_cursor_off(void){ 38 | lcd.noCursor(); 39 | } 40 | void lcd_cursor_blinkoff(void){ 41 | lcd.noBlink(); 42 | } 43 | void lcd_print_number(int num){ 44 | lcd.print(num); 45 | } 46 | void lcd_print_string(String s){ 47 | lcd.print(s); 48 | } 49 | 50 | void lcd_cursor_show(void) 51 | { 52 | lcd.cursor(); 53 | } 54 | 55 | void lcd_cursor_blink(void) 56 | { 57 | lcd.blink(); 58 | } -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/src/lcd.h: -------------------------------------------------------------------------------- 1 | #ifndef LCD_H 2 | #define LCD_H 3 | #include 4 | 5 | void lcd_clear(void); 6 | void lcd_print_char(char c); 7 | void lcd_scroll_left(void); 8 | void lcd_scroll_right(void); 9 | void lcd_set_cursor(int c, int r); 10 | void lcd_no_auto_scroll(void); 11 | void lcd_begin(uint8_t cols, uint8_t rows); 12 | void lcd_move_cursor_R_to_L(void); 13 | void lcd_move_cursor_L_to_R(void); 14 | void lcd_cursor_off(void); 15 | void lcd_cursor_blinkoff(void); 16 | void lcd_print_number(int num); 17 | void lcd_print_string(String s); 18 | void lcd_cursor_blink(void); 19 | void lcd_cursor_show(void); 20 | 21 | #endif -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "main.h" 4 | #include "lcd.h" 5 | 6 | static void protimer_event_dispatcher(protimer_t *const mobj,event_t const *const e); 7 | static uint8_t process_button_pad_value(uint8_t btn_pad_value); 8 | static void display_init(void); 9 | static void protimer_state_table_init(protimer_t *const mobj); 10 | 11 | /*Main application object */ 12 | static protimer_t protimer; 13 | 14 | void setup() { 15 | // put your setup code here, to run once: 16 | Serial.begin(115200); 17 | display_init(); 18 | Serial.println("Productive timer application"); 19 | Serial.println("==========================="); 20 | pinMode(PIN_BUTTON1,INPUT); 21 | pinMode(PIN_BUTTON2,INPUT); 22 | pinMode(PIN_BUTTON3,INPUT); 23 | 24 | protimer_state_table_init(&protimer); 25 | protimer_init(&protimer); 26 | } 27 | 28 | void loop() { 29 | 30 | uint8_t b1,b2,b3,btn_pad_value; 31 | protimer_user_event_t ue; 32 | static uint32_t current_time = millis(); 33 | static protimer_tick_event_t te; 34 | 35 | //1. read the button pad status 36 | b1 = digitalRead(PIN_BUTTON1); 37 | b2 = digitalRead(PIN_BUTTON2); 38 | b3 = digitalRead(PIN_BUTTON3); 39 | 40 | btn_pad_value = (b1<<2)|(b2<<1)|b3; 41 | 42 | //software button de-bouncing 43 | btn_pad_value = process_button_pad_value(btn_pad_value); 44 | 45 | //2. make an event 46 | if(btn_pad_value){ 47 | if(btn_pad_value == BTN_PAD_VALUE_INC_TIME){ 48 | ue.super.sig = INC_TIME; 49 | }else if(btn_pad_value == BTN_PAD_VALUE_DEC_TIME){ 50 | ue.super.sig = DEC_TIME; 51 | }else if(btn_pad_value == BTN_PAD_VALUE_SP){ 52 | ue.super.sig = START_PAUSE; 53 | }else if(btn_pad_value == BTN_PAD_VALUE_ABRT){ 54 | ue.super.sig = ABRT; 55 | } 56 | //3. send it to event dispatcher 57 | protimer_event_dispatcher(&protimer,&ue.super); 58 | } 59 | 60 | //4. dispatch the time tick event for every 100ms 61 | if(millis() - current_time >= 100){ 62 | //100ms has passed 63 | current_time = millis(); 64 | te.super.sig = TIME_TICK; 65 | if(++te.ss > 10) te.ss = 1; 66 | protimer_event_dispatcher(&protimer,&te.super); 67 | } 68 | 69 | } 70 | 71 | 72 | static void protimer_event_dispatcher(protimer_t *const mobj,event_t const *const e){ 73 | 74 | event_status_t status; 75 | protimer_state_t source, target; 76 | e_handler_t ehandler; 77 | 78 | source = mobj->active_state; 79 | ehandler = (e_handler_t) mobj->state_table[mobj->active_state * MAX_SIGNALS + e->sig]; 80 | if(ehandler) 81 | status = (*ehandler)(mobj,e); 82 | 83 | if(status == EVENT_TRANSITION){ 84 | target = mobj->active_state; 85 | event_t ee; 86 | //1. run the exit action for the source state 87 | ee.sig = EXIT; 88 | ehandler =(e_handler_t) mobj->state_table[source*MAX_SIGNALS + EXIT]; 89 | if(ehandler) 90 | (*ehandler)(mobj,&ee); 91 | 92 | //2. run the entry action for the target state 93 | ee.sig = ENTRY; 94 | ehandler =(e_handler_t) mobj->state_table[target * MAX_SIGNALS + ENTRY]; 95 | if(ehandler) 96 | (*ehandler)(mobj,&ee); 97 | } 98 | 99 | } 100 | 101 | 102 | static void protimer_state_table_init(protimer_t *const mobj) 103 | { 104 | static e_handler_t protimer_state_table[MAX_STATES][MAX_SIGNALS] = { 105 | [IDLE] = {&IDLE_Inc_time,NULL,&IDLE_Time_tick,&IDLE_Start_pause,NULL,&IDLE_Entry,&IDLE_Exit}, 106 | [TIME_SET] = {&TIME_SET_Inc_time,&TIME_SET_Dec_time,NULL,&TIME_SET_Start_pause,&TIME_SET_abrt,&TIME_SET_Entry,&TIME_SET_Exit}, 107 | [COUNTDOWN] = {NULL,NULL,&COUNTDOWN_Time_tick,&COUNTDOWN_Start_pause,&COUNTDOWN_abrt,NULL,COUNTDOWN_Exit}, 108 | [PAUSE] = {&PAUSE_Inc_time,&PAUSE_Dec_time,NULL,&PAUSE_Start_pause,&PAUSE_abrt,&PAUSE_Entry,&PAUSE_Exit}, 109 | [STAT] = {NULL,NULL,&STAT_Time_tick,NULL,NULL,&STAT_Entry,STAT_Exit} 110 | }; 111 | 112 | mobj->state_table = (uintptr_t*) &protimer_state_table[0][0]; 113 | 114 | } 115 | 116 | 117 | static uint8_t process_button_pad_value(uint8_t btn_pad_value) 118 | { 119 | static button_state_t btn_sm_state = NOT_PRESSED; 120 | static uint32_t curr_time = millis(); 121 | 122 | switch(btn_sm_state){ 123 | case NOT_PRESSED:{ 124 | if(btn_pad_value){ 125 | btn_sm_state = BOUNCE; 126 | curr_time = millis(); 127 | } 128 | break; 129 | } 130 | case BOUNCE:{ 131 | if(millis() - curr_time >= 50 ){ 132 | //50ms has passed 133 | if(btn_pad_value){ 134 | btn_sm_state = PRESSED; 135 | return btn_pad_value; 136 | } 137 | else 138 | btn_sm_state = NOT_PRESSED; 139 | } 140 | break; 141 | } 142 | case PRESSED:{ 143 | if(!btn_pad_value){ 144 | btn_sm_state = BOUNCE; 145 | curr_time = millis(); 146 | } 147 | break; 148 | } 149 | 150 | } 151 | 152 | return 0; 153 | } 154 | 155 | static void display_init(void) 156 | { 157 | lcd_begin(16,2); 158 | lcd_clear(); 159 | lcd_move_cursor_L_to_R(); 160 | lcd_set_cursor(0,0); 161 | lcd_no_auto_scroll(); 162 | lcd_cursor_off(); 163 | } -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/src/main.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MAIN_H 3 | #define MAIN_H 4 | 5 | #include 6 | 7 | 8 | #define PIN_BUTTON1 2 9 | #define PIN_BUTTON2 3 10 | #define PIN_BUTTON3 4 11 | #define PIN_BUZZER 12 12 | 13 | //lcd connections 14 | #define PIN_LCD_RS 5 15 | #define PIN_LCD_RW 6 16 | #define PIN_LCD_EN 7 17 | #define PIN_LCD_D4 8 18 | #define PIN_LCD_D5 9 19 | #define PIN_LCD_D6 10 20 | #define PIN_LCD_D7 11 21 | 22 | #define BTN_PAD_VALUE_INC_TIME 4 23 | #define BTN_PAD_VALUE_DEC_TIME 2 24 | #define BTN_PAD_VALUE_ABRT 6 25 | #define BTN_PAD_VALUE_SP 1 26 | 27 | typedef enum{ 28 | NOT_PRESSED, 29 | BOUNCE, 30 | PRESSED 31 | }button_state_t; 32 | 33 | 34 | /* Signals of the application*/ 35 | typedef enum{ 36 | INC_TIME, 37 | DEC_TIME, 38 | TIME_TICK, 39 | START_PAUSE, 40 | ABRT, 41 | /* Internal activity signals */ 42 | ENTRY, 43 | EXIT, 44 | MAX_SIGNALS 45 | }protimer_signal_t; 46 | 47 | /* Various States of the application*/ 48 | typedef enum{ 49 | IDLE, 50 | TIME_SET, 51 | COUNTDOWN, 52 | PAUSE, 53 | STAT, 54 | MAX_STATES 55 | }protimer_state_t; 56 | 57 | /* Main application structure */ 58 | typedef struct { 59 | uint32_t curr_time; 60 | uint32_t elapsed_time; 61 | uint32_t pro_time; 62 | protimer_state_t active_state; 63 | uintptr_t *state_table; 64 | }protimer_t; 65 | 66 | /*Generic(Super) event structure */ 67 | typedef struct{ 68 | uint8_t sig; 69 | }event_t; 70 | 71 | /* For user generated events */ 72 | typedef struct{ 73 | event_t super; 74 | }protimer_user_event_t; 75 | 76 | /* For tick event */ 77 | typedef struct{ 78 | event_t super; 79 | uint8_t ss; 80 | }protimer_tick_event_t; 81 | 82 | typedef enum{ 83 | EVENT_HANDLED, 84 | EVENT_IGNORED, 85 | EVENT_TRANSITION 86 | }event_status_t; 87 | 88 | 89 | //function pointer type for event handlers 90 | typedef event_status_t (*e_handler_t)(protimer_t *const mobj, event_t const *const e); 91 | 92 | 93 | void protimer_init(protimer_t *mobj); 94 | event_status_t protimer_state_machine(protimer_t *const mobj, event_t const *const e); 95 | 96 | 97 | //prototypes of event handlers 98 | event_status_t IDLE_Inc_time(protimer_t *const mobj, event_t const *const e); 99 | event_status_t IDLE_Time_tick(protimer_t *const mobj, event_t const *const e); 100 | event_status_t IDLE_Start_pause(protimer_t *const mobj, event_t const *const e); 101 | event_status_t IDLE_Entry(protimer_t *const mobj, event_t const *const e); 102 | event_status_t IDLE_Exit(protimer_t *const mobj, event_t const *const e); 103 | 104 | event_status_t COUNTDOWN_Start_pause(protimer_t *const mobj, event_t const *const e); 105 | event_status_t COUNTDOWN_abrt(protimer_t *const mobj, event_t const *const e); 106 | event_status_t COUNTDOWN_Exit(protimer_t *const mobj, event_t const *const e); 107 | event_status_t COUNTDOWN_Time_tick(protimer_t *const mobj, event_t const *const e); 108 | 109 | event_status_t PAUSE_Inc_time(protimer_t *const mobj, event_t const *const e); 110 | event_status_t PAUSE_Dec_time(protimer_t *const mobj, event_t const *const e); 111 | event_status_t PAUSE_Start_pause(protimer_t *const mobj, event_t const *const e); 112 | event_status_t PAUSE_abrt(protimer_t *const mobj, event_t const *const e); 113 | event_status_t PAUSE_Entry(protimer_t *const mobj, event_t const *const e); 114 | event_status_t PAUSE_Exit(protimer_t *const mobj, event_t const *const e); 115 | 116 | 117 | event_status_t TIME_SET_Inc_time(protimer_t *const mobj, event_t const *const e); 118 | event_status_t TIME_SET_Dec_time(protimer_t *const mobj, event_t const *const e); 119 | event_status_t TIME_SET_Start_pause(protimer_t *const mobj, event_t const *const e); 120 | event_status_t TIME_SET_abrt(protimer_t *const mobj, event_t const *const e); 121 | event_status_t TIME_SET_Entry(protimer_t *const mobj, event_t const *const e); 122 | event_status_t TIME_SET_Exit(protimer_t *const mobj, event_t const *const e); 123 | 124 | event_status_t STAT_Time_tick(protimer_t *const mobj, event_t const *const e); 125 | event_status_t STAT_Time_tick(protimer_t *const mobj, event_t const *const e); 126 | event_status_t STAT_Entry(protimer_t *const mobj, event_t const *const e); 127 | event_status_t STAT_Exit(protimer_t *const mobj, event_t const *const e); 128 | 129 | #endif -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/src/protimer_state_mach.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "main.h" 3 | #include "lcd.h" 4 | 5 | 6 | //prototypes of helper functions 7 | static void do_beep(void); 8 | static void display_clear(void); 9 | static void display_message(String s,uint8_t c , uint8_t r); 10 | static void display_time(uint32_t time); 11 | 12 | 13 | void protimer_init(protimer_t *mobj){ 14 | event_t ee; 15 | e_handler_t ehandler; 16 | ee.sig = ENTRY; 17 | mobj->active_state = IDLE; 18 | mobj->pro_time = 0; 19 | ehandler = (e_handler_t) mobj->state_table[IDLE * MAX_SIGNALS + ENTRY]; 20 | (*ehandler)(mobj,&ee); 21 | } 22 | 23 | /////////////////////////Event handlers//////////////////////////// 24 | 25 | event_status_t IDLE_Inc_time(protimer_t *const mobj, event_t const *const e){ 26 | mobj->curr_time += 60; 27 | mobj->active_state = TIME_SET; 28 | return EVENT_TRANSITION; 29 | } 30 | 31 | event_status_t IDLE_Time_tick(protimer_t *const mobj, event_t const *const e){ 32 | if( ((protimer_tick_event_t *)(e))->ss == 5){ 33 | do_beep(); 34 | return EVENT_HANDLED; 35 | } 36 | 37 | return EVENT_IGNORED; 38 | } 39 | 40 | event_status_t IDLE_Start_pause(protimer_t *const mobj, event_t const *const e){ 41 | mobj->active_state = STAT; 42 | return EVENT_TRANSITION; 43 | } 44 | 45 | event_status_t IDLE_Entry(protimer_t *const mobj, event_t const *const e){ 46 | mobj->curr_time = 0; 47 | mobj->elapsed_time = 0; 48 | display_time(0); 49 | display_message("Set",0,0); 50 | display_message("time",0,1); 51 | return EVENT_HANDLED; 52 | } 53 | event_status_t IDLE_Exit(protimer_t *const mobj, event_t const *const e){ 54 | display_clear(); 55 | return EVENT_HANDLED; 56 | } 57 | 58 | event_status_t COUNTDOWN_Start_pause(protimer_t *const mobj, event_t const *const e){ 59 | mobj->active_state = PAUSE; 60 | return EVENT_TRANSITION; 61 | } 62 | event_status_t COUNTDOWN_abrt(protimer_t *const mobj, event_t const *const e){ 63 | mobj->active_state = IDLE; 64 | return EVENT_TRANSITION; 65 | } 66 | event_status_t COUNTDOWN_Exit(protimer_t *const mobj, event_t const *const e){ 67 | mobj->pro_time += mobj->elapsed_time; 68 | mobj->elapsed_time = 0; 69 | return EVENT_HANDLED; 70 | } 71 | event_status_t COUNTDOWN_Time_tick(protimer_t *const mobj, event_t const *const e){ 72 | if(((protimer_tick_event_t*)(e))->ss == 10){ 73 | --mobj->curr_time; 74 | ++mobj->elapsed_time; 75 | display_time(mobj->curr_time); 76 | if(!mobj->curr_time){ 77 | mobj->active_state = IDLE; 78 | return EVENT_TRANSITION; 79 | } 80 | return EVENT_HANDLED; 81 | } 82 | return EVENT_IGNORED; 83 | } 84 | 85 | event_status_t PAUSE_Inc_time(protimer_t *const mobj, event_t const *const e){ 86 | mobj->curr_time += 60; 87 | mobj->active_state = TIME_SET; 88 | return EVENT_TRANSITION; 89 | } 90 | event_status_t PAUSE_Dec_time(protimer_t *const mobj, event_t const *const e){ 91 | if(mobj->curr_time >= 60){ 92 | mobj->curr_time -= 60; 93 | mobj->active_state = TIME_SET; 94 | return EVENT_TRANSITION; 95 | } 96 | return EVENT_IGNORED; 97 | } 98 | event_status_t PAUSE_Start_pause(protimer_t *const mobj, event_t const *const e){ 99 | mobj->active_state = COUNTDOWN; 100 | return EVENT_TRANSITION; 101 | } 102 | event_status_t PAUSE_abrt(protimer_t *const mobj, event_t const *const e){ 103 | mobj->active_state = IDLE; 104 | return EVENT_TRANSITION; 105 | } 106 | event_status_t PAUSE_Entry(protimer_t *const mobj, event_t const *const e){ 107 | display_message("Paused",5,1); 108 | return EVENT_HANDLED; 109 | } 110 | event_status_t PAUSE_Exit(protimer_t *const mobj, event_t const *const e){ 111 | display_clear(); 112 | return EVENT_HANDLED; 113 | } 114 | 115 | event_status_t TIME_SET_Inc_time(protimer_t *const mobj, event_t const *const e){ 116 | mobj->curr_time += 60; 117 | display_time(mobj->curr_time); 118 | return EVENT_HANDLED; 119 | } 120 | event_status_t TIME_SET_Dec_time(protimer_t *const mobj, event_t const *const e){ 121 | if(mobj->curr_time >=60){ 122 | mobj->curr_time -= 60; 123 | display_time(mobj->curr_time); 124 | return EVENT_HANDLED; 125 | } 126 | return EVENT_IGNORED; 127 | } 128 | event_status_t TIME_SET_Start_pause(protimer_t *const mobj, event_t const *const e){ 129 | if(mobj->curr_time >=60){ 130 | mobj->active_state = COUNTDOWN; 131 | return EVENT_TRANSITION; 132 | } 133 | return EVENT_IGNORED; 134 | } 135 | event_status_t TIME_SET_abrt(protimer_t *const mobj, event_t const *const e){ 136 | mobj->active_state = IDLE; 137 | return EVENT_TRANSITION; 138 | } 139 | event_status_t TIME_SET_Entry(protimer_t *const mobj, event_t const *const e){ 140 | display_time(mobj->curr_time); 141 | return EVENT_HANDLED; 142 | } 143 | 144 | event_status_t TIME_SET_Exit(protimer_t *const mobj, event_t const *const e){ 145 | display_clear(); 146 | return EVENT_HANDLED; 147 | } 148 | 149 | event_status_t STAT_Time_tick(protimer_t *const mobj, event_t const *const e){ 150 | static int tick_count = 0; 151 | if(++tick_count == 30){ 152 | tick_count = 0; 153 | mobj->active_state = IDLE; 154 | return EVENT_TRANSITION; 155 | } 156 | return EVENT_IGNORED; 157 | } 158 | 159 | event_status_t STAT_Entry(protimer_t *const mobj, event_t const *const e){ 160 | display_time(mobj->pro_time); 161 | display_message("Productive TTT",1,1); 162 | return EVENT_HANDLED; 163 | } 164 | event_status_t STAT_Exit(protimer_t *const mobj, event_t const *const e){ 165 | display_clear(); 166 | return EVENT_HANDLED; 167 | } 168 | //////////////////////////helper functions////////////////////////// 169 | static void display_time(uint32_t time){ 170 | char buf[7]; 171 | String time_msg; 172 | 173 | uint16_t m = time / 60; 174 | uint8_t s = time % 60; 175 | sprintf(buf,"%03d:%02d",m,s); 176 | 177 | time_msg = (String)buf; 178 | lcd_set_cursor(5,0); 179 | lcd_print_string(time_msg); 180 | } 181 | 182 | static void display_message(String s,uint8_t c , uint8_t r){ 183 | lcd_set_cursor(c,r); 184 | lcd_print_string(s); 185 | } 186 | 187 | static void display_clear(void){ 188 | lcd_clear(); 189 | } 190 | 191 | static void do_beep(void){ 192 | tone(PIN_BUZZER, 4000, 25); 193 | } -------------------------------------------------------------------------------- /Course_Exercises/005Protimer_ST/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:uno] 12 | platform = atmelavr 13 | board = uno 14 | framework = arduino 15 | lib_deps = C:\Users\nieki\OneDrive\Documents\Arduino\libraries\qpn_avr 16 | -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/qm/.qhsmtst: -------------------------------------------------------------------------------- 1 | 2 | 3 | GPL 4 | 5 | 6 | 1 7 | 0 8 | 3 9 | 0 10 | 11 | 12 | 0,0,674,300 13 | 0,300,674,300 14 | 0,0,1227,655,* 15 | 16 | 17 | 2032128 18 | 0 19 | 20 | 21 | 22 | 23 | 0 24 | 25 | 26 | 27 | 28 | 0 29 | 30 | 31 | 0 32 | 33 | 34 | 35 | 36 | 0 37 | 38 | 39 | 0 40 | 41 | 42 | 43 | 44 | 0 45 | 46 | 47 | 0 48 | 49 | 50 | 51 | 52 | 0 53 | 54 | 55 | 0 56 | 57 | 58 | 59 | 60 | 0 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/qm/qhsmtst.qm: -------------------------------------------------------------------------------- 1 | 2 | 3 | QHsmTst is a contrived state machine from Chapter 2 of the PSiCC2 book for testing all possible transition topologies with up to 4-levels of state nesting. 4 | 5 | 6 | 7 | 8 | 9 | 10 | Test active object 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | me->foo = 0U; 20 | BSP_display("top-INIT;"); 21 | 22 | 23 | 24 | 25 | 26 | 27 | BSP_display("s-ENTRY;"); 28 | BSP_display("s-EXIT;"); 29 | 30 | 31 | BSP_display("s-INIT;"); 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | me->foo 41 | me->foo = 0U; 42 | BSP_display("s-I;"); 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | BSP_display("s-E;"); 54 | 55 | 56 | 57 | 58 | 59 | 60 | BSP_exit(); 61 | 62 | 63 | 64 | 65 | 66 | 67 | BSP_display("s1-ENTRY;"); 68 | BSP_display("s1-EXIT;"); 69 | 70 | 71 | BSP_display("s1-INIT;"); 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | !me->foo 85 | me->foo = 1U; 86 | BSP_display("s1-D;"); 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | BSP_display("s1-A;"); 98 | 99 | 100 | 101 | 102 | 103 | 104 | BSP_display("s1-B;"); 105 | 106 | 107 | 108 | 109 | 110 | 111 | BSP_display("s1-F;"); 112 | 113 | 114 | 115 | 116 | 117 | 118 | BSP_display("s1-C;"); 119 | 120 | 121 | 122 | 123 | 124 | 125 | BSP_display("s11-ENTRY;"); 126 | BSP_display("s11-EXIT;"); 127 | 128 | 129 | BSP_display("s11-H;"); 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | me->foo 139 | me->foo = 0U; 140 | BSP_display("s11-D;"); 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | BSP_display("s11-G;"); 152 | 153 | 154 | 155 | 156 | 157 | 158 | BSP_display("s11-I;"); 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | BSP_display("s12-ENTRY;"); 171 | BSP_display("s12-EXIT;"); 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | BSP_display("s2-ENTRY;"); 185 | BSP_display("s2-EXIT;"); 186 | 187 | 188 | BSP_display("s2-INIT;"); 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | !me->foo 198 | me->foo = 1U; 199 | BSP_display("s2-I;"); 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | BSP_display("s2-F;"); 211 | 212 | 213 | 214 | 215 | 216 | 217 | BSP_display("s2-C;"); 218 | 219 | 220 | 221 | 222 | 223 | 224 | BSP_display("s21-ENTRY;"); 225 | BSP_display("s21-EXIT;"); 226 | 227 | 228 | BSP_display("s21-INIT;"); 229 | 230 | 231 | 232 | 233 | 234 | 235 | BSP_display("s21-G;"); 236 | 237 | 238 | 239 | 240 | 241 | 242 | BSP_display("s21-A;"); 243 | 244 | 245 | 246 | 247 | 248 | 249 | BSP_display("s21-B;"); 250 | 251 | 252 | 253 | 254 | 255 | 256 | BSP_display("s211-ENTRY;"); 257 | BSP_display("s211-EXIT;"); 258 | 259 | 260 | BSP_display("s211-H;"); 261 | 262 | 263 | 264 | 265 | 266 | 267 | BSP_display("s211-D;"); 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | = &QHsmTst_obj.super; 298 | 299 | 300 | 301 | QHsm_ctor(super_QHsmTst,Q_STATE_CAST(&QHsmTst_initial)); 302 | 303 | 304 | 305 | 306 | 307 | 308 | #include <Arduino.h> 309 | #include "qpn.h" 310 | #include "QHSM_Test.h" 311 | #include "bsp.h" 312 | $declare${HSMs::QHsmTst} 313 | $define${HSMs::super_QHsmTst} 314 | $define${HSMs::QHsmTst_ctor} 315 | $define${HSMs::QHsmTst} 316 | 317 | 318 | 319 | #ifndef QHSM_TEST_H 320 | #define QHSM_TEST_H 321 | 322 | enum QHSM_Test_Signals{ 323 | A_SIG = Q_USER_SIG, 324 | B_SIG, 325 | C_SIG, 326 | D_SIG, 327 | E_SIG, 328 | F_SIG, 329 | G_SIG, 330 | H_SIG, 331 | I_SIG, 332 | TERMINATE_SIG, 333 | IGNORE_SIG, 334 | MAX_SIG 335 | }; 336 | 337 | $declare${HSMs::super_QHsmTst} 338 | $declare${HSMs::QHsmTst_ctor} 339 | 340 | #endif 341 | 342 | 343 | 344 | -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/src/QHSM_Test.cpp: -------------------------------------------------------------------------------- 1 | /*.$file${../src::QHSM_Test.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 2 | /* 3 | * Model: qhsmtst.qm 4 | * File: ${../src::QHSM_Test.cpp} 5 | * 6 | * This code has been generated by QM 5.1.1 . 7 | * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | * 9 | * This program is open source software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as published 11 | * by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * for more details. 17 | */ 18 | /*.$endhead${../src::QHSM_Test.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 19 | #include 20 | #include "qpn.h" 21 | #include "QHSM_Test.h" 22 | #include "bsp.h" 23 | /*.$declare${HSMs::QHsmTst} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 24 | /*.${HSMs::QHsmTst} ........................................................*/ 25 | typedef struct QHsmTst { 26 | /* protected: */ 27 | QHsm super; 28 | 29 | /* private: */ 30 | uint8_t foo; 31 | 32 | /* private state histories */ 33 | QStateHandler hist_s1; 34 | } QHsmTst; 35 | extern QHsmTst QHsmTst_obj; 36 | 37 | /* protected: */ 38 | static QState QHsmTst_initial(QHsmTst * const me); 39 | static QState QHsmTst_s(QHsmTst * const me); 40 | static QState QHsmTst_s1(QHsmTst * const me); 41 | static QState QHsmTst_s11(QHsmTst * const me); 42 | static QState QHsmTst_s12(QHsmTst * const me); 43 | static QState QHsmTst_s2(QHsmTst * const me); 44 | static QState QHsmTst_s21(QHsmTst * const me); 45 | static QState QHsmTst_s211(QHsmTst * const me); 46 | /*.$enddecl${HSMs::QHsmTst} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 47 | /*.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 48 | /*. Check for the minimum required QP version */ 49 | #if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U)) 50 | #error qpn version 6.9.0 or higher required 51 | #endif 52 | /*.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 53 | /*.$define${HSMs::super_QHsmTst} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 54 | /*.${HSMs::super_QHsmTst} ..................................................*/ 55 | QHsm *const super_QHsmTst = &QHsmTst_obj.super; 56 | /*.$enddef${HSMs::super_QHsmTst} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 57 | /*.$define${HSMs::QHsmTst_ctor} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 58 | /*.${HSMs::QHsmTst_ctor} ...................................................*/ 59 | void QHsmTst_ctor(void) { 60 | QHsm_ctor(super_QHsmTst,Q_STATE_CAST(&QHsmTst_initial)); 61 | } 62 | /*.$enddef${HSMs::QHsmTst_ctor} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 63 | /*.$define${HSMs::QHsmTst} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 64 | /*.${HSMs::QHsmTst} ........................................................*/ 65 | QHsmTst QHsmTst_obj; 66 | /*.${HSMs::QHsmTst::SM} ....................................................*/ 67 | static QState QHsmTst_initial(QHsmTst * const me) { 68 | /*.${HSMs::QHsmTst::SM::initial} */ 69 | me->foo = 0U; 70 | BSP_display("top-INIT;"); 71 | /* state history attributes */ 72 | /* state history attributes */ 73 | me->hist_s1 = Q_STATE_CAST(&QHsmTst_s11); 74 | return Q_TRAN(&QHsmTst_s2); 75 | } 76 | /*.${HSMs::QHsmTst::SM::s} .................................................*/ 77 | static QState QHsmTst_s(QHsmTst * const me) { 78 | QState status_; 79 | switch (Q_SIG(me)) { 80 | /*.${HSMs::QHsmTst::SM::s} */ 81 | case Q_ENTRY_SIG: { 82 | BSP_display("s-ENTRY;"); 83 | status_ = Q_HANDLED(); 84 | break; 85 | } 86 | /*.${HSMs::QHsmTst::SM::s} */ 87 | case Q_EXIT_SIG: { 88 | BSP_display("s-EXIT;"); 89 | status_ = Q_HANDLED(); 90 | break; 91 | } 92 | /*.${HSMs::QHsmTst::SM::s::initial} */ 93 | case Q_INIT_SIG: { 94 | BSP_display("s-INIT;"); 95 | status_ = Q_TRAN(&QHsmTst_s11); 96 | break; 97 | } 98 | /*.${HSMs::QHsmTst::SM::s::I} */ 99 | case I_SIG: { 100 | /*.${HSMs::QHsmTst::SM::s::I::[me->foo]} */ 101 | if (me->foo) { 102 | me->foo = 0U; 103 | BSP_display("s-I;"); 104 | status_ = Q_HANDLED(); 105 | } 106 | else { 107 | status_ = Q_UNHANDLED(); 108 | } 109 | break; 110 | } 111 | /*.${HSMs::QHsmTst::SM::s::E} */ 112 | case E_SIG: { 113 | BSP_display("s-E;"); 114 | status_ = Q_TRAN(&QHsmTst_s11); 115 | break; 116 | } 117 | /*.${HSMs::QHsmTst::SM::s::TERMINATE} */ 118 | case TERMINATE_SIG: { 119 | BSP_exit(); 120 | status_ = Q_HANDLED(); 121 | break; 122 | } 123 | default: { 124 | status_ = Q_SUPER(&QHsm_top); 125 | break; 126 | } 127 | } 128 | return status_; 129 | } 130 | /*.${HSMs::QHsmTst::SM::s::s1} .............................................*/ 131 | static QState QHsmTst_s1(QHsmTst * const me) { 132 | QState status_; 133 | switch (Q_SIG(me)) { 134 | /*.${HSMs::QHsmTst::SM::s::s1} */ 135 | case Q_ENTRY_SIG: { 136 | BSP_display("s1-ENTRY;"); 137 | status_ = Q_HANDLED(); 138 | break; 139 | } 140 | /*.${HSMs::QHsmTst::SM::s::s1} */ 141 | case Q_EXIT_SIG: { 142 | BSP_display("s1-EXIT;"); 143 | /* save deep history */ 144 | me->hist_s1 = QHsm_state(me); 145 | status_ = Q_HANDLED(); 146 | break; 147 | } 148 | /*.${HSMs::QHsmTst::SM::s::s1::initial} */ 149 | case Q_INIT_SIG: { 150 | BSP_display("s1-INIT;"); 151 | status_ = Q_TRAN(&QHsmTst_s11); 152 | break; 153 | } 154 | /*.${HSMs::QHsmTst::SM::s::s1::D} */ 155 | case D_SIG: { 156 | /*.${HSMs::QHsmTst::SM::s::s1::D::[!me->foo]} */ 157 | if (!me->foo) { 158 | me->foo = 1U; 159 | BSP_display("s1-D;"); 160 | status_ = Q_TRAN(&QHsmTst_s); 161 | } 162 | else { 163 | status_ = Q_UNHANDLED(); 164 | } 165 | break; 166 | } 167 | /*.${HSMs::QHsmTst::SM::s::s1::A} */ 168 | case A_SIG: { 169 | BSP_display("s1-A;"); 170 | status_ = Q_TRAN(&QHsmTst_s1); 171 | break; 172 | } 173 | /*.${HSMs::QHsmTst::SM::s::s1::B} */ 174 | case B_SIG: { 175 | BSP_display("s1-B;"); 176 | status_ = Q_TRAN(&QHsmTst_s11); 177 | break; 178 | } 179 | /*.${HSMs::QHsmTst::SM::s::s1::F} */ 180 | case F_SIG: { 181 | BSP_display("s1-F;"); 182 | status_ = Q_TRAN(&QHsmTst_s211); 183 | break; 184 | } 185 | /*.${HSMs::QHsmTst::SM::s::s1::C} */ 186 | case C_SIG: { 187 | BSP_display("s1-C;"); 188 | status_ = Q_TRAN(&QHsmTst_s2); 189 | break; 190 | } 191 | default: { 192 | status_ = Q_SUPER(&QHsmTst_s); 193 | break; 194 | } 195 | } 196 | return status_; 197 | } 198 | /*.${HSMs::QHsmTst::SM::s::s1::s11} ........................................*/ 199 | static QState QHsmTst_s11(QHsmTst * const me) { 200 | QState status_; 201 | switch (Q_SIG(me)) { 202 | /*.${HSMs::QHsmTst::SM::s::s1::s11} */ 203 | case Q_ENTRY_SIG: { 204 | BSP_display("s11-ENTRY;"); 205 | status_ = Q_HANDLED(); 206 | break; 207 | } 208 | /*.${HSMs::QHsmTst::SM::s::s1::s11} */ 209 | case Q_EXIT_SIG: { 210 | BSP_display("s11-EXIT;"); 211 | status_ = Q_HANDLED(); 212 | break; 213 | } 214 | /*.${HSMs::QHsmTst::SM::s::s1::s11::H} */ 215 | case H_SIG: { 216 | BSP_display("s11-H;"); 217 | status_ = Q_TRAN(&QHsmTst_s); 218 | break; 219 | } 220 | /*.${HSMs::QHsmTst::SM::s::s1::s11::D} */ 221 | case D_SIG: { 222 | /*.${HSMs::QHsmTst::SM::s::s1::s11::D::[me->foo]} */ 223 | if (me->foo) { 224 | me->foo = 0U; 225 | BSP_display("s11-D;"); 226 | status_ = Q_TRAN(&QHsmTst_s1); 227 | } 228 | else { 229 | status_ = Q_UNHANDLED(); 230 | } 231 | break; 232 | } 233 | /*.${HSMs::QHsmTst::SM::s::s1::s11::G} */ 234 | case G_SIG: { 235 | BSP_display("s11-G;"); 236 | status_ = Q_TRAN(&QHsmTst_s211); 237 | break; 238 | } 239 | /*.${HSMs::QHsmTst::SM::s::s1::s11::I} */ 240 | case I_SIG: { 241 | BSP_display("s11-I;"); 242 | status_ = Q_TRAN(&QHsmTst_s12); 243 | break; 244 | } 245 | default: { 246 | status_ = Q_SUPER(&QHsmTst_s1); 247 | break; 248 | } 249 | } 250 | return status_; 251 | } 252 | /*.${HSMs::QHsmTst::SM::s::s1::s12} ........................................*/ 253 | static QState QHsmTst_s12(QHsmTst * const me) { 254 | QState status_; 255 | switch (Q_SIG(me)) { 256 | /*.${HSMs::QHsmTst::SM::s::s1::s12} */ 257 | case Q_ENTRY_SIG: { 258 | BSP_display("s12-ENTRY;"); 259 | status_ = Q_HANDLED(); 260 | break; 261 | } 262 | /*.${HSMs::QHsmTst::SM::s::s1::s12} */ 263 | case Q_EXIT_SIG: { 264 | BSP_display("s12-EXIT;"); 265 | status_ = Q_HANDLED(); 266 | break; 267 | } 268 | default: { 269 | status_ = Q_SUPER(&QHsmTst_s1); 270 | break; 271 | } 272 | } 273 | return status_; 274 | } 275 | /*.${HSMs::QHsmTst::SM::s::s2} .............................................*/ 276 | static QState QHsmTst_s2(QHsmTst * const me) { 277 | QState status_; 278 | switch (Q_SIG(me)) { 279 | /*.${HSMs::QHsmTst::SM::s::s2} */ 280 | case Q_ENTRY_SIG: { 281 | BSP_display("s2-ENTRY;"); 282 | status_ = Q_HANDLED(); 283 | break; 284 | } 285 | /*.${HSMs::QHsmTst::SM::s::s2} */ 286 | case Q_EXIT_SIG: { 287 | BSP_display("s2-EXIT;"); 288 | status_ = Q_HANDLED(); 289 | break; 290 | } 291 | /*.${HSMs::QHsmTst::SM::s::s2::initial} */ 292 | case Q_INIT_SIG: { 293 | BSP_display("s2-INIT;"); 294 | status_ = Q_TRAN(&QHsmTst_s21); 295 | break; 296 | } 297 | /*.${HSMs::QHsmTst::SM::s::s2::I} */ 298 | case I_SIG: { 299 | /*.${HSMs::QHsmTst::SM::s::s2::I::[!me->foo]} */ 300 | if (!me->foo) { 301 | me->foo = 1U; 302 | BSP_display("s2-I;"); 303 | status_ = Q_HANDLED(); 304 | } 305 | else { 306 | status_ = Q_UNHANDLED(); 307 | } 308 | break; 309 | } 310 | /*.${HSMs::QHsmTst::SM::s::s2::F} */ 311 | case F_SIG: { 312 | BSP_display("s2-F;"); 313 | status_ = Q_TRAN_HIST(me->hist_s1); 314 | break; 315 | } 316 | /*.${HSMs::QHsmTst::SM::s::s2::C} */ 317 | case C_SIG: { 318 | BSP_display("s2-C;"); 319 | status_ = Q_TRAN(&QHsmTst_s1); 320 | break; 321 | } 322 | default: { 323 | status_ = Q_SUPER(&QHsmTst_s); 324 | break; 325 | } 326 | } 327 | return status_; 328 | } 329 | /*.${HSMs::QHsmTst::SM::s::s2::s21} ........................................*/ 330 | static QState QHsmTst_s21(QHsmTst * const me) { 331 | QState status_; 332 | switch (Q_SIG(me)) { 333 | /*.${HSMs::QHsmTst::SM::s::s2::s21} */ 334 | case Q_ENTRY_SIG: { 335 | BSP_display("s21-ENTRY;"); 336 | status_ = Q_HANDLED(); 337 | break; 338 | } 339 | /*.${HSMs::QHsmTst::SM::s::s2::s21} */ 340 | case Q_EXIT_SIG: { 341 | BSP_display("s21-EXIT;"); 342 | status_ = Q_HANDLED(); 343 | break; 344 | } 345 | /*.${HSMs::QHsmTst::SM::s::s2::s21::initial} */ 346 | case Q_INIT_SIG: { 347 | BSP_display("s21-INIT;"); 348 | status_ = Q_TRAN(&QHsmTst_s211); 349 | break; 350 | } 351 | /*.${HSMs::QHsmTst::SM::s::s2::s21::G} */ 352 | case G_SIG: { 353 | BSP_display("s21-G;"); 354 | status_ = Q_TRAN(&QHsmTst_s1); 355 | break; 356 | } 357 | /*.${HSMs::QHsmTst::SM::s::s2::s21::A} */ 358 | case A_SIG: { 359 | BSP_display("s21-A;"); 360 | status_ = Q_TRAN(&QHsmTst_s21); 361 | break; 362 | } 363 | /*.${HSMs::QHsmTst::SM::s::s2::s21::B} */ 364 | case B_SIG: { 365 | BSP_display("s21-B;"); 366 | status_ = Q_TRAN(&QHsmTst_s211); 367 | break; 368 | } 369 | default: { 370 | status_ = Q_SUPER(&QHsmTst_s2); 371 | break; 372 | } 373 | } 374 | return status_; 375 | } 376 | /*.${HSMs::QHsmTst::SM::s::s2::s21::s211} ..................................*/ 377 | static QState QHsmTst_s211(QHsmTst * const me) { 378 | QState status_; 379 | switch (Q_SIG(me)) { 380 | /*.${HSMs::QHsmTst::SM::s::s2::s21::s211} */ 381 | case Q_ENTRY_SIG: { 382 | BSP_display("s211-ENTRY;"); 383 | status_ = Q_HANDLED(); 384 | break; 385 | } 386 | /*.${HSMs::QHsmTst::SM::s::s2::s21::s211} */ 387 | case Q_EXIT_SIG: { 388 | BSP_display("s211-EXIT;"); 389 | status_ = Q_HANDLED(); 390 | break; 391 | } 392 | /*.${HSMs::QHsmTst::SM::s::s2::s21::s211::H} */ 393 | case H_SIG: { 394 | BSP_display("s211-H;"); 395 | status_ = Q_TRAN(&QHsmTst_s); 396 | break; 397 | } 398 | /*.${HSMs::QHsmTst::SM::s::s2::s21::s211::D} */ 399 | case D_SIG: { 400 | BSP_display("s211-D;"); 401 | status_ = Q_TRAN(&QHsmTst_s21); 402 | break; 403 | } 404 | default: { 405 | status_ = Q_SUPER(&QHsmTst_s21); 406 | break; 407 | } 408 | } 409 | return status_; 410 | } 411 | /*.$enddef${HSMs::QHsmTst} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 412 | -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/src/QHSM_Test.h: -------------------------------------------------------------------------------- 1 | /*.$file${../src::QHSM_Test.h} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 2 | /* 3 | * Model: qhsmtst.qm 4 | * File: ${../src::QHSM_Test.h} 5 | * 6 | * This code has been generated by QM 5.1.1 . 7 | * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | * 9 | * This program is open source software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as published 11 | * by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * for more details. 17 | */ 18 | /*.$endhead${../src::QHSM_Test.h} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 19 | #ifndef QHSM_TEST_H 20 | #define QHSM_TEST_H 21 | 22 | enum QHSM_Test_Signals{ 23 | A_SIG = Q_USER_SIG, 24 | B_SIG, 25 | C_SIG, 26 | D_SIG, 27 | E_SIG, 28 | F_SIG, 29 | G_SIG, 30 | H_SIG, 31 | I_SIG, 32 | TERMINATE_SIG, 33 | IGNORE_SIG, 34 | MAX_SIG 35 | }; 36 | 37 | /*.$declare${HSMs::super_QHsmTst} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 38 | extern QHsm *const super_QHsmTst; 39 | /*.$enddecl${HSMs::super_QHsmTst} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 40 | /*.$declare${HSMs::QHsmTst_ctor} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 41 | /*.${HSMs::QHsmTst_ctor} ...................................................*/ 42 | void QHsmTst_ctor(void); 43 | /*.$enddecl${HSMs::QHsmTst_ctor} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 44 | 45 | #endif -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/src/bsp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void BSP_display(String str){ 4 | Serial.print(str); 5 | } 6 | 7 | void BSP_exit(void){ 8 | Serial.println("Bye!!"); 9 | } -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/src/bsp.h: -------------------------------------------------------------------------------- 1 | #ifndef BSP_H 2 | #define BSP_H 3 | 4 | void BSP_display(String str); 5 | void BSP_exit(void); 6 | 7 | #endif -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "qpn.h" 3 | #include "QHSM_Test.h" 4 | Q_DEFINE_THIS_FILE; 5 | 6 | void setup() { 7 | // put your setup code here, to run once: 8 | Serial.begin(9600); 9 | Serial.println("QHSM Testing..."); 10 | QHsmTst_ctor(); 11 | QHSM_INIT(super_QHsmTst); 12 | Serial.print('\n'); 13 | } 14 | 15 | void loop() { 16 | // put your main code here, to run repeatedly: 17 | char ue; 18 | if(Serial.available() > 0){ 19 | ue = Serial.read(); 20 | if(ue == 'a' || ue == 'A'){ 21 | Q_SIG(super_QHsmTst) = (QSignal)A_SIG; 22 | } 23 | else if (ue == 'b' || ue == 'B') Q_SIG(super_QHsmTst) = (QSignal)B_SIG; 24 | else if (ue == 'c' || ue == 'C') Q_SIG(super_QHsmTst) = (QSignal)C_SIG; 25 | else if (ue == 'd' || ue == 'D') Q_SIG(super_QHsmTst) = (QSignal)D_SIG; 26 | else if (ue == 'e' || ue == 'E') Q_SIG(super_QHsmTst) = (QSignal)E_SIG; 27 | else if (ue == 'f' || ue == 'F') Q_SIG(super_QHsmTst) = (QSignal)F_SIG; 28 | else if (ue == 'g' || ue == 'G') Q_SIG(super_QHsmTst) = (QSignal)G_SIG; 29 | else if (ue == 'h' || ue == 'H') Q_SIG(super_QHsmTst) = (QSignal)H_SIG; 30 | else if (ue == 'i' || ue == 'I') Q_SIG(super_QHsmTst) = (QSignal)I_SIG; 31 | else if (ue == 'x' || ue == 'X') Q_SIG(super_QHsmTst) = (QSignal)TERMINATE_SIG; 32 | else Q_SIG(super_QHsmTst) = IGNORE_SIG; 33 | 34 | QHSM_DISPATCH(super_QHsmTst); 35 | Serial.print('\n'); 36 | } 37 | 38 | } 39 | 40 | 41 | Q_NORETURN Q_onAssert ( char_t const Q_ROM *const module,int_t const location ){ 42 | 43 | Serial.println("Assertion failure!!"); 44 | Serial.println((String)module); 45 | Serial.println(location); 46 | while(1); 47 | } -------------------------------------------------------------------------------- /Course_Exercises/006QHsmTest/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:uno] 12 | platform = atmelavr 13 | board = uno 14 | framework = arduino 15 | lib_deps = 16 | arduino-libraries/LiquidCrystal@^1.0.7 17 | C:\Users\nieki\OneDrive\Documents\Arduino\libraries\qpn_avr 18 | -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/qm/.ClockAlarm: -------------------------------------------------------------------------------- 1 | 2 | 3 | GPL 4 | 5 | 6 | 1 7 | 0 8 | 3 9 | 0 10 | 11 | 12 | -361,0,899,655 13 | 0,0,633,655,* 14 | 0,0,1268,655 15 | 16 | 17 | 2032128 18 | 0 19 | 20 | 21 | 22 | 23 | 0 24 | 25 | 26 | 27 | 28 | 0 29 | 30 | 31 | 0 32 | 33 | 34 | 35 | 36 | 0 37 | 38 | 39 | 0 40 | 41 | 42 | 43 | 44 | 0 45 | 46 | 47 | 0 48 | 49 | 50 | 51 | 52 | 0 53 | 54 | 55 | 0 56 | 57 | 58 | 59 | 60 | 0 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/src/ClockAlarm_SM.h: -------------------------------------------------------------------------------- 1 | /*.$file${HSMs::../src::ClockAlarm_SM.h} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 2 | /* 3 | * Model: ClockAlarm.qm 4 | * File: ${HSMs::../src::ClockAlarm_SM.h} 5 | * 6 | * This code has been generated by QM 5.1.1 . 7 | * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | * 9 | * This program is open source software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as published 11 | * by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * for more details. 17 | */ 18 | /*.$endhead${HSMs::../src::ClockAlarm_SM.h} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 19 | #ifndef CLOCK_ALARM_H 20 | #define CLOCK_ALARM_H 21 | 22 | enum ClockAlarm_Signals{ 23 | SET_SIG = Q_USER_SIG, 24 | OK_SIG, 25 | ABRT_SIG, 26 | ALARM_SIG, 27 | TICK_SIG, 28 | IGNORE_SIG, 29 | MAX_SIG 30 | }; 31 | 32 | enum time_mode{ 33 | MODE_24H, 34 | MODE_12H 35 | }; 36 | 37 | enum alarm_status{ 38 | ALARM_OFF, 39 | ALARM_ON 40 | }; 41 | 42 | typedef enum time_format{ 43 | FORMAT_24H, 44 | FORMAT_AM, 45 | FORMAT_PM 46 | }time_format_t; 47 | 48 | #define GET_HOUR(seconds) (seconds/3600UL) 49 | #define GET_MIN(seconds) ((seconds/60UL)%60UL) 50 | #define GET_SEC(seconds) (seconds % 60UL) 51 | #define DIGIT1(d) (d/10U) 52 | #define DIGIT2(d) (d%10U) 53 | 54 | #define MAX_TIME (864000UL) 55 | #define INITIAL_CURR_TIME ((10UL * 3600UL + 10UL * 60UL + 10UL) * 10UL) 56 | #define INITIAL_ALARM_TIME (8UL * 3600UL) 57 | 58 | #define TICKING_CURR_TIME_ROW 0 59 | #define TICKING_CURR_TIME_COL 3 60 | #define CLOCK_SETTING_TIME_ROW 0 61 | #define CLOCK_SETTING_TIME_COL 2 62 | #define CLOCK_SETTING_TIME_HOUR_D1_COL 2 63 | #define CLOCK_SETTING_TIME_HOUR_D2_COL 3 64 | #define CLOCK_SETTING_TIME_MIN_D1_COL 5 65 | #define CLOCK_SETTING_TIME_MIN_D2_COL 6 66 | #define CLOCK_SETTING_TIME_SEC_D1_COL 8 67 | #define CLOCK_SETTING_TIME_SEC_D2_COL 9 68 | #define CLOCK_SETTING_TIME_FMT_COL 11 69 | #define CLOCK_SETTING_ERR_MSG_ROW 1 70 | #define CLOCK_SETTING_ERR_MSG_COL 4 71 | #define CLOCK_SETTING_ERR_MSG_COL_END 9 72 | 73 | #define ALARM_SETTING_CURR_TIME_ROW 1 74 | #define ALARM_SETTING_CURR_TIME_COL 2 75 | #define ALARM_SETTING_STATUS_ROW 0 76 | #define ALARM_SETTING_STATUS_COL 4 77 | #define ALARM_NOTIFY_MSG_ROW 0 78 | #define ALARM_NOTIFY_MSG_COL 4 79 | 80 | #define CS_ROW 0 81 | #define CS_HOUR_D1_COL 2 82 | /*.$declare${HSMs::Clock_Alarm_ctor} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 83 | /*.${HSMs::Clock_Alarm_ctor} ...............................................*/ 84 | void Clock_Alarm_ctor(void); 85 | /*.$enddecl${HSMs::Clock_Alarm_ctor} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 86 | /*.$declare${HSMs::super_ClockAlarm} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 87 | extern QHsm *const super_ClockAlarm; 88 | /*.$enddecl${HSMs::super_ClockAlarm} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 89 | 90 | #endif -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/src/lcd.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "lcd.h" 4 | 5 | #include 6 | 7 | LiquidCrystal lcd(PIN_LCD_RS,PIN_LCD_RW,PIN_LCD_EN,PIN_LCD_D4,PIN_LCD_D5,PIN_LCD_D6,PIN_LCD_D7); 8 | 9 | void lcd_clear(void){ 10 | lcd.clear(); 11 | } 12 | void lcd_print_char(char c){ 13 | lcd.print(c); 14 | } 15 | 16 | void lcd_scroll_left(void){ 17 | lcd.scrollDisplayLeft(); 18 | } 19 | void lcd_scroll_right(void){ 20 | lcd.scrollDisplayRight(); 21 | } 22 | void lcd_set_cursor(int c, int r){ 23 | lcd.setCursor(c,r); 24 | } 25 | void lcd_no_auto_scroll(void){ 26 | lcd.noAutoscroll(); 27 | } 28 | void lcd_begin(uint8_t cols , uint8_t rows){ 29 | lcd.begin(cols,rows); 30 | } 31 | void lcd_move_cursor_R_to_L(void){ 32 | lcd.rightToLeft(); 33 | } 34 | void lcd_move_cursor_L_to_R(void){ 35 | lcd.leftToRight(); 36 | } 37 | void lcd_cursor_off(void){ 38 | lcd.noCursor(); 39 | } 40 | void lcd_cursor_blinkoff(void){ 41 | lcd.noBlink(); 42 | } 43 | void lcd_print_number(int num){ 44 | lcd.print(num); 45 | } 46 | void lcd_print_string(String s){ 47 | lcd.print(s); 48 | } 49 | 50 | void lcd_cursor_show(void) 51 | { 52 | lcd.cursor(); 53 | } 54 | 55 | void lcd_cursor_blink(void) 56 | { 57 | lcd.blink(); 58 | } 59 | 60 | void lcd_create_custom_char(byte num, byte* data) { 61 | lcd.createChar(num, data); 62 | } 63 | 64 | void lcd_display_custom_char(byte num){ 65 | lcd.write(num); 66 | } -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/src/lcd.h: -------------------------------------------------------------------------------- 1 | #ifndef LCD_H 2 | #define LCD_H 3 | 4 | #include 5 | 6 | void lcd_clear(void); 7 | void lcd_print_char(char c); 8 | void lcd_scroll_left(void); 9 | void lcd_scroll_right(void); 10 | void lcd_set_cursor(int c, int r); 11 | void lcd_no_auto_scroll(void); 12 | void lcd_begin(uint8_t cols, uint8_t rows); 13 | void lcd_move_cursor_R_to_L(void); 14 | void lcd_move_cursor_L_to_R(void); 15 | void lcd_cursor_off(void); 16 | void lcd_cursor_blinkoff(void); 17 | void lcd_print_number(int num); 18 | void lcd_print_string(String s); 19 | void lcd_cursor_blink(void); 20 | void lcd_cursor_show(void); 21 | void lcd_create_custom_char(byte num, byte *data); 22 | void lcd_display_custom_char(byte num); 23 | 24 | //lcd connections 25 | #define PIN_LCD_RS 5 26 | #define PIN_LCD_RW 6 27 | #define PIN_LCD_EN 7 28 | #define PIN_LCD_D4 8 29 | #define PIN_LCD_D5 9 30 | #define PIN_LCD_D6 10 31 | #define PIN_LCD_D7 11 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "qpn.h" 3 | #include "ClockAlarm_SM.h" 4 | #include "lcd.h" 5 | #include "main.h" 6 | 7 | Q_DEFINE_THIS_FILE; 8 | 9 | static void Timer1_setup(void); 10 | static void display_init(void); 11 | static uint8_t process_button_pad_value(uint8_t btn_pad_value); 12 | 13 | void setup() { 14 | // put your setup code here, to run once: 15 | Serial.begin(9600); 16 | display_init(); 17 | Clock_Alarm_ctor(); 18 | QHSM_INIT(super_ClockAlarm); 19 | Timer1_setup(); 20 | } 21 | 22 | void loop() { 23 | // put your main code here, to run repeatedly: 24 | static uint32_t tick_time = millis(); 25 | static uint32_t alarm_check_time = millis(); 26 | uint8_t b1,b2,btn_pad_value; 27 | 28 | //1. read the button pad status 29 | b1 = digitalRead(PIN_BUTTON1); 30 | b2 = digitalRead(PIN_BUTTON2); 31 | 32 | btn_pad_value = (b1<<1u)|b2; 33 | 34 | //software button de-bouncing 35 | btn_pad_value = process_button_pad_value(btn_pad_value); 36 | 37 | while(millis() - tick_time >= 50 ){ 38 | //send TICK event 39 | tick_time = millis(); 40 | Q_SIG(super_ClockAlarm) = TICK_SIG; 41 | QHSM_DISPATCH(super_ClockAlarm); 42 | } 43 | 44 | while(millis() - alarm_check_time >= 500 ){ 45 | //send TICK event 46 | alarm_check_time = millis(); 47 | Q_SIG(super_ClockAlarm) = ALARM_SIG; 48 | QHSM_DISPATCH(super_ClockAlarm); 49 | } 50 | 51 | if(btn_pad_value){ 52 | if(btn_pad_value == BTN_PAD_VALUE_SET){ 53 | Q_SIG(super_ClockAlarm) = SET_SIG; 54 | }else if(btn_pad_value == BTN_PAD_VALUE_OK){ 55 | Q_SIG(super_ClockAlarm) = OK_SIG; 56 | }else if(btn_pad_value == BTN_PAD_VALUE_ABRT){ 57 | Q_SIG(super_ClockAlarm) = ABRT_SIG; 58 | }else 59 | Q_SIG(super_ClockAlarm) = IGNORE_SIG; 60 | 61 | QHSM_DISPATCH(super_ClockAlarm); 62 | } 63 | 64 | } 65 | 66 | static void Timer1_setup(void){ 67 | TCCR1A = 0; //CTC mode 68 | TCCR1B = B00001100; //prescaler=256,CTC mode 69 | TIMSK1 |= B00000010; //Interrupt enable for OCR1A compare match 70 | OCR1A = 6250-1; //OC match value for 100ms time base generation 71 | } 72 | 73 | 74 | 75 | static void display_init(void) 76 | { 77 | lcd_begin(16,2); 78 | lcd_clear(); 79 | lcd_move_cursor_L_to_R(); 80 | lcd_set_cursor(0,0); 81 | lcd_no_auto_scroll(); 82 | lcd_cursor_off(); 83 | } 84 | 85 | Q_NORETURN Q_onAssert ( char_t const Q_ROM *const module,int_t const location ){ 86 | 87 | Serial.println("Assertion failure!!"); 88 | Serial.println((String)module); 89 | Serial.println(location); 90 | while(1); 91 | } 92 | 93 | 94 | static uint8_t process_button_pad_value(uint8_t btn_pad_value) 95 | { 96 | static button_state_t btn_sm_state = NOT_PRESSED; 97 | static uint32_t curr_time = millis(); 98 | 99 | switch(btn_sm_state){ 100 | case NOT_PRESSED:{ 101 | if(btn_pad_value){ 102 | btn_sm_state = BOUNCE; 103 | curr_time = millis(); 104 | } 105 | break; 106 | } 107 | case BOUNCE:{ 108 | if(millis() - curr_time >= 50 ){ 109 | //50ms has passed 110 | if(btn_pad_value){ 111 | btn_sm_state = PRESSED; 112 | return btn_pad_value; 113 | } 114 | else 115 | btn_sm_state = NOT_PRESSED; 116 | } 117 | break; 118 | } 119 | case PRESSED:{ 120 | if(!btn_pad_value){ 121 | btn_sm_state = BOUNCE; 122 | curr_time = millis(); 123 | } 124 | break; 125 | } 126 | 127 | } 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/src/main.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_H 2 | #define MAIN_H 3 | 4 | #define PIN_BUTTON1 2 5 | #define PIN_BUTTON2 3 6 | #define PIN_BUZZER 12 7 | 8 | #define BTN_PAD_VALUE_SET 2 9 | #define BTN_PAD_VALUE_OK 1 10 | #define BTN_PAD_VALUE_ABRT 3 11 | 12 | 13 | typedef enum{ 14 | NOT_PRESSED, 15 | BOUNCE, 16 | PRESSED 17 | }button_state_t; 18 | 19 | 20 | 21 | #endif -------------------------------------------------------------------------------- /Course_Exercises/007ClockAlarm/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:uno] 12 | platform = atmelavr 13 | board = uno 14 | framework = arduino 15 | lib_deps = 16 | arduino-libraries/LiquidCrystal@^1.0.7 17 | C:\Users\nieki\OneDrive\Documents\Arduino\libraries\qpn_avr 18 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/qm/.ClockAlarm: -------------------------------------------------------------------------------- 1 | 2 | 3 | GPL 4 | 5 | 6 | 1 7 | 0 8 | 3 9 | 0 10 | 11 | 12 | -246,0,1202,676 13 | 0,0,932,494,* 14 | 0,0,674,300 15 | 282,300,674,300 16 | 282,0,674,300 17 | 0,355,1152,349 18 | 0,0,674,300 19 | 316,224,640,480 20 | 0,0,640,480 21 | 22 | 23 | 2032128 24 | 0 25 | 26 | 27 | 28 | 29 | 0 30 | 31 | 32 | 33 | 34 | 0 35 | 36 | 37 | 0 38 | 39 | 40 | 41 | 42 | 0 43 | 44 | 45 | 0 46 | 47 | 48 | 49 | 50 | 0 51 | 52 | 53 | 0 54 | 55 | 56 | 57 | 58 | 0 59 | 60 | 61 | 0 62 | 63 | 64 | 65 | 66 | 0 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/qm/ClockAlarm.qm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | This returns the value of curr_time 17 | uint8_t saved_sreg = SREG; 18 | uint32_t temp; 19 | cli(); 20 | temp = Clock_Alarm_curr_time; 21 | SREG = saved_sreg; 22 | return temp; 23 | 24 | 25 | if(++Clock_Alarm_curr_time == MAX_TIME){ 26 | Clock_Alarm_curr_time = 0; 27 | } 28 | 29 | 30 | 31 | uint8_t save_sreg; 32 | save_sreg = SREG; 33 | cli(); 34 | TCCR1B &= ~(0x7U); //Stop the TIMER1 35 | TCNT1 = 0U; 36 | Clock_Alarm_curr_time = new_curr_time; 37 | TCCR1B = (TCCR1B_CTC_MODE |TCCR1B_PRESCALER_1); 38 | SREG = save_sreg; 39 | 40 | 41 | 42 | 43 | String time_as_string; 44 | uint32_t time_; 45 | 46 | uint32_t time24h = Clock_Alarm_get_curr_time(); 47 | uint8_t ss = time24h % 10U; //extract sub-second to append later 48 | time24h /= 10; //convert to number of seconds 49 | 50 | time_ = (me->time_mode == MODE_24H)?time24h:convert_24hformat_to_12h(time24h); 51 | time_as_string = integertime_to_string(time_); //hh:mm:ss 52 | time_as_string.concat('.'); 53 | time_as_string.concat(ss); 54 | 55 | /*if mode is 12H , concatenate am/pm information */ 56 | if(me->time_mode == MODE_12H){ 57 | time_as_string.concat(' '); 58 | time_as_string.concat(get_am_or_pm(time24h)); 59 | } 60 | 61 | display_write(time_as_string,row,col); 62 | 63 | 64 | 65 | 66 | String time_as_string; 67 | 68 | time_as_string = integertime_to_string(me->temp_time); //hh:mm:ss 69 | 70 | /*concatenate am/pm information */ 71 | if(me->temp_format != FORMAT_24H){ 72 | time_as_string.concat(' '); 73 | if(me->temp_format == FORMAT_AM) 74 | time_as_string.concat("AM"); 75 | else 76 | time_as_string.concat("PM"); 77 | } 78 | 79 | display_write(time_as_string,row,col); 80 | 81 | 82 | 83 | Alarm_init(&me->alarm); 84 | Clock_Alarm_set_curr_time(INITIAL_CURR_TIME); 85 | me->time_mode = MODE_12H; 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | Q_SIG(&me->alarm) = ALARM_CHECK_SIG; 101 | Q_PAR(&me->alarm) = Clock_Alarm_get_curr_time()/10; 102 | Alarm_dispatch(&me->alarm); 103 | if(me->curr_setting == NO_SETTING) 104 | Clock_Alarm_display_curr_time(me,TICKING_CURR_TIME_ROW,TICKING_CURR_TIME_COL); 105 | else if(me->curr_setting == ALARM_SETTING){ 106 | Clock_Alarm_display_curr_time(me,ALARM_SETTING_CURR_TIME_ROW,ALARM_SETTING_CURR_TIME_COL); 107 | if( QHsm_state(me) != Q_STATE_CAST(&Clock_Alarm_alarm_on_off)) 108 | Clock_Alarm_display_clock_setting_time(me,CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_COL); 109 | 110 | if( QHsm_state(me) == Q_STATE_CAST(&Clock_Alarm_hd1)) 111 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_HOUR_D1_COL); 112 | else if( QHsm_state(me) == Q_STATE_CAST(&Clock_Alarm_hd2)) 113 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_HOUR_D2_COL); 114 | else if( QHsm_state(me) == Q_STATE_CAST(&Clock_Alarm_md1)) 115 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_MIN_D1_COL); 116 | else if( QHsm_state(me) == Q_STATE_CAST(&Clock_Alarm_md2)) 117 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_MIN_D2_COL); 118 | else if( QHsm_state(me) == Q_STATE_CAST(&Clock_Alarm_sd1)) 119 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_SEC_D1_COL); 120 | else if( QHsm_state(me) == Q_STATE_CAST(&Clock_Alarm_sd2)) 121 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_SEC_D2_COL); 122 | else if( QHsm_state(me) == Q_STATE_CAST(&Clock_Alarm_clock_format)) 123 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 124 | else if( QHsm_state(me) == Q_STATE_CAST(&Clock_Alarm_alarm_on_off)) 125 | display_set_cursor(CLOCK_SETTING_TIME_ROW,ALARM_SETTING_STATUS_COL); 126 | } 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | Clock_Alarm_display_curr_time(me,TICKING_CURR_TIME_ROW,TICKING_CURR_TIME_COL); 138 | me->curr_setting = NO_SETTING; 139 | display_clear(); 140 | 141 | me->curr_setting =CLOCK_SETTING; 142 | me->temp_time = Clock_Alarm_get_curr_time()/10; 143 | if(me->time_mode == MODE_12H){ 144 | if(get_am_or_pm(me->temp_time).equals("AM")){ 145 | me->temp_format = FORMAT_AM; 146 | } 147 | else{ 148 | me->temp_format = FORMAT_PM; 149 | } 150 | me->temp_time = convert_24hformat_to_12h(me->temp_time); 151 | } 152 | else 153 | me->temp_format = FORMAT_24H; 154 | 155 | 156 | 157 | 158 | 159 | me->curr_setting =ALARM_SETTING; 160 | me->temp_time = Alarm_get_alarm_time(&me->alarm); 161 | if(me->time_mode == MODE_12H){ 162 | if(get_am_or_pm(me->temp_time).equals("AM")){ 163 | me->temp_format = FORMAT_AM; 164 | } 165 | else{ 166 | me->temp_format = FORMAT_PM; 167 | } 168 | me->temp_time = convert_24hformat_to_12h(me->temp_time); 169 | } 170 | else 171 | me->temp_format = FORMAT_24H; 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | Clock_Alarm_display_clock_setting_time(me,CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_COL); 183 | display_cursor_on_blinkon(); 184 | display_clear(); 185 | display_cursor_off_blinkoff(); 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | if(me->curr_setting == CLOCK_SETTING){ 198 | if(me->temp_format != FORMAT_24H){ 199 | me->temp_time = convert_12hformat_to_24h( me->temp_time,(time_format_t)me->temp_format); 200 | me->time_mode = MODE_12H; 201 | }else{ 202 | me->time_mode = MODE_24H; 203 | } 204 | me->temp_time *= 10UL; 205 | Clock_Alarm_set_curr_time(me->temp_time); 206 | }else if(me->curr_setting == ALARM_SETTING){ 207 | //me->alarm_status = me->temp_digit; 208 | if(me->temp_format != FORMAT_24H){ 209 | me->temp_time = convert_12hformat_to_24h( me->temp_time,(time_format_t)me->temp_format); 210 | } 211 | Alarm_set_alarm_time(&me->alarm,me->temp_time); 212 | Alarm_set_status(&me->alarm,me->temp_digit); 213 | } 214 | 215 | 216 | 217 | 218 | 219 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_HOUR_D2_COL); 220 | me->temp_digit = DIGIT2(GET_HOUR(me->temp_time)); 221 | 222 | ++me->temp_digit; 223 | me->temp_digit %= 10; 224 | me->temp_time -= DIGIT2(GET_HOUR(me->temp_time)) * 3600UL; 225 | me->temp_time += (me->temp_digit) * 3600UL; 226 | Clock_Alarm_display_clock_setting_time(me,CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_COL); 227 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_HOUR_D2_COL); 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_MIN_D1_COL); 243 | me->temp_digit = DIGIT1(GET_MIN(me->temp_time)); 244 | 245 | ++me->temp_digit; 246 | me->temp_digit %= 6; 247 | me->temp_time -= DIGIT1(GET_MIN(me->temp_time)) *10UL * 60UL; 248 | me->temp_time += (me->temp_digit) * 10UL * 60UL; 249 | Clock_Alarm_display_clock_setting_time(me,CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_COL); 250 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_MIN_D1_COL); 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_MIN_D2_COL); 266 | me->temp_digit = DIGIT2(GET_MIN(me->temp_time)); 267 | 268 | ++me->temp_digit; 269 | me->temp_digit %= 10; 270 | me->temp_time -= DIGIT2(GET_MIN(me->temp_time)) * 60UL; 271 | me->temp_time += (me->temp_digit) * 60UL; 272 | Clock_Alarm_display_clock_setting_time(me,CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_COL); 273 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_MIN_D2_COL); 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_SEC_D2_COL); 289 | me->temp_digit = DIGIT2(GET_SEC(me->temp_time)); 290 | 291 | ++me->temp_digit; 292 | me->temp_digit %= 10; 293 | me->temp_time -= DIGIT2(GET_SEC(me->temp_time)); 294 | me->temp_time += me->temp_digit; 295 | Clock_Alarm_display_clock_setting_time(me,CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_COL); 296 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_SEC_D2_COL); 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 313 | String msg[3] = {"24H","AM ","PM "}; 314 | display_write(msg[me->temp_format],CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 315 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 316 | 317 | String msg; 318 | if(me->temp_format == FORMAT_24H){ 319 | me->temp_format = FORMAT_AM; 320 | msg = "AM "; 321 | } 322 | else if(me->temp_format == FORMAT_AM){ 323 | me->temp_format = FORMAT_PM; 324 | msg = "PM "; 325 | } 326 | else if (me->temp_format == FORMAT_PM){ 327 | me->temp_format = FORMAT_24H; 328 | msg = "24H"; 329 | } 330 | display_write(msg,CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 331 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 332 | 333 | 334 | 335 | 336 | 337 | 338 | is_time_set_error(me->temp_time,(time_format_t)me->temp_format) 339 | 340 | 341 | 342 | 343 | 344 | else 345 | 346 | me->curr_setting == ALARM_SETTING 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | display_cursor_off_blinkoff(); 365 | display_erase_block(CLOCK_SETTING_ERR_MSG_ROW,0,15); 366 | QActive_armX(AO_ClockAlarm,0,MS_TO_TICKS(500),MS_TO_TICKS(500)); 367 | display_erase_block(CLOCK_SETTING_ERR_MSG_ROW,CLOCK_SETTING_ERR_MSG_COL,CLOCK_SETTING_ERR_MSG_COL_END); 368 | QActive_disarmX(AO_ClockAlarm,0); 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | display_cursor_on_blinkon(); 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | Q_SIG(&me->alarm) = ALARM_CHECK_SIG; 388 | Q_PAR(&me->alarm) = Clock_Alarm_get_curr_time()/10; 389 | Alarm_dispatch(&me->alarm); 390 | 391 | 392 | 393 | 394 | 395 | display_erase_block(CLOCK_SETTING_ERR_MSG_ROW,CLOCK_SETTING_ERR_MSG_COL,CLOCK_SETTING_ERR_MSG_COL_END); 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | display_write("Error!",CLOCK_SETTING_ERR_MSG_ROW,CLOCK_SETTING_ERR_MSG_COL); 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_HOUR_D1_COL); 423 | me->temp_digit = DIGIT1(GET_HOUR(me->temp_time)); 424 | 425 | ++me->temp_digit; 426 | me->temp_digit %= 3; 427 | me->temp_time -= DIGIT1(GET_HOUR(me->temp_time)) * 10UL * 3600UL; 428 | me->temp_time += me->temp_digit * 10UL * 3600UL; 429 | Clock_Alarm_display_clock_setting_time(me,CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_COL); 430 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_HOUR_D1_COL); 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_SEC_D1_COL); 447 | me->temp_digit = DIGIT1(GET_SEC(me->temp_time)); 448 | 449 | ++me->temp_digit; 450 | me->temp_digit %= 6; 451 | me->temp_time -= DIGIT1(GET_SEC(me->temp_time)) * 10UL; 452 | me->temp_time += me->temp_digit * 10UL; 453 | Clock_Alarm_display_clock_setting_time(me,CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_COL); 454 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_SEC_D1_COL); 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | display_erase_block(ALARM_SETTING_STATUS_ROW,0,15); 471 | me->temp_digit = 0U; 472 | display_write("ALARM OFF",ALARM_SETTING_STATUS_ROW,ALARM_SETTING_STATUS_COL); 473 | display_set_cursor(ALARM_SETTING_STATUS_ROW,ALARM_SETTING_STATUS_COL); 474 | 475 | if(me->temp_digit){ 476 | display_write("ALARM OFF",ALARM_SETTING_STATUS_ROW,ALARM_SETTING_STATUS_COL); 477 | me->temp_digit = 0; 478 | }else{ 479 | display_write("ALARM ON ",ALARM_SETTING_STATUS_ROW,ALARM_SETTING_STATUS_COL); 480 | me->temp_digit = 1; 481 | } 482 | display_set_cursor(ALARM_SETTING_STATUS_ROW,ALARM_SETTING_STATUS_COL); 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | me->timeout = 20; 500 | QActive_armX(AO_ClockAlarm,0,MS_TO_TICKS(500),MS_TO_TICKS(500)); 501 | display_clear(); 502 | QActive_disarmX(AO_ClockAlarm,0); 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | Clock_Alarm_display_curr_time(me,ALARM_SETTING_CURR_TIME_ROW,ALARM_SETTING_CURR_TIME_COL); 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | display_write("*ALARM*",ALARM_NOTIFY_MSG_ROW,ALARM_NOTIFY_MSG_COL); 527 | 528 | --me->timeout; 529 | 530 | me->timeout 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | display_erase_block(ALARM_NOTIFY_MSG_ROW,ALARM_NOTIFY_MSG_COL,10); 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | uint8_t b1,b2,btn_pad_value; 573 | 574 | //1. read the button pad status 575 | b1 = digitalRead(PIN_BUTTON1); 576 | b2 = digitalRead(PIN_BUTTON2); 577 | 578 | btn_pad_value = (b1<<1u)|b2; 579 | if(btn_pad_value){ 580 | if(btn_pad_value == BTN_PAD_VALUE_SET){ 581 | QACTIVE_POST(AO_ClockAlarm,SET_SIG,0U); 582 | }else if(btn_pad_value == BTN_PAD_VALUE_OK){ 583 | QACTIVE_POST(AO_ClockAlarm,OK_SIG,0U); 584 | }else if(btn_pad_value == BTN_PAD_VALUE_ABRT){ 585 | QACTIVE_POST(AO_ClockAlarm,ABRT_SIG,0U); 586 | } 587 | } 588 | QF_INT_DISABLE(); 589 | flag_report_button_press = true; 590 | QF_INT_ENABLE(); 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | QHSM_INIT(&me->super); 605 | 606 | 607 | QHSM_DISPATCH(&me->super); 608 | 609 | 610 | 611 | me->alarm_time = alarm_time; 612 | 613 | 614 | 615 | me->alarm_status = status; 616 | 617 | 618 | return me->alarm_time; 619 | 620 | 621 | 622 | me->alarm_time = INITIAL_ALARM_TIME; 623 | me->alarm_status = ALARM_OFF; 624 | 625 | 626 | 627 | 628 | 629 | 630 | if(Q_PAR(me) == me->alarm_time) 631 | QACTIVE_POST(AO_ClockAlarm,ALARM_SIG,0U); 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | = &Clock_Alarm_obj.super; 643 | 644 | 645 | = &Button_obj.super; 646 | 647 | 648 | Alarm_ctor(&Clock_Alarm_obj.alarm); 649 | QActive_ctor(AO_ClockAlarm,Q_STATE_CAST(&Clock_Alarm_initial)); 650 | 651 | 652 | QActive_ctor(AO_Button,Q_STATE_CAST(&Button_initial)); 653 | 654 | 655 | 656 | QHsm_ctor(&me->super,Q_STATE_CAST(&Alarm_initial)); 657 | 658 | 659 | 660 | #include <Arduino.h> 661 | #include "qpn.h" 662 | #include "lcd.h" 663 | #include "alarm.h" 664 | #include "ClockAlarm_SM.h" 665 | #include "main.h" 666 | 667 | 668 | //prototypes of helper functions 669 | String get_am_or_pm(uint32_t time24h); 670 | void display_write(String str_, uint8_t r, uint8_t c); 671 | String integertime_to_string(uint32_t time_); 672 | uint32_t convert_12hformat_to_24h(uint32_t time12h, time_format_t ampm); 673 | uint32_t convert_24hformat_to_12h(uint32_t time24h); 674 | void display_cursor_on_blinkon(void); 675 | void display_cursor_off_blinkoff(); 676 | void display_set_cursor(uint8_t r, uint8_t c); 677 | void display_clear(void); 678 | bool is_time_set_error(uint32_t time_, time_format_t format); 679 | void display_erase_block(uint8_t row,uint8_t col_start,uint8_t col_stop); 680 | 681 | $declare${AOs::Clock_Alarm} 682 | $define${AOs::AO_ClockAlarm} 683 | $define${AOs::Clock_Alarm_ctor} 684 | 685 | $define${AOs::Clock_Alarm} 686 | 687 | ISR(TIMER1_COMPA_vect){ 688 | static uint8_t count = 0; 689 | QF_tickXISR(0); 690 | if(++count == 100U) { 691 | count = 0; 692 | Clock_Alarm_update_curr_time(); 693 | QACTIVE_POST_ISR(AO_ClockAlarm,TICK_SIG,0U); 694 | } 695 | 696 | } 697 | /* 698 | * Description : Decodes AM/PM information from given time in 24H format 699 | * param1: Integer time in 24H format 700 | * return : A string value("AM" or "PM") 701 | */ 702 | String get_am_or_pm(uint32_t time24h){ 703 | String ampm; 704 | uint8_t h = GET_HOUR(time24h); 705 | if(h == 0U){ 706 | ampm = "AM"; 707 | }else if( h > 12U){ 708 | ampm = "PM"; 709 | }else if (h == 12U) 710 | ampm = "PM"; 711 | else 712 | ampm = "AM"; 713 | return ampm; 714 | } 715 | 716 | /* 717 | * Description: Writes a message to the LCD at given row and column number 718 | * param1 : Message to write in 'String' format 719 | * param2 : row number of the LCD 720 | * param2 : column number of the LCD 721 | */ 722 | void display_write(String str_, uint8_t r, uint8_t c){ 723 | lcd_set_cursor(c,r); 724 | lcd_print_string(str_); 725 | } 726 | 727 | /* 728 | * Description: converts an 'integer' time to 'String' time 729 | * param1 : time represented in terms of number of seconds 730 | * return : time as 'String' value in the format HH:MM:SS 731 | */ 732 | String integertime_to_string(uint32_t time_){ 733 | uint8_t h,m,s; 734 | char buf[10]; //00:00:00+null 735 | h = GET_HOUR(time_); /* Extract how many hours the 'time_' represent */ 736 | m = GET_MIN(time_); /* Extract how many minutes the 'time_' represent */ 737 | s = GET_SEC(time_); /* Extract how many seconds the 'time_' represent */ 738 | sprintf(buf,"%02d:%02d:%02d",h,m,s); 739 | return (String)buf; 740 | } 741 | 742 | /* 743 | * Description: Converts given integer time in 12H format to integer time 24H format 744 | * param1 : Integer time in 12H format 745 | * param2 : time format of type time_format_t 746 | * return : Integer time in 24H format 747 | */ 748 | uint32_t convert_12hformat_to_24h(uint32_t time12h, time_format_t ampm){ 749 | uint8_t hour; 750 | uint32_t time24h; 751 | hour = GET_HOUR(time12h); 752 | if(ampm == FORMAT_AM){ 753 | time24h = (hour == 12)? (time12h-(12UL * 3600UL)) : time12h; 754 | }else{ 755 | time24h = (hour == 12)? time12h : (time12h +(12UL * 3600UL)); 756 | } 757 | return time24h; 758 | } 759 | 760 | /* 761 | * Description: Converts given integer time in 24H format to integer time 12H format 762 | * param1 : Integer time in 24H format 763 | * return : Integer time in 12H format 764 | */ 765 | uint32_t convert_24hformat_to_12h(uint32_t time24h){ 766 | uint8_t hour; 767 | uint32_t time12h; 768 | hour = GET_HOUR(time24h); 769 | 770 | if(hour == 0) 771 | time12h = time24h + (12UL * 3600UL); 772 | else{ 773 | if((hour < 12UL) || (hour == 12UL)) 774 | return time24h; 775 | else 776 | time12h = time24h - (12UL * 3600UL); 777 | } 778 | return time12h; 779 | } 780 | 781 | void display_cursor_on_blinkon(void){ 782 | lcd_cursor_show(); 783 | lcd_cursor_blink(); 784 | } 785 | 786 | void display_set_cursor(uint8_t r, uint8_t c){ 787 | lcd_set_cursor(c,r); 788 | } 789 | 790 | 791 | void display_cursor_off_blinkoff(){ 792 | lcd_cursor_off(); 793 | lcd_cursor_blinkoff(); 794 | } 795 | 796 | void display_clear(void){ 797 | lcd_clear(); 798 | } 799 | 800 | bool is_time_set_error(uint32_t time_,time_format_t format){ 801 | uint8_t h = GET_HOUR(time_); 802 | return ((h > 23) || ((h > 12 || (h == 0))&& format != FORMAT_24H) ); 803 | } 804 | 805 | 806 | void display_erase_block(uint8_t row,uint8_t col_start,uint8_t col_stop) 807 | { 808 | uint8_t len = col_stop - col_start; 809 | do{ 810 | lcd_set_cursor(col_start++,row); 811 | lcd_print_char(' '); 812 | }while(len--); 813 | } 814 | 815 | 816 | 817 | 818 | #ifndef CLOCK_ALARM_H 819 | #define CLOCK_ALARM_H 820 | 821 | //#include "qpn.h" 822 | 823 | $declare${AOs::AO_ClockAlarm} 824 | $declare${AOs::Clock_Alarm_ctor} 825 | 826 | enum ClockAlarm_Signals{ 827 | SET_SIG = Q_USER_SIG, 828 | OK_SIG, 829 | ABRT_SIG, 830 | ALARM_SIG, 831 | TICK_SIG, 832 | ALARM_CHECK_SIG, 833 | BUTTON_SCAN_SIG, 834 | IGNORE_SIG, 835 | MAX_SIG 836 | }; 837 | 838 | enum time_mode{ 839 | MODE_24H, 840 | MODE_12H 841 | }; 842 | 843 | enum alarm_status{ 844 | ALARM_OFF, 845 | ALARM_ON 846 | }; 847 | 848 | enum setting{ 849 | NO_SETTING, 850 | CLOCK_SETTING, 851 | ALARM_SETTING 852 | }; 853 | 854 | typedef enum time_format{ 855 | FORMAT_24H, 856 | FORMAT_AM, 857 | FORMAT_PM 858 | }time_format_t; 859 | 860 | typedef enum{ 861 | NOT_PRESSED, 862 | BOUNCE, 863 | PRESSED 864 | }button_state_t; 865 | 866 | 867 | 868 | #define GET_HOUR(seconds) (seconds/3600UL) 869 | #define GET_MIN(seconds) ((seconds/60UL)%60UL) 870 | #define GET_SEC(seconds) (seconds % 60UL) 871 | #define DIGIT1(d) (d/10U) 872 | #define DIGIT2(d) (d%10U) 873 | 874 | #define MAX_TIME (864000UL) 875 | #define INITIAL_CURR_TIME ((10UL * 3600UL + 10UL * 60UL + 10UL) * 10UL) 876 | #define INITIAL_ALARM_TIME (8UL * 3600UL) 877 | 878 | #define TICKING_CURR_TIME_ROW 0 879 | #define TICKING_CURR_TIME_COL 3 880 | #define CLOCK_SETTING_TIME_ROW 0 881 | #define CLOCK_SETTING_TIME_COL 2 882 | #define CLOCK_SETTING_TIME_HOUR_D1_COL 2 883 | #define CLOCK_SETTING_TIME_HOUR_D2_COL 3 884 | #define CLOCK_SETTING_TIME_MIN_D1_COL 5 885 | #define CLOCK_SETTING_TIME_MIN_D2_COL 6 886 | #define CLOCK_SETTING_TIME_SEC_D1_COL 8 887 | #define CLOCK_SETTING_TIME_SEC_D2_COL 9 888 | #define CLOCK_SETTING_TIME_FMT_COL 11 889 | #define CLOCK_SETTING_ERR_MSG_ROW 1 890 | #define CLOCK_SETTING_ERR_MSG_COL 4 891 | #define CLOCK_SETTING_ERR_MSG_COL_END 9 892 | 893 | #define ALARM_SETTING_CURR_TIME_ROW 1 894 | #define ALARM_SETTING_CURR_TIME_COL 2 895 | #define ALARM_SETTING_STATUS_ROW 0 896 | #define ALARM_SETTING_STATUS_COL 4 897 | #define ALARM_NOTIFY_MSG_ROW 0 898 | #define ALARM_NOTIFY_MSG_COL 4 899 | 900 | #define CS_ROW 0 901 | #define CS_HOUR_D1_COL 2 902 | 903 | #endif 904 | 905 | 906 | #include <Arduino.h> 907 | #include "qpn.h" 908 | #include "alarm.h" 909 | #include "ClockAlarm_SM.h" 910 | 911 | Q_DEFINE_THIS_FILE; 912 | 913 | $define${AOs::Alarm} 914 | $define${AOs::Alarm_ctor} 915 | 916 | 917 | #ifndef ALARM_H 918 | #define ALARM_H 919 | 920 | $declare${AOs::Alarm} 921 | $declare${AOs::Alarm_ctor} 922 | 923 | #endif 924 | 925 | 926 | #include <Arduino.h> 927 | #include "qpn.h" 928 | #include "button_SM.h" 929 | #include "ClockAlarm_SM.h" 930 | #include "main.h" 931 | 932 | $define${AOs::AO_Button} 933 | $define${AOs::Button} 934 | $define${AOs::Button_ctor} 935 | 936 | 937 | #ifndef BUTTON_H 938 | #define BUTTON_H 939 | 940 | $declare${AOs::AO_Button} 941 | $declare${AOs::Button} 942 | $declare${AOs::Button_ctor} 943 | #endif 944 | 945 | 946 | 947 | 948 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/src/ClockAlarm_SM.h: -------------------------------------------------------------------------------- 1 | /*.$file${AOs::../src::ClockAlarm_SM.h} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 2 | /* 3 | * Model: ClockAlarm.qm 4 | * File: ${AOs::../src::ClockAlarm_SM.h} 5 | * 6 | * This code has been generated by QM 5.1.1 . 7 | * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | * 9 | * This program is open source software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as published 11 | * by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * for more details. 17 | */ 18 | /*.$endhead${AOs::../src::ClockAlarm_SM.h} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 19 | #ifndef CLOCK_ALARM_H 20 | #define CLOCK_ALARM_H 21 | 22 | //#include "qpn.h" 23 | 24 | /*.$declare${AOs::AO_ClockAlarm} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 25 | extern QActive *const AO_ClockAlarm; 26 | /*.$enddecl${AOs::AO_ClockAlarm} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 27 | /*.$declare${AOs::Clock_Alarm_ctor} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 28 | /*.${AOs::Clock_Alarm_ctor} ................................................*/ 29 | void Clock_Alarm_ctor(void); 30 | /*.$enddecl${AOs::Clock_Alarm_ctor} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 31 | 32 | enum ClockAlarm_Signals{ 33 | SET_SIG = Q_USER_SIG, 34 | OK_SIG, 35 | ABRT_SIG, 36 | ALARM_SIG, 37 | TICK_SIG, 38 | ALARM_CHECK_SIG, 39 | BUTTON_SCAN_SIG, 40 | IGNORE_SIG, 41 | MAX_SIG 42 | }; 43 | 44 | enum time_mode{ 45 | MODE_24H, 46 | MODE_12H 47 | }; 48 | 49 | enum alarm_status{ 50 | ALARM_OFF, 51 | ALARM_ON 52 | }; 53 | 54 | enum setting{ 55 | NO_SETTING, 56 | CLOCK_SETTING, 57 | ALARM_SETTING 58 | }; 59 | 60 | typedef enum time_format{ 61 | FORMAT_24H, 62 | FORMAT_AM, 63 | FORMAT_PM 64 | }time_format_t; 65 | 66 | typedef enum{ 67 | NOT_PRESSED, 68 | BOUNCE, 69 | PRESSED 70 | }button_state_t; 71 | 72 | 73 | 74 | #define GET_HOUR(seconds) (seconds/3600UL) 75 | #define GET_MIN(seconds) ((seconds/60UL)%60UL) 76 | #define GET_SEC(seconds) (seconds % 60UL) 77 | #define DIGIT1(d) (d/10U) 78 | #define DIGIT2(d) (d%10U) 79 | 80 | #define MAX_TIME (864000UL) 81 | #define INITIAL_CURR_TIME ((10UL * 3600UL + 10UL * 60UL + 10UL) * 10UL) 82 | #define INITIAL_ALARM_TIME (8UL * 3600UL) 83 | 84 | #define TICKING_CURR_TIME_ROW 0 85 | #define TICKING_CURR_TIME_COL 3 86 | #define CLOCK_SETTING_TIME_ROW 0 87 | #define CLOCK_SETTING_TIME_COL 2 88 | #define CLOCK_SETTING_TIME_HOUR_D1_COL 2 89 | #define CLOCK_SETTING_TIME_HOUR_D2_COL 3 90 | #define CLOCK_SETTING_TIME_MIN_D1_COL 5 91 | #define CLOCK_SETTING_TIME_MIN_D2_COL 6 92 | #define CLOCK_SETTING_TIME_SEC_D1_COL 8 93 | #define CLOCK_SETTING_TIME_SEC_D2_COL 9 94 | #define CLOCK_SETTING_TIME_FMT_COL 11 95 | #define CLOCK_SETTING_ERR_MSG_ROW 1 96 | #define CLOCK_SETTING_ERR_MSG_COL 4 97 | #define CLOCK_SETTING_ERR_MSG_COL_END 9 98 | 99 | #define ALARM_SETTING_CURR_TIME_ROW 1 100 | #define ALARM_SETTING_CURR_TIME_COL 2 101 | #define ALARM_SETTING_STATUS_ROW 0 102 | #define ALARM_SETTING_STATUS_COL 4 103 | #define ALARM_NOTIFY_MSG_ROW 0 104 | #define ALARM_NOTIFY_MSG_COL 4 105 | 106 | #define CS_ROW 0 107 | #define CS_HOUR_D1_COL 2 108 | 109 | #endif -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/src/alarm.cpp: -------------------------------------------------------------------------------- 1 | /*.$file${AOs::../src::alarm.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 2 | /* 3 | * Model: ClockAlarm.qm 4 | * File: ${AOs::../src::alarm.cpp} 5 | * 6 | * This code has been generated by QM 5.1.1 . 7 | * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | * 9 | * This program is open source software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as published 11 | * by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * for more details. 17 | */ 18 | /*.$endhead${AOs::../src::alarm.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 19 | #include 20 | #include "qpn.h" 21 | #include "alarm.h" 22 | #include "ClockAlarm_SM.h" 23 | 24 | Q_DEFINE_THIS_FILE; 25 | 26 | /*.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 27 | /*. Check for the minimum required QP version */ 28 | #if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U)) 29 | #error qpn version 6.9.0 or higher required 30 | #endif 31 | /*.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 32 | /*.$define${AOs::Alarm} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 33 | /*.${AOs::Alarm} ...........................................................*/ 34 | /*.${AOs::Alarm::init} .....................................................*/ 35 | void Alarm_init(Alarm * const me) { 36 | QHSM_INIT(&me->super); 37 | } 38 | 39 | /*.${AOs::Alarm::dispatch} .................................................*/ 40 | void Alarm_dispatch(Alarm * const me) { 41 | QHSM_DISPATCH(&me->super); 42 | } 43 | 44 | /*.${AOs::Alarm::set_alarm_time} ...........................................*/ 45 | void Alarm_set_alarm_time(Alarm * const me, uint32_t alarm_time) { 46 | me->alarm_time = alarm_time; 47 | } 48 | 49 | /*.${AOs::Alarm::set_status} ...............................................*/ 50 | void Alarm_set_status(Alarm * const me, uint8_t status) { 51 | me->alarm_status = status; 52 | } 53 | 54 | /*.${AOs::Alarm::get_alarm_time} ...........................................*/ 55 | uint32_t Alarm_get_alarm_time(Alarm * const me) { 56 | return me->alarm_time; 57 | } 58 | 59 | /*.${AOs::Alarm::SM} .......................................................*/ 60 | QState Alarm_initial(Alarm * const me) { 61 | /*.${AOs::Alarm::SM::initial} */ 62 | me->alarm_time = INITIAL_ALARM_TIME; 63 | me->alarm_status = ALARM_OFF; 64 | return Q_TRAN(&Alarm_ALARM); 65 | } 66 | /*.${AOs::Alarm::SM::ALARM} ................................................*/ 67 | QState Alarm_ALARM(Alarm * const me) { 68 | QState status_; 69 | switch (Q_SIG(me)) { 70 | /*.${AOs::Alarm::SM::ALARM::ALARM_CHECK} */ 71 | case ALARM_CHECK_SIG: { 72 | if(Q_PAR(me) == me->alarm_time) 73 | QACTIVE_POST(AO_ClockAlarm,ALARM_SIG,0U); 74 | status_ = Q_HANDLED(); 75 | break; 76 | } 77 | default: { 78 | status_ = Q_SUPER(&QHsm_top); 79 | break; 80 | } 81 | } 82 | return status_; 83 | } 84 | /*.$enddef${AOs::Alarm} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 85 | /*.$define${AOs::Alarm_ctor} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 86 | /*.${AOs::Alarm_ctor} ......................................................*/ 87 | void Alarm_ctor(Alarm *const me) { 88 | QHsm_ctor(&me->super,Q_STATE_CAST(&Alarm_initial)); 89 | } 90 | /*.$enddef${AOs::Alarm_ctor} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 91 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/src/alarm.h: -------------------------------------------------------------------------------- 1 | /*.$file${AOs::../src::alarm.h} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 2 | /* 3 | * Model: ClockAlarm.qm 4 | * File: ${AOs::../src::alarm.h} 5 | * 6 | * This code has been generated by QM 5.1.1 . 7 | * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | * 9 | * This program is open source software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as published 11 | * by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * for more details. 17 | */ 18 | /*.$endhead${AOs::../src::alarm.h} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 19 | #ifndef ALARM_H 20 | #define ALARM_H 21 | 22 | /*.$declare${AOs::Alarm} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 23 | /*.${AOs::Alarm} ...........................................................*/ 24 | typedef struct Alarm { 25 | /* protected: */ 26 | QHsm super; 27 | 28 | /* private: */ 29 | uint32_t alarm_time; 30 | uint8_t alarm_status; 31 | } Alarm; 32 | 33 | /* public: */ 34 | void Alarm_init(Alarm * const me); 35 | void Alarm_dispatch(Alarm * const me); 36 | void Alarm_set_alarm_time(Alarm * const me, uint32_t alarm_time); 37 | void Alarm_set_status(Alarm * const me, uint8_t status); 38 | uint32_t Alarm_get_alarm_time(Alarm * const me); 39 | 40 | /* protected: */ 41 | QState Alarm_initial(Alarm * const me); 42 | QState Alarm_ALARM(Alarm * const me); 43 | /*.$enddecl${AOs::Alarm} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 44 | /*.$declare${AOs::Alarm_ctor} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 45 | /*.${AOs::Alarm_ctor} ......................................................*/ 46 | void Alarm_ctor(Alarm *const me); 47 | /*.$enddecl${AOs::Alarm_ctor} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 48 | 49 | #endif -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/src/button_SM.cpp: -------------------------------------------------------------------------------- 1 | /*.$file${AOs::../src::button_SM.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 2 | /* 3 | * Model: ClockAlarm.qm 4 | * File: ${AOs::../src::button_SM.cpp} 5 | * 6 | * This code has been generated by QM 5.1.1 . 7 | * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | * 9 | * This program is open source software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as published 11 | * by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * for more details. 17 | */ 18 | /*.$endhead${AOs::../src::button_SM.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 19 | #include 20 | #include "qpn.h" 21 | #include "button_SM.h" 22 | #include "ClockAlarm_SM.h" 23 | #include "main.h" 24 | 25 | /*.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 26 | /*. Check for the minimum required QP version */ 27 | #if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U)) 28 | #error qpn version 6.9.0 or higher required 29 | #endif 30 | /*.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 31 | /*.$define${AOs::AO_Button} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 32 | /*.${AOs::AO_Button} .......................................................*/ 33 | QActive *const AO_Button = &Button_obj.super; 34 | /*.$enddef${AOs::AO_Button} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 35 | /*.$define${AOs::Button} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 36 | /*.${AOs::Button} ..........................................................*/ 37 | Button Button_obj; 38 | /*.${AOs::Button::SM} ......................................................*/ 39 | QState Button_initial(Button * const me) { 40 | /*.${AOs::Button::SM::initial} */ 41 | return Q_TRAN(&Button_Button); 42 | } 43 | /*.${AOs::Button::SM::Button} ..............................................*/ 44 | QState Button_Button(Button * const me) { 45 | QState status_; 46 | switch (Q_SIG(me)) { 47 | /*.${AOs::Button::SM::Button::Q_TIMEOUT} */ 48 | case Q_TIMEOUT_SIG: { 49 | uint8_t b1,b2,btn_pad_value; 50 | 51 | //1. read the button pad status 52 | b1 = digitalRead(PIN_BUTTON1); 53 | b2 = digitalRead(PIN_BUTTON2); 54 | 55 | btn_pad_value = (b1<<1u)|b2; 56 | if(btn_pad_value){ 57 | if(btn_pad_value == BTN_PAD_VALUE_SET){ 58 | QACTIVE_POST(AO_ClockAlarm,SET_SIG,0U); 59 | }else if(btn_pad_value == BTN_PAD_VALUE_OK){ 60 | QACTIVE_POST(AO_ClockAlarm,OK_SIG,0U); 61 | }else if(btn_pad_value == BTN_PAD_VALUE_ABRT){ 62 | QACTIVE_POST(AO_ClockAlarm,ABRT_SIG,0U); 63 | } 64 | } 65 | QF_INT_DISABLE(); 66 | flag_report_button_press = true; 67 | QF_INT_ENABLE(); 68 | status_ = Q_HANDLED(); 69 | break; 70 | } 71 | default: { 72 | status_ = Q_SUPER(&QHsm_top); 73 | break; 74 | } 75 | } 76 | return status_; 77 | } 78 | /*.$enddef${AOs::Button} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 79 | /*.$define${AOs::Button_ctor} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 80 | /*.${AOs::Button_ctor} .....................................................*/ 81 | void Button_ctor(void) { 82 | QActive_ctor(AO_Button,Q_STATE_CAST(&Button_initial)); 83 | } 84 | /*.$enddef${AOs::Button_ctor} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 85 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/src/button_SM.h: -------------------------------------------------------------------------------- 1 | /*.$file${AOs::../src::button_SM.h} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 2 | /* 3 | * Model: ClockAlarm.qm 4 | * File: ${AOs::../src::button_SM.h} 5 | * 6 | * This code has been generated by QM 5.1.1 . 7 | * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost. 8 | * 9 | * This program is open source software: you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License as published 11 | * by the Free Software Foundation. 12 | * 13 | * This program is distributed in the hope that it will be useful, but 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 | * for more details. 17 | */ 18 | /*.$endhead${AOs::../src::button_SM.h} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 19 | #ifndef BUTTON_H 20 | #define BUTTON_H 21 | 22 | /*.$declare${AOs::AO_Button} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 23 | extern QActive *const AO_Button; 24 | /*.$enddecl${AOs::AO_Button} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 25 | /*.$declare${AOs::Button} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 26 | /*.${AOs::Button} ..........................................................*/ 27 | typedef struct Button { 28 | /* protected: */ 29 | QActive super; 30 | 31 | /* private: */ 32 | } Button; 33 | extern Button Button_obj; 34 | 35 | /* protected: */ 36 | QState Button_initial(Button * const me); 37 | QState Button_Button(Button * const me); 38 | /*.$enddecl${AOs::Button} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 39 | /*.$declare${AOs::Button_ctor} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/ 40 | /*.${AOs::Button_ctor} .....................................................*/ 41 | void Button_ctor(void); 42 | /*.$enddecl${AOs::Button_ctor} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/ 43 | #endif -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/src/lcd.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "lcd.h" 4 | 5 | #include 6 | 7 | LiquidCrystal lcd(PIN_LCD_RS,PIN_LCD_RW,PIN_LCD_EN,PIN_LCD_D4,PIN_LCD_D5,PIN_LCD_D6,PIN_LCD_D7); 8 | 9 | void lcd_clear(void){ 10 | lcd.clear(); 11 | } 12 | void lcd_print_char(char c){ 13 | lcd.print(c); 14 | } 15 | 16 | void lcd_scroll_left(void){ 17 | lcd.scrollDisplayLeft(); 18 | } 19 | void lcd_scroll_right(void){ 20 | lcd.scrollDisplayRight(); 21 | } 22 | void lcd_set_cursor(int c, int r){ 23 | lcd.setCursor(c,r); 24 | } 25 | void lcd_no_auto_scroll(void){ 26 | lcd.noAutoscroll(); 27 | } 28 | void lcd_begin(uint8_t cols , uint8_t rows){ 29 | lcd.begin(cols,rows); 30 | } 31 | void lcd_move_cursor_R_to_L(void){ 32 | lcd.rightToLeft(); 33 | } 34 | void lcd_move_cursor_L_to_R(void){ 35 | lcd.leftToRight(); 36 | } 37 | void lcd_cursor_off(void){ 38 | lcd.noCursor(); 39 | } 40 | void lcd_cursor_blinkoff(void){ 41 | lcd.noBlink(); 42 | } 43 | void lcd_print_number(int num){ 44 | lcd.print(num); 45 | } 46 | void lcd_print_string(String s){ 47 | lcd.print(s); 48 | } 49 | 50 | void lcd_cursor_show(void) 51 | { 52 | lcd.cursor(); 53 | } 54 | 55 | void lcd_cursor_blink(void) 56 | { 57 | lcd.blink(); 58 | } 59 | 60 | void lcd_create_custom_char(byte num, byte* data) { 61 | lcd.createChar(num, data); 62 | } 63 | 64 | void lcd_display_custom_char(byte num){ 65 | lcd.write(num); 66 | } -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/src/lcd.h: -------------------------------------------------------------------------------- 1 | #ifndef LCD_H 2 | #define LCD_H 3 | 4 | #include 5 | 6 | void lcd_clear(void); 7 | void lcd_print_char(char c); 8 | void lcd_scroll_left(void); 9 | void lcd_scroll_right(void); 10 | void lcd_set_cursor(int c, int r); 11 | void lcd_no_auto_scroll(void); 12 | void lcd_begin(uint8_t cols, uint8_t rows); 13 | void lcd_move_cursor_R_to_L(void); 14 | void lcd_move_cursor_L_to_R(void); 15 | void lcd_cursor_off(void); 16 | void lcd_cursor_blinkoff(void); 17 | void lcd_print_number(int num); 18 | void lcd_print_string(String s); 19 | void lcd_cursor_blink(void); 20 | void lcd_cursor_show(void); 21 | void lcd_create_custom_char(byte num, byte *data); 22 | void lcd_display_custom_char(byte num); 23 | 24 | //lcd connections 25 | #define PIN_LCD_RS 5 26 | #define PIN_LCD_RW 6 27 | #define PIN_LCD_EN 7 28 | #define PIN_LCD_D4 8 29 | #define PIN_LCD_D5 9 30 | #define PIN_LCD_D6 10 31 | #define PIN_LCD_D7 11 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "qpn.h" 3 | #include "ClockAlarm_SM.h" 4 | #include "button_SM.h" 5 | #include "lcd.h" 6 | #include "main.h" 7 | 8 | Q_DEFINE_THIS_FILE; 9 | 10 | bool flag_report_button_press = true; 11 | 12 | static void sys_tick_init(void); 13 | static void display_init(void); 14 | static void attach_button_interrupts(void); 15 | 16 | static QEvt ClockAlarmQueue[8]; 17 | static QEvt ButtonQueue[8]; 18 | 19 | QActiveCB const QF_active[] = { 20 | { (QActive*) 0, (QEvt*) 0, 0}, 21 | { (QActive*) AO_ClockAlarm,(QEvt*)ClockAlarmQueue,Q_DIM(ClockAlarmQueue)}, 22 | { (QActive*) AO_Button,(QEvt*)ButtonQueue,Q_DIM(ButtonQueue)} 23 | }; 24 | 25 | void setup() { 26 | // put your setup code here, to run once: 27 | Serial.begin(9600); 28 | display_init(); 29 | attach_button_interrupts(); 30 | Clock_Alarm_ctor(); 31 | Button_ctor(); 32 | QF_init(Q_DIM(QF_active)); 33 | 34 | } 35 | 36 | void loop() { 37 | QF_run(); 38 | } 39 | 40 | void SET_handler(){ 41 | 42 | QF_INT_DISABLE(); 43 | if(flag_report_button_press){ 44 | flag_report_button_press = false; 45 | QActive_armX(AO_Button,0,MS_TO_TICKS(50),0U); 46 | } 47 | QF_INT_ENABLE(); 48 | 49 | } 50 | 51 | void OK_handler(){ 52 | QF_INT_DISABLE(); 53 | if(flag_report_button_press){ 54 | flag_report_button_press = false; 55 | QActive_armX(AO_Button,0,MS_TO_TICKS(50),0U); 56 | } 57 | QF_INT_ENABLE(); 58 | } 59 | 60 | 61 | static void attach_button_interrupts(void) 62 | { 63 | attachInterrupt(digitalPinToInterrupt(PIN_BUTTON1), SET_handler, RISING); 64 | attachInterrupt(digitalPinToInterrupt(PIN_BUTTON2), OK_handler, RISING); 65 | } 66 | 67 | static void sys_tick_init(void){ 68 | TCCR1A = TCCR1A_CTC_MODE; //CTC mode 69 | TCCR1B = (TCCR1B_CTC_MODE |TCCR1B_PRESCALER_1); //prescaler=1,CTC mode 70 | TIMSK1 |= B00000010; //Interrupt enable for OCR1A compare match 71 | OCR1A = TIMER1_OC_MATCH_VALUE; //OC match value for CONFIG_TICKS_PER_SECOND time base generation 72 | } 73 | 74 | 75 | 76 | static void display_init(void) 77 | { 78 | lcd_begin(16,2); 79 | lcd_clear(); 80 | lcd_move_cursor_L_to_R(); 81 | lcd_set_cursor(0,0); 82 | lcd_no_auto_scroll(); 83 | lcd_cursor_off(); 84 | } 85 | 86 | void QF_onStartup(void) 87 | { 88 | sys_tick_init(); 89 | } 90 | 91 | void QV_onIdle(void){ 92 | QV_CPU_SLEEP(); 93 | } 94 | 95 | Q_NORETURN Q_onAssert ( char_t const Q_ROM *const module,int_t const location ){ 96 | 97 | Serial.println("Assertion failure!!"); 98 | Serial.println((String)module); 99 | Serial.println(location); 100 | while(1); 101 | } 102 | 103 | 104 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/src/main.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_H 2 | #define MAIN_H 3 | 4 | #define PIN_BUTTON1 2 //SET 5 | #define PIN_BUTTON2 3 //OK 6 | 7 | #define BTN_PAD_VALUE_SET 2 8 | #define BTN_PAD_VALUE_OK 1 9 | #define BTN_PAD_VALUE_ABRT 3 10 | 11 | 12 | #define MCU_SYS_CLOCK_FREQ 16000000UL 13 | 14 | #define TCCR1A_CTC_MODE (0U) 15 | #define TCCR1B_CTC_MODE (1U << 3U) 16 | #define TCCR1B_PRESCALER_1 0x1UL 17 | #define TCCR1B_PRESCALER_8 0x2UL 18 | #define TCCR1B_PRESCALER_64 0x3UL 19 | #define TCCR1B_PRESCALER_256 0x4UL 20 | 21 | 22 | #define TIMER1_PRESCALER_1 1UL 23 | #define TIMER1_PRESCALER_8 8UL 24 | #define TIMER1_PRESCALER_64 64UL 25 | #define TIMER1_PRESCALER_256 256UL 26 | #define TIMER1_PRESCALER_1024 1024UL 27 | 28 | #define CONFIG_TCCR1B_PRESCALER TCCR1B_PRESCALER_1 29 | #define CONFIG_TIMER1_PRESCALER TIMER1_PRESCALER_1 30 | #define CONFIG_TICKS_PER_SECOND 1000UL 31 | 32 | #define MS_PER_TICK (1000UL/CONFIG_TICKS_PER_SECOND) 33 | #define TIMER1_OC_MATCH_VALUE (((MCU_SYS_CLOCK_FREQ * MS_PER_TICK) / (CONFIG_TIMER1_PRESCALER * 1000UL))-1) 34 | 35 | //#define MS_TO_TICKS( timeInMs ) ( ( timeInMs) * (CONFIG_TICKS_PER_SECOND / 1000UL) ) 36 | #define MS_TO_TICKS( timeInMs ) ( ( timeInMs) / (MS_PER_TICK) ) 37 | 38 | 39 | extern bool flag_report_button_press; 40 | #endif 41 | -------------------------------------------------------------------------------- /Course_Exercises/008ClockAlarm_AO/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /Course_Exercises/ClockAlarm_SM_TODO.cpp: -------------------------------------------------------------------------------- 1 | #define GET_HOUR(seconds) (seconds/3600UL) 2 | #define GET_MIN(seconds) ((seconds/60UL)%60UL) 3 | #define GET_SEC(seconds) (seconds % 60UL) 4 | #define DIGIT1(d) (d/10U) 5 | #define DIGIT2(d) (d%10U) 6 | 7 | /* 8 | * Description : Displays current time depending upon the time mode 9 | * param1: 'me' pointer 10 | * param2 : row number of the LCD 11 | * param3: column number of the LCD 12 | */ 13 | void display_curr_time(Clock_Alarm *me,uint8_t row, uint8_t col){ 14 | String time_as_string; 15 | uint32_t time_; 16 | 17 | uint32_t time24h = Clock_Alarm_get_curr_time()/10; //convert to number of seconds 18 | uint8_t ss = time24h % 10U; //extract sub-second to append later 19 | 20 | time_ = (me->time_mode == MODE_24H)?time24h:convert_24hformat_to_12h(time24h); 21 | time_as_string = integertime_to_string(time_); //hh:mm:ss 22 | time_as_string.concat('.'); 23 | time_as_string.concat(ss); 24 | 25 | /*if mode is 12H , concatenate am/pm information */ 26 | if(me->time_mode == MODE_12H){ 27 | time_as_string.concat(' '); 28 | time_as_string.concat(get_am_or_pm(time24h)); 29 | } 30 | 31 | display_write(time_as_string,row,col); 32 | } 33 | 34 | 35 | /* 36 | * Description : Decodes AM/PM information from given time in 24H format 37 | * param1: Integer time in 24H format 38 | * return : A string value("AM" or "PM") 39 | */ 40 | String get_am_or_pm(uint32_t time24h){ 41 | String ampm; 42 | uint8_t h = GET_HOUR(time24h); 43 | if(h == 0U){ 44 | ampm = "AM"; 45 | }else if( h > 12U){ 46 | ampm = "PM"; 47 | }else if (h == 12U) 48 | ampm = "PM"; 49 | else 50 | ampm = "AM"; 51 | return ampm; 52 | } 53 | 54 | /* 55 | * Description: Writes a message to the LCD at given row and column number 56 | * param1 : Message to write in 'String' format 57 | * param2 : row number of the LCD 58 | * param2 : column number of the LCD 59 | */ 60 | void display_write(String str_, uint8_t r, uint8_t c){ 61 | lcd_set_cursor(c,r); 62 | lcd_print_string(str_); 63 | } 64 | 65 | /* 66 | * Description: converts an 'integer' time to 'String' time 67 | * param1 : time represented in terms of number of seconds 68 | * return : time as 'String' value in the format HH:MM:SS 69 | */ 70 | String integertime_to_string(uint32_t time_){ 71 | uint8_t h,m,s; 72 | char buf[10]; //00:00:00+null 73 | h = GET_HOUR(time_); /* Extract how many hours the 'time_' represent */ 74 | m = GET_MIN(time_); /* Extract how many minutes the 'time_' represent */ 75 | s = GET_SEC(time_); /* Extract how many seconds the 'time_' represent */ 76 | sprintf(buf,"%02d:%02d:%02d",h,m,s); 77 | return (String)buf; 78 | } 79 | 80 | /* 81 | * Description: Converts given integer time in 12H format to integer time 24H format 82 | * param1 : Integer time in 12H format 83 | * param2 : time format of type time_format_t 84 | * return : Integer time in 24H format 85 | */ 86 | uint32_t convert_12hformat_to_24h(uint32_t time12h, time_format_t ampm){ 87 | uint8_t hour; 88 | uint32_t time24h; 89 | hour = GET_HOUR(time12h); 90 | if(ampm == FORMAT_AM){ 91 | time24h = (hour == 12)? (time12h-(12UL * 3600UL)) : time12h; 92 | }else{ 93 | time24h = (hour == 12)? time12h : (time12h +(12UL * 3600UL)); 94 | } 95 | return time24h; 96 | } 97 | 98 | /* 99 | * Description: Converts given integer time in 24H format to integer time 12H format 100 | * param1 : Integer time in 24H format 101 | * return : Integer time in 12H format 102 | */ 103 | uint32_t convert_24hformat_to_12h(uint32_t time24h){ 104 | uint8_t hour; 105 | uint32_t time12h; 106 | hour = GET_HOUR(time24h); 107 | 108 | if(hour == 0) 109 | time12h = time24h + (12UL * 3600UL); 110 | else{ 111 | if((hour < 12UL) || (hour == 12UL)) 112 | return time24h; 113 | else 114 | time12h = time24h - (12UL * 3600UL); 115 | } 116 | return time12h; 117 | } 118 | 119 | 120 | /* 121 | * Description : Displays current time depending upon the time mode 122 | * param1: 'me' pointer 123 | * param2 : row number of the LCD 124 | * param3: column number of the LCD 125 | */ 126 | void display_clock_setting_time(Clock_Alarm *me,uint8_t row, uint8_t col){ 127 | String time_as_string; 128 | 129 | time_as_string = integertime_to_string(me->temp_time); //hh:mm:ss 130 | 131 | /*concatenate am/pm information */ 132 | if(me->temp_format != FORMAT_24H){ 133 | time_as_string.concat(' '); 134 | if(me->temp_format == FORMAT_AM) 135 | time_as_string.concat("AM"); 136 | else 137 | time_as_string.concat("PM"); 138 | } 139 | 140 | display_write(time_as_string,row,col); 141 | } 142 | 143 | 144 | 145 | /*.${HSMs::Clock_Alarm::SM::Clock::Ticking::SET} */ 146 | me->temp_time = Clock_Alarm_get_curr_time()/10; 147 | if(me->time_mode == MODE_12H){ 148 | if(get_am_or_pm(me->temp_time).equals("AM")){ 149 | me->temp_format = FORMAT_AM; 150 | } 151 | else{ 152 | me->temp_format = FORMAT_PM; 153 | } 154 | me->temp_time = convert_24hformat_to_12h(me->temp_time); 155 | } 156 | else 157 | me->temp_format = FORMAT_24H; 158 | 159 | 160 | /* ${HSMs::Clock_Alarm::SM::Clock::Settings::Clock_Setting} */ 161 | Clock_Alarm_display_clock_setting_time(me,0,2); 162 | display_cursor_on_blinkon(); 163 | 164 | /* ${HSMs::Clock_Alarm::SM::Clock::Settings::Clock_Setting::cs_hour_d1} */ 165 | display_set_cursor(CS_ROW,CS_HOUR_D1_COL); 166 | me->temp_digit = DIGIT1(GET_HOUR(me->temp_time)); 167 | 168 | /*${HSMs::Clock_Alarm::SM::Clock::Settings::Clock_Setting::cs_hour_d1::SET} */ 169 | ++me->temp_digit; 170 | me->temp_digit %= 3; 171 | me->temp_time -= DIGIT1(GET_HOUR(me->temp_time)) * 10UL * 3600UL; 172 | me->temp_time += (me->temp_digit * 10UL ) * 3600UL; 173 | Clock_Alarm_display_clock_setting_time(me,0,2); 174 | display_set_cursor(CS_ROW,CS_HOUR_D1_COL); 175 | 176 | 177 | void display_cursor_on_blinkon(){ 178 | lcd_cursor_show(); 179 | lcd_cursor_blink(); 180 | } 181 | 182 | void display_cursor_off_blinkoff(){ 183 | lcd_cursor_off(); 184 | lcd_cursor_blinkoff(); 185 | } 186 | 187 | 188 | void display_set_cursor(uint8_t r, uint8_t c){ 189 | lcd_set_cursor(c,r); 190 | } 191 | 192 | bool is_time_set_error(uint32_t time_,time_format_t format){ 193 | uint8_t h = GET_HOUR(time_); 194 | return ((h > 23) || ((h > 12 || (h == 0))&& format != FORMAT_24H) ); 195 | } 196 | 197 | ${HSMs::Clock_Alarm::SM::Clock::Settings::Clock_Setting::cs_format} 198 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 199 | String msg[3] = {"24H","AM ","PM "}; 200 | display_write(msg[me->temp_format],CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 201 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 202 | 203 | ${HSMs::Clock_Alarm::SM::Clock::Settings::Clock_Setting::cs_format::SET} 204 | String msg; 205 | if(me->temp_format == FORMAT_24H){ 206 | me->temp_format = FORMAT_AM; 207 | msg = "AM "; 208 | } 209 | else if(me->temp_format == FORMAT_AM){ 210 | me->temp_format = FORMAT_PM; 211 | msg = "PM "; 212 | } 213 | else if (me->temp_format == FORMAT_PM){ 214 | me->temp_format = FORMAT_24H; 215 | msg = "24H"; 216 | } 217 | display_write(msg,CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 218 | display_set_cursor(CLOCK_SETTING_TIME_ROW,CLOCK_SETTING_TIME_FMT_COL); 219 | 220 | 221 | void display_erase_block(uint8_t row,uint8_t col_start,uint8_t col_stop) 222 | { 223 | uint8_t len = col_stop - col_start; 224 | do{ 225 | lcd_set_cursor(col_start++,row); 226 | lcd_print_char(' '); 227 | }while(len--); 228 | } 229 | 230 | /* ${HSMs::Clock_Alarm::SM::Clock::Settings::OK} */ 231 | uint8_t save_sreg; 232 | 233 | if(me->temp_format != FORMAT_24H){ 234 | me->temp_time = convert_12hformat_to_24h( me->temp_time,(time_format_t)me->temp_format); 235 | me->time_mode = MODE_12H; 236 | }else{ 237 | me->time_mode = MODE_24H; 238 | } 239 | 240 | me->temp_time *= 10UL; 241 | save_sreg = SREG; 242 | cli(); 243 | TCCR1B &= ~(0x7U); //Stop the TIMER1 244 | TCNT1 = 0U; 245 | Clock_Alarm_curr_time = me->temp_time; 246 | TCCR1B |= 0x4U; 247 | SREG = save_sreg; -------------------------------------------------------------------------------- /Course_Exercises/workspace.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "003Protimer" 5 | }, 6 | { 7 | "name": "004Protimer_SH", 8 | "path": "004Protimer_SH" 9 | }, 10 | { 11 | "name": "005Protimer_ST", 12 | "path": "005Protimer_ST" 13 | }, 14 | { 15 | "name": "006QHsmTest", 16 | "path": "006QHsmTest" 17 | }, 18 | { 19 | "name": "007ClockAlarm", 20 | "path": "007ClockAlarm" 21 | }, 22 | { 23 | "name": "008ClockAlarm_AO", 24 | "path": "008ClockAlarm_AO" 25 | } 26 | ], 27 | "settings": {} 28 | } -------------------------------------------------------------------------------- /EmbeddedUMLStateMachines.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niekiran/EmbeddedUMLStateMachines/50021be17ab068f87d13522036ce20316effe1c5/EmbeddedUMLStateMachines.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EmbeddedUMLStateMachines 2 | Repository for the Udemy course "Embedded Systems Design using UML State Machines" 3 | -------------------------------------------------------------------------------- /protimer_v1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niekiran/EmbeddedUMLStateMachines/50021be17ab068f87d13522036ce20316effe1c5/protimer_v1.pdf --------------------------------------------------------------------------------