Thursday, May 21, 2015

Ruby on Rails Note - 05/20/2015

1. css files are in app/asset/stylesheets/xxx.scss. Rails keeps application.html.erb as a framework page for the entire application. The application.html.erb file is located in views/layouts/ directory. In order to use the xxx.scss, it has to be introduced in the application.html.erb file, in such way as following.
  <body class='xxx.scss'> or <body class='<%= controller.controller_name%>'>
Then, the css classes can be used in index.html.erb.

2. Some rails helper function:
(1) cycle('a', 'b') sets the css class of each row to either 'a' or 'b' and automatically toggles between the two style names on successive lines.
(2) trunctate(string, length:n) is used to display just the first n characters of string.
(3) strip_tags(string) removes the html tags from the string.
(4) link_to('Product', @product) is equal to
     link_to('Product', controller:'products', action:'show', id:product)
     The link_to generates  a hyper link which execute show method in controller which invokes show.html.erb if nothing in the method.

3. Git usage
(1) basic configuration
    $ git config --global --add user.name "Alex"
    $ git config --global --add user.email alex@gmail.com
    $ git config --global --list
These configuration info will be added every check in as the committer info.
(2) add a .gitignore file to specify a file list that you don't want to check in
(3) create a local empty repository in current directory.
    $ git init
(4) add all the files under the current directory to local repository.
    $ git add .
(5) commit the change to local repository
    $ git commit -m "first commit"

If you want to clear the local repository.
(1) rm -rf .git

If you have a github account, you can push your repository to the github
(1) create a repository on github
(2) $ git remote add origin "YOUR HTTPS GITHUB REPOSITORY URL"
(3) $ git push origin master




Tuesday, May 19, 2015

Ruby on Rails Note - 05/19/2015

1. To create a new project.
    $ rails new [project name]

2. Create a scaffold. A scaffold is a full set of model, database migration for that model, controller to manipulate it, view to view and manipulate the data, and a test suite for each of the above.
    $ rails generate scaffold Product \
            title:string description:text image_url:string price:decimal

The default database for Rails development is SQLite3. The config/database.yml file tells Rails where to look for the database.

3. To migrate database.
    $ rake db:migrate

The migration file is xxxxxxxxxxxxxx_create_xxxx.rb. A migration represents a change we want to make to the data, expressed in a source file in database-independent terms. These changes can update both the database schema and the data in the database tables.

4. To start rails server.
    $rails server

5. To import seed data to the database.
    $rails db:seed

The data can be defined in db/seed.rb.

Monday, April 20, 2015

Start Ruby on Rails!

Installing Ruby on Rails on Mac OS X Yosemite

1. Install latest Xcoder (6.3)

2. Install Command Line Tools which is premise for step 6:
    Xcoder -> Open Developer Tool -> More Developer Tools...

3. Install RVM:
    $ curl -L https://get.rvm.io | bash -s stable

4. Install latest ruby (2.2.1):
    $ rvm install 2.2.1 --autolibs=enable

5. Configure the environment to be ruby 2.2.1:
    $ rvm use 2.2.1

6. Install latest rails (4.2.1)
    $ gem install rails --version 4.2.1 (--no-ri --no-rdoc)

7. Make ruby 2.2.1 as the default environment
    $ rvm --default 2.2.1

After installation, there might be something that you would like to do, such as upgrade to newer version.
1. To find out all the versions of Rails that you have installed:
    $ gem list --local rails

Installing PostgreSQL on Mac OS X Yosemite
1. www.postgresql.org/download/macosx/  find a installer on the website and install PostgreSQL.
2. Install the database driver for PostgreSQL. Driver can be downloaded from https://bitbucket.org/ged/ruby-pg/wiki/Home. You have to specify the pg_config location. PostgreSQL installed by EnterpriseDB keeps pg_config in /Library/PostgreSQL/9.4/bin/pg_config
$gem install pg -- --with-pg-config=/Library/PostgreSQL/9.4/bin/pg_config

To be continued:
1. Version Control (Git) ?
2. Continuous integration (CI) system?
3. Editors?

Tuesday, November 25, 2014

Android Rookie Diary 11/25/2014

Just started a project that allows android phone talk to a STM32f103 (ARM 32bit Cortex-M3). It's been quite a while since I touched Android whose version was Gingerbread (2.3.3). As an android rookie right now, I'd like to keep a "diary" that could remind me of any mistakes that I made while I'm working on this project.

null exception.
It's easy to make such a stupid mistake if you've been off Java/Android for a while.
First, it's null exception in regards of View.
1:  @Override  
2:  protected void onCreate(Bundle savedInstanceState) {  
3:      super.onCreate(savedInstanceState); 
4:      mTextView = (TextView) findViewById(R.id.textview);  
5:      mTextView.setText("JunEnd");
6:      setContentView(R.layout.activity_register);
7:  }  
setContentView() sets the activity content from a layout resource, so should be called before findViewById(). Otherwise findViewById() will return null because of no layout resource and thus line 5 throws a null exception.

Second, it's null exception in regards of Spinner.
1:  public class RegisterActivity extends Activity implements OnItemSelectedListener {  
2:      private Spinner mSpinner;  
3:      private ArrayList<String> mArrayList_SpinnerList;  
4:      @Override  
5:      protected void onCreate(Bundle savedInstanceState) {  
6:          super.onCreate(savedInstanceState);  
7:          setContentView(R.layout.activity_register);  
8:          ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,  
9:                  android.R.layout.simple_spinner_item, mArrayList_SpinnerList);  
10:          adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);  
11:          mSpinner.setAdapter(adapter);  
12:          mSpinner.setOnItemSelectedListener(this);  
13:      }  
14:      @Override  
15:      public void onItemSelected(AdapterView<?> parent, View view, int pos,  
16:              long id) {  
17:          // TODO Auto-generated method stub  
19:      }  
20:      @Override  
21:      public void onNothingSelected(AdapterView<?> arg0) {  
22:          // TODO Auto-generated method stub  
23:      }  
24:  }  
I forgot to instantiate mArrayList_SpinnerList and passed it to constructor ArrayAdapter() and then thus gave Spinner this adapter holding an uninstantiated object. I believe this is causing a null exception and killed the app.

Wednesday, February 22, 2012

Deep inspection of scheduler (2) -- computing next wake up time


Here, we are going to talk about the computation of the scheduler. As mentioned last blog, the next_wake is the essential variable that determines the next wake-up of the scheduler. So we will check where this variable is changed.

Code Segment 1 (next_wake is changed in the task scan):
        for (task_ID=0; task_ID < NRK_MAX_TASKS; task_ID++){
                ......
                if(nrk_task_TCB[task_ID].task_state == SUSPENDED){
                        ......          
                        if(nrk_task_TCB[task_ID].next_wakeup!=0 &&
                           nrk_task_TCB[task_ID].next_wakeup<next_wake )
next_wake=nrk_task_TCB[task_ID].next_wakeup;
                }
        }
From this segment, we conclude that next_wake is related with user-defined task's next wake-up time, since only user-defined task will have SUSPENDED task state and idle task won't. However, how's the next_wake changed?
Code Segment (in the task scanning loop)
        if( nrk_task_TCB[task_ID].task_ID!=NRK_IDLE_TASK_ID &&
             nrk_task_TCB[task_ID].task_state!=FINISHED ){
if(nrk_task_TCB[task_ID].next_wakeup >= _nrk_prev_timer_val)
nrk_task_TCB[task_ID].next_wakeup-=_nrk_prev_timer_val;
else 
nrk_task_TCB[task_ID].next_wakeup=0;
                ......
        }
The scenario described here by the code is that if the next_wakeup time line (which is defined initially by the nrk_create_taskset) is behind current task ending line plus 2ms, the next_wakeup time line should move forward by _nrk_prev_timer_val, otherwise, the task should be waken up immediately. Then the scheduler would execute this task soon. (Refer to last blog to see how does this happen)  However this may result in unexpected bugs if the next_wakeup is smaller than _nrk_prev_timer_val but not so much. Next blog would talk about these potential bugs in the scheduler.

Code Segment 2 (next_wake is changed in non-idle and idle tasks respectively):
In next executable non-idle task
  if(nrk_task_TCB[task_ID].cpu_reserve!=0 && 
            nrk_task_TCB[task_ID].cpu_remaining<MAX_SCHED_WAKEUP_TIME){
if(next_wake>nrk_task_TCB[task_ID].cpu_remaining)
next_wake=nrk_task_TCB[task_ID].cpu_remaining;
        }else
if(next_wake>MAX_SCHED_WAKEUP_TIME)    
                        next_wake=MAX_SCHED_WAKEUP_TIME; 
}
Here, we know that next_wake is also related with task's cpu remaining time. First, we have to notice that task's cpu_reserve should be initialized to non-zero. And then we have to know that task_ID here is the highest priority task ID. Additionally, the next_wake here is the closest next wake-up time line. Therefore, the code segment here indicates that next wake-up time is not allowed to exceed the highest priority task's cpu remaining time. It means that if next executable task is not idle, it has to be interrupted by the scheduler at the moment that the highest priority task's cpu remaining time is consumed out. This is actually undesired wake-up and may result in unexpected bugs.  Next blog would talk about these potential bugs in the scheduler.

In idle task
        if(next_wake>NRK_SLEEP_WAKEUP_TIME) {
if(next_wake-NRK_SLEEP_WAKEUP_TIME
                    <MAX_SCHED_WAKEUP_TIME){
if(next_wake-NRK_SLEEP_WAKEUP_TIME
                            <NRK_SLEEP_WAKEUP_TIME)
next_wake=NRK_SLEEP_WAKEUP_TIME-1;
else
next_wake=next_wake-NRK_SLEEP_WAKEUP_TIME;
}else if(next_wake>NRK_SLEEP_WAKEUP_TIME
                            +MAX_SCHED_WAKEUP_TIME
next_wake=MAX_SCHED_WAKEUP_TIME;
else 
next_wake=MAX_SCHED_WAKEUP_TIME
                                           -NRK_SLEEP_WAKEUP_TIME;
}
Since idle task has the lowest priority, we don't need to worry about that some other task would preempt it. We see that next_wake has to be larger than 10ms (which is represented by NRK_SLEEP_WAKEUP_TIME), otherwise next_wake is determined by Code Segment 1. Once the condition is satisfied, the scheduler would wake up 10ms before the closest next user-defined task. (because next_wake is determined by Code Segment 1 before) Therefore, we see that idle task plays a role here in making the processor sleep deep, just as mentioned before in last blog.

Generally, the computation here includes:
1. computes all the next_wakeups of tasks and pick the closest one as the next_wake which determines the next wake-up time of the scheduler.
2. Get the highest priority task ID (task_ID).
3. (1) If the task_ID indicates a non-idle task and cpu_reserve is initialized as non-zero, next_wake is set to cpu_remaining. (2) If the task_ID indicates an idle task, next_wake is 10ms before the closest next user-defined task.
4. _nrk_set_next_wakeup(next_wake) starts next round of scheduling.

Deep inspection of scheduler (1) -- scheduling flow

We leave two questions in last blog. We are gonna answer them here. First, we repeat the question:

1. How the scheduler knows or computes the next wake-up time for the idle and non-idle task?
2. How the scheduler tell the processor to wake up the non-idle task from the sleep mode? 

At first glance, we will see the following code at the end of scheduler:
Code Segment:
         ......
         _nrk_set_next_wakeup(next_wake); // scheduler would be called next_wake(ms) later
         ......
        nrk_start_high_ready_task(); // scheduler would start the ready task with the highest priority


Therefore, the essential thing in the scheduler is  the variable of next_wake which determines when the tasks would be scheduled again. Given this, we answer the first question by discussing about variable of next_wake and the second question by exploring how the task becomes the highest priority one.

The second question which refers to the scheduling flow may help us understanding the scheduler much more easily. Therefore, I am going to talk about the flow first.

Given that each task has to call nrk_wait_unit_next_period() at the end, we look into this method first and find that there are three important things that may be used in the scheduler (Explanation is made in the comments).
Code Segment:
        ......  
        nrk_cur_task_TCB->suspend_flag = 1; //current task is suspended
        ......

        timer += TIME_PAD; // timer records current OS timer value and TIME_PAD equals 2
        _nrk_prev_timer_val = timer; // used to compute next wake-up time in scheduler
        _nrk_set_next_wakeup (timer); // the scheduler would be called 2ms later
        ......

Then we look into the scheduler. The first thing scheduler does is to check the suspending flag of current task. If current task is suspended, the scheduler would remove the task from the ready queue that means once the user-defined task calls the scheduler it would be removed from the ready queue immediately.
Code Segment:
        if(nrk_cur_task_TCB->suspend_flag==1 && nrk_cur_task_TCB->task_state!=FINISHED){
                ......// here the task state would be changed
nrk_rem_from_readyQ(nrk_cur_task_TCB->task_ID);
}
Given the current non-idle task is removed, nrk_start_high_ready_task() would invoke other user-defined task if any. In the special case where there is only one user-defined task, this method would have to call the idle task which has the lowest priority by default.


Then, a new question may be raised intuitively: how would the scheduler add back the removed task to the ready queue? When continuing exploring the code, we find that the scheduler would scan all the tasks and in the scanning the removed task may be added back to the ready queue.
Code Segment:

        ......
        if (nrk_task_TCB[task_ID].task_state == SUSPENDED ) {
if (nrk_task_TCB[task_ID].next_wakeup == 0) {
                        ......
                        nrk_task_TCB[task_ID].suspend_flag=0;

                        if(nrk_task_TCB[task_ID].num_periods==1) {
                                ......
nrk_add_to_readyQ(task_ID);
}else{// if task has to wake up several period later, there is no need to add it back
                ......
                }
        }
Here, we can see that three conditions have to be satisfied before the task is added back to the ready queue. Intuitively, the task state must be SUSPENDED, since when the task calls the scheduler by nrk_wait_unit_next_period(), the  suspend_flag variable is set to 1 which would make task_state SUSPENDED at the beginning of the scheduler. And then the ready task should be waken up immediately, that is, next_wakeup would be 0. However, the next_wakeup variable does not count number of periods, so we have to check the number of periods and make sure that the task should wake up next period. Once the task is added back to the ready queue, nrk_start_high_ready_task() would decide which to be executed given that there are several tasks in the queue.


Generally, the scheduling flow goes like this,
1. Remove current task if it is suspended.
2. add task back to the ready queue if the task should be executed immediately (this process usually happens several scheduling rounds later)
3. start the highest priority task in the ready queue.

Though the process is simple, we have to determine when to wake up the scheduler. Waking up scheduler once is obviously not enough for adding task back to the ready queue, because when the scheduler is first called, its next_wakeup variable seldom becomes 0. As shown in Fig 1 on last blog, the scheduler would be called 3 times between the executions of one task.

Therefore, the first question has to be answered. We are gonna talk about it next blog.

Sunday, February 19, 2012

Notes about task execution and scheduler

Before talking about task scheduler, I am gonna inspect how the task is executed first.

How the task progresses?

First, you need to initialize the system by calling  nrk_init() where an idle task is created. The idle task is used in task scheduler for making tasks sleep deep (I will talk about it later in the scheduler section). And then you should create the task by calling nrk_create_taskset(), where task period, priority, CPU reserved time etc. are defined and especially the user-defined task is pushed into the task stack.

And then, nrk_start() starts executing all the tasks in the task stack. In nrk_start(), you should pay attention to two methods -- nrk_target_start() and nrk_start_high_ready_task()nrk_target_start() (defined in nrk_cpu.c) initializes timers (very important to the system because all the tasks are executed based on the timer) and nrk_start_high_ready_task() starts the ready task with the highest priority though it is defined hardware specific assembly file. Initially, all the tasks are ready so the task with the highest priority would be executed first.

Since the task is started, the processor would process the task. There are two points required high attention. 1. Task should not exceed the period defined before. 2. At the end of the task, nrk_wait_until_next_period() (defined in nrk_task.cmust be called. This method would bring you into the task scheduler.

How the scheduler works?

In nrk_wait_until_next_period(), the task scheduler would be called 2ms after the task finishes its job.
Code segment:

      ......
      timer += TIME_PAD; // TIMER_PAD = 2 and timer = nrk_os_timer_get();
      _nrk_prev_timer_val = timer;
      _nrk_set_next_wakeup (timer);
      ......
      _nrk_wait_for_scheduler ();
      ......
_nrk_prev_timer_val records task execution time plus 2ms and this value would be used in the scheduler to calculate next wake-up time. (we will talk about the computation in next blog) _nrk_set_next_wakeup (timer) would make the OS timer generate an interrupt 2ms later. _nrk_wait_for_scheduler () would make the task into the sleep mode. It should be noticed that the sleep mode is not the most power-saved. The deep sleep which indeed saves power would be made by the task scheduler.

However, the scheduler is hardware, namely timer, triggered. Looking into nrk_task.c, you would find that _nrk_scheduler() is called in the _nrk_timer_tick() which is called by the interrupt caused by the timer. That is to say, it is not the _nrk_wait_for_scheduler () trigger the scheduler but instead the _nrk_set_next_wakeup (timer).

Once the scheduler is on work, the idle task defined in  nrk_init() is used for making the process into deep sleep. Figure 1 shows it.
Fig 1
The yellow line indicates the task execution time. The purple line indicates the scheduler execution time. And the green line indicates the sleep mode time. It is obvious that the scheduler is called three times between two periods of the task. Actually, the processor calls the idle task at the first. The scheduler determines to start the task again at the second time since the scope shows that the processor enters the sleep mode again which is executed in the user-defined task. And the scheduler finally decides to start the task immediately since the task should start its new period. And also, you can see that during the first two callings the processor is not in the sleep mode. Actually, at that time, processor is in deep sleep. 

There would be two questions about the scheduler.
1. How the scheduler knows or computes the next wake-up time for the idle and non-idle task?
2. How the scheduler tell the processor to wake up the non-idle task from the sleep mode?