FSM Lecture 72: Exercise-007 Implementing CLOCK_SETTING state part-1

 

Exercise-007 Implementing CLOCK_SETTING state part-1

 

 

In the previous article, I completed drawing these sub-states inside this Clock_Setting, as shown in Figure 1. I have used a separate state to configure each digit of different fields.

Figure 1. Drawing the sub-states inside the Clock_Setting
Figure 1. Drawing the sub-states inside the Clock_Setting

 

You need not use two separate states to configure two separate digits of the hour field. You can even use one state, but you can use one variable to distinguish between digit1 and digit2. That also you can do. Because when you use more variables, you should also take care of initializing them and deinitializing them. Sometimes it’s better to use one more state rather than using a variable. Sometimes it makes sense to use a variable. 

 

Now let’s talk about some pseudocode. I’ll be just briefing what we’ll be doing to handle the SET signal.

Figure 2. About pseudocode
Figure 2. About pseudocode

 

You are in a Ticking state, and the current time is being displayed to the user, and let’s say the ‘SET’  signal arrives. That is an indication that we should go to Clock_Setting mode.

Let’s define one action for the SET signal, a transition action. Here we will copy the current time to the temporary time variable, and then this enters the Clock_Setting state. The Entry action of the Setting state will be executed, followed by Clock_Setting state, followed by the cs_hour_d1 state. But we don’t have any Entry action in the Setting state. 

The Entry action of Clock_Setting will display the temporary time we captured here (Copy curr_time to temp_time). We will display that and make the Cursor on and Blink on. Because, as you saw in the demo, we should blink the Cursor. That will do in Clock_Setting.

And then, cs_hour_d1 is an initial state of a Clock_Setting super state. The state machine enters the initial state. Here, in this Entry action, we will Set the cursor at the appropriate digit. We will set the cursor. 

When the state machine is in cs_hour_d1 state, whenever the SET signal is received, we have to change the digit d1.  We will increment the digit-1 of temp_time’s hour field. We have to update the display with a new temp_time then; that will do here.

And then, when the state machine is in cs_hour_d1 state and when the ‘OK’ signal is received, there will be a transition to the next state (cs_hour_d2).

Here again, cs_hour_d2 will have one Entry action, and you have to Set the cursor to this digit on display. And whenever the ‘SET’ signal is received, increment the digit-2 of the temp_time’s hour field, the same thing you have to do here. And then ‘OK,’ it moves next state.

And again, you have to Set the cursor here (cs_min_d3). Increment the digit-1 of temp_time’s a minute field. I hope you can do that. This is just my logic, and you are free to implement your own logic. 

 

 /*.${HSMs::Clock_Alarm::SM::Clock::Ticking::SET} */
me->temp_time = Clock_Alarm_get_curr_time()/10;
if(me->time_mode == MODE_12H){
     if(get_am_or_pm(me->temp_time).equals("AM")){
          me->temp_format = FORMAT_AM;
      }
      else{
         me->temp_format = FORMAT_PM;
      }
       me->temp_time = convert_24hformat_to_12h(me->temp_time);
}
else
        me->temp_format = FORMAT_24H;

TODO File code

For example, let’s code for Ticking state’s SET transition action. You can see the code above. 

${HSMs::Clock_Alarm::SM::Clock::Ticking::SET}

me->temp_time = Clock_Alarm_get_curr_time()/10;  Here you can see that, I am copying the current time into the temporary time.

If the mode is 12H, then the temporary time should be updated with a 12 hour format. That I do here. me->temp_time = convert_24hformat_to_12h(me->temp_time);

And then, I use one more variable called temp_format. This variable will be used to capture users format selection later. Just create one class attribute called  temp_format, where I capture what exactly is a time_format, whether it is an AM, PM, or 24H. temp_format is required later when we have to display the time format.

Copy the code, and I’m going to the SET transition,  and in action, paste that code.

Figure 4. SET transition code
Figure 3. SET transition code

 

This code actually needs a temp_format variable. Let’s create that.  

Figure 5.creation of temp_format variable
Figure 4. Creation of temp_format variable

 

Select Clock_Alarm: QHsm, Add attribute. I’ll call this temp_format, type is uin8_t, and I’ll keep it private. Save that.

 

After that, when we reach Clock_Setting state, we should display that captured temporary time. For that, we will be using one function called display_clock_setting_time. It displays the clock setting time.

void display_clock_setting_time(Clock_Alarm * me, uint8_t row, uint8_t col) {
         String time_as_string;

         time_as_string = integertime_to_string(me->temp_time); //hh:mm:ss

         /*concatenate am/pm information */
         if(me->temp_format != FORMAT_24H){
            time_as_string.concat(' ');
            if(me->temp_format == FORMAT_AM)
                time_as_string.concat("AM");
             else
                 time_as_string.concat("PM");
            }

         display_write(time_as_string,row,col);
     }

display_clock_setting_time

display_clock_setting_time converts that temporary time that you had saved in the earlier step; it just converts that into a string. And then, it concatenates the AM or PM information if required; It writes to the display.

 

Let’s create one class operation. Name it as display_clock_setting_time; return type is ‘void’; visibility ‘public’, no problem.

And this has access to the ‘me’ pointers; I will consider display_clock_setting_time a non-static function. And copy all these display_clock_setting_time codes, paste that into the code section. Save, as shown in Figure 5. Display_clock_setting_time  we are going to call from Clock_Setting.

Figure 7. Creating a display_clock_setting_time class operation
Figure 5. Creating a display_clock_setting_time class operation

 

Whenever the Clock_Setting state is entered as a part of the entry action, we are going to display that clock setting time.

 

Figure 8. Defining a macro
Figure 6. Defining a macro

 

You have to supply the ‘me’ pointer and the location where you want to print that. 

I’ll provide the macro. #define CLOCK_SETTING_TIME_ROW, which is 0.  

#define CLOCK_SETTING_TIME_COL, I’ll select 2 here. And I’ll use these macros in entry action, as shown in Figure 6. 

 

Let’s go back to the state machine,  and you should also turn on the cursor and turn on the blink of the LCD.

void display_cursor_on_blinkon() {
    lcd_cursor_show();
    lcd_cursor_blink();
}

display_cursor_on_blinkon()

For that, I have given one helper function you can use that. And its name is display_cursor_on_blinkon() it does nothing actually.  It just calls the lcd.cpp’s functions. lcd_cursor_show and lcd_cursor_blink. So, call this function in the Clock_setting → Entry action.

 

After that, the state machine enters cs_hour_d1, and we will set the cursor at d1’s position. We should call set_cursor. I will use display_set_cursor, which calls lcd_set_cursor.

void display_set_cursor(uint8_t r, uint8_t c) {
     lcd_set_cursor(c,r);
}

display_set_cursor

What’s a position?

Where coordinates do you have to mention?

Row and column number. I’ll just use the macros, as shown in Figure 7.

Implementing CLOCK_SETTING state part-1
Figure 7. Defining a macro

 

Row will be the same. That is 0.

 

Now let’s get back to the state machine. In cs_hour_d1, here we set the cursor. And whenever the user sends the SET signal, we should increment the d1 digit. 

What I’ll do here is I will use another variable to hold the digit. I’ll create one more attribute, name it temp_digit; we will use uint8_t, private.

Implementing CLOCK_SETTING state part-1
Figure 8. Creating Temp_digit variable

 

Here, whenever the state machine enters cs_hour_d1 state, me->temp_digit will hold the first digit of the temporary times hour field. For that, I’ll use the macro that I introduced earlier, which is  DIGIT1 macro. It just returns the unit field and 10th field. DIGIT1 returns the 10th field, and DIGIT2 returns the unit field.

Implementing CLOCK_SETTING state part-1
Figure 9. display_set_cursor

 

Use DIGIT1 of GET_HOUR. I’ll extract the DIGIT1 of  GET_HOUR of temp_time. That’s it. I capture the first digit of the hour field of the temp_time. 

 

After that, whenever the ‘SET’ is received, I’m just going to increment that. me->temp_digit ++. For digit-1, the allowed values are 0, 1, 2. That’s why, I’ll just do me->temp_digit % = 3. Because the digit value can vary between 0, 1, and 2. It can’t be 3. 

You have just changed this temp_digit; you did a ‘++’ whenever you received the SET signal.

Implementing CLOCK_SETTING state part-1
Figure 10. SET transition action code

 

Now, we have to update that information in the temporary time variable. You would first delete the earlier value and feed the new value. 

I’m going to do this. me->temp_time -= DIGIT1 (GET_HOUR(me-> temp_time)) * 10UL * 3600UL; 

And then, I am compensating with temp_digit value. I’m taking the digit value multiplied by 10 because it’s the 10th place. Because temp_digit should go at the 10th place and multiply by a number of seconds in one hour. First, subtract the old seconds, introduce the new second. 

And then, you already have created this function display_clock_setting_time. We display the modified temporary time. And the cursor must stay at D1’s position. Once you do this, the cursor will move to somewhere else. You have to bring back the cursor at D1’s position. The code is shown in Figure 10.

 

Please note that this is not the logic you have to implement; you are free to implement anything you want. I mean, there could be some other approaches. You are free to think of your own logic. 

And whenever ‘OK’ is received here, there is an external transition; we come to cs_hour_d2. Again we have to repeat that. Whatever we have done here, we have repeated here. Copy the code of this cs_hour_d1, go to cs_hour_d2, and paste that here. Instead of DIGIT1, this is DIGIT2, and display_set_cursor D2 column.

Implementing CLOCK_SETTING state part-1
Figure 11. SET transition action code

 

And ‘SET,’ almost the same code you have to copy and paste here. The value of D2 can vary from  0 to 9. That’s why you have to use 10 here. And this is DIGIT2, and DIGIT2 is actually at the unit place. That’s why multiplying by 10 is not required. (Figure 11) Likewise, you have to modify.

 

FastBit Embedded Brain Academy Courses

Click here: https://fastbitlab.com/course1

 

 

FastBitLab

The FastBit Embedded Brain Academy uses the power of internet to bring the online courses related to the field of embedded system programming, Real time operating system, Embedded Linux systems, etc at your finger tip with very low cost. Backed with strong experience of industry, we have produced lots of courses with the customer enrolment over 3000+ across 100+ countries.