Author Archives: admin

AC1300 driver install on ubuntu

Reference: https://community.tp-link.com/en/home/forum/topic/208022

Unplug the network USB adapter, then run the commands below

sudo apt install dkms
git clone https://github.com/cilynx/rtl88x2bu.git
cd rtl88x2bu
VER=$(sed -n 's/\PACKAGE_VERSION="\(.*\)"/\1/p' dkms.conf)
sudo rsync -rvhP ./ /usr/src/rtl88x2bu-${VER}
sudo dkms add -m rtl88x2bu -v ${VER}
sudo dkms build -m rtl88x2bu -v ${VER}
sudo dkms install -m rtl88x2bu -v ${VER}
sudo modprobe 88x2bu

Dual booting option with GRUB between Desktop and Terminal Modes

This article presents how to setup a dual booting option using Grub to select between Ubuntu Desktop or Terminal Only modes.

Introduction

Desktop environments make development easy but the execution of an application often does not need the desktop GUI environment. Actually, the desktop environments deteriorate the performance of an application especially if the application needs an RT performance. For the comparison, see another article of mine.

Thus, when we develop an application, the desktop environment is more useful than desktop environment, and otherwise, vise versa. There are multiple ways to transit between these two modes. In my opinion, dual booting is a nice option to achieve this goal. Particularly GRUB allows us for setting up the dual booting option easily.

Setup

Installation of Grub cusotmizer

I am using Grub Customizer to ease the process. For the installation follow the command below:

sudo add-apt-repository ppa:danielrichter2007/grub-customizer 
sudo apt update
sudo apt install grub-customizer

Setup of Grub cusotmizer

Open Grub Customizer by typing “Grub customizer” after press Menu button. Then, you will see menu below:

Then, choose the first option which is for Desktop. Then, click edit (Pencil Icon). You will see some pop-up like below:

Copy the entire boot sequence and paste it at a text editor. We will use this one later. Press “Cancel”, then go back to the main menu and click “New” button “+” Icon. Write the name of new booting configuration and, choose type “Other”. Then paste the text you got from previous Boot option. Here what you need to do is add 3 for the line “linux”. For details, see below:

linux    /boot/vmlinuz-4.4.208-rt191esmacat-master-s root=UUID=68f423de-1e99-43a2-a050-58e26b2ffb29 ro 3 quiet splash $vt_handoff

Once you finish, then press “Save” and “Exit”. Then boot again.

Result

Once you boot up, then you will see the menu allowing you to choose different options including “Command-line”. Once you choose the “Command-line” option, you can use Linux without loading desktop environments.

I hope this article helps your project. Good luck!

Histogram loop time

C++ Class for Loop Time Histogram Statistics

Overview

In this post, I am sharing a C++ Class for Loop Time Histogram. The class measures the loop time and provides its histogram statistics. It is very easy to use and portable. The class provides file output and file output + screen output features.

@Update 04/08/2020: Now histogram is printed in terminal for quick review. For details see the result picture below.

How to use

Simply include the class object, and add a function at the beginning of the loop. Finally, execute a function outputting the result.

Example Code

This example code will execute rand() function multiple times in a loop and measure its loop time.

#include <iostream>
#include <random>
#include "loop_time_stats.h"

using namespace std;

int main()
{
    loop_time_stats l("stats.txt",loop_time_stats::output_mode::fileout_and_screenout);

    for (int i=0;i<100000;i++){
        l.loop_starting_point();
        for (int j=0;j<5000;j++){
            int k =rand();
        }
    }
    l.store_loop_time_stats();
    return 0;
}

Result

C++ Class for Loop Time Histogram

The program also saves the result in a text file. I have plotted its result in Excel. The results are shown in the pictures below:

C++ Class for Loop Time Histogram

Download

You can download the class, example code, and excel files in the link below:

https://drive.google.com/drive/folders/1jMfjhO4zbqBd0Y_ozbGH7zhT0HMnUaZF?usp=sharing

Why did I develop this one?

It is critical for real-time applications to have consistent loop-times with low jitter. There are many different ways of measuring the loop time and generating the histogram (e.g., see cyclictest ( https://github.com/LITMUS-RT/cyclictest ) ), many of those are not portable.

While developing a program, these loop-time measurement codes need to be sometimes activated and sometimes deactivated. Finally they need to be removed at release. It means the code needs to be portable. Object-oriented programming (OOP) concept with C++ class is well suited for this purpose.

Thus, I have embedded all of the sophisticated-looking codes in the class and left only “init”, “loop_start_point”, and “save”. With this simple structure, the user would be easily manage the code with a minimal footage.

Reference

Good luck to your project, and if you have any questions or ideas to improve the codes, please leave a comment. Bye!

Parallel RT Processes with Same Periodic Cycles

For many control applications, multiple RT processes need to run with periodic cycles.

This article presents an example code that enables two RT applications to run with a same periodic cycle. Two RT processes share one shared memory to pass the reference start time of the thread.

Once two processes are synchronized, then two processes control their cycles with “CLOCK_MONOTONIC” clock.

The code for the first app code

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include "shared_memory_base.h"

#define TIMESPEC_ADD(A,B) /* A += B */ \
    do {                                   \
    (A).tv_sec += (B).tv_sec;          \
    (A).tv_nsec += (B).tv_nsec;        \
    if ( (A).tv_nsec >= 1000000000 ) { \
    (A).tv_sec++;                  \
    (A).tv_nsec -= 1000000000;     \
    }                                  \
    } while (0)

#define TIMESPEC_SUB(A,B) /* A -= B */ \
    do {                                   \
    (A).tv_sec -= (B).tv_sec;          \
    (A).tv_nsec -= (B).tv_nsec;        \
    if ( (A).tv_nsec < 0 ) {           \
    (A).tv_sec--;                  \
    (A).tv_nsec += 1000000000;     \
    }                                  \
    } while (0)


void *thread_func ( void *param )
{
    FILE *fp;
    char filename_fp[50];
    shared_memory_base comm;
    comm.init();
    comm.data->first_app_on=1;

    struct timespec t_1us;
    t_1us.tv_sec = 0; t_1us.tv_nsec=1000;


    long thread_id = (long) param;

    sprintf (filename_fp, "%ld%s", thread_id, ".txt");
    fp = fopen(filename_fp, "w");//opening file

    struct timespec t_next, period, t_now, t_prev, t_diff;

    /* period = 0.5 ms * thread_id */
    period.tv_sec = 0;
    period.tv_nsec = ( 1 ) * 500000; // a x ms

    comm.data->first_app_on = 1;
    while (comm.data->second_app_on == 0);
    clock_nanosleep ( CLOCK_MONOTONIC, 0, &t_1us, NULL );   // wait 1us for second app till it set up the t_ref
    t_now = comm.data->t_ref;
    t_next = t_now;
    t_prev = t_now;

    int t_jitter[100];
    for (int i=0;i<100;i++) t_jitter[i] = 0;
    int t_j = 0;

    for ( int i = 0; i < 10000; i++ )
    {
        clock_gettime ( CLOCK_MONOTONIC, &t_now );
        t_diff = t_now;
        TIMESPEC_SUB ( t_diff, t_prev );
        t_prev = t_now;
        t_j = t_diff.tv_nsec / 10000;
        if (t_j<0) t_jitter[0]++;
        else if (t_j>99) t_jitter[99]++;
        else t_jitter[t_j]++;
        if(i%1000==1) printf("second: %d\n",i);
        TIMESPEC_ADD ( t_next, period );
        clock_nanosleep ( CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL );
    }

    for (int i=0;i<100;i++) {
        printf("%d ",t_jitter[i]);
        fprintf(fp, "%d\n",t_jitter[i]);
    }
    fclose(fp);
    comm.detach_shared_memory();
    return NULL;
}

int main ()
{
    int policy;
    struct sched_param prio;
    pthread_attr_t attr;

    pthread_t tid1;

    policy = SCHED_OTHER;
    if (pthread_setschedparam( pthread_self(),policy, &prio )){
        perror ("Error: pthread_setschedparam (root permission?)");
        exit(1);
    }

    pthread_attr_init( &attr);
    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED);
    policy = SCHED_RR;
    pthread_attr_setschedpolicy( &attr, policy);
    prio.sched_priority = 1; // priority range should be btw -20 to +19
    pthread_attr_setschedparam(&attr,&prio);

    if ( pthread_create(&tid1, &attr, thread_func, (void *)(1)) ){
        perror ( "Error: pthread1_create" );
        return 1;
    }

    /* wait for threads to finish */
    pthread_join ( tid1, NULL );

    return 0;
}

The code for the second application

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include "shared_memory_base.h"

#define TIMESPEC_ADD(A,B) /* A += B */ \
    do {                                   \
    (A).tv_sec += (B).tv_sec;          \
    (A).tv_nsec += (B).tv_nsec;        \
    if ( (A).tv_nsec >= 1000000000 ) { \
    (A).tv_sec++;                  \
    (A).tv_nsec -= 1000000000;     \
    }                                  \
    } while (0)

#define TIMESPEC_SUB(A,B) /* A -= B */ \
    do {                                   \
    (A).tv_sec -= (B).tv_sec;          \
    (A).tv_nsec -= (B).tv_nsec;        \
    if ( (A).tv_nsec < 0 ) {           \
    (A).tv_sec--;                  \
    (A).tv_nsec += 1000000000;     \
    }                                  \
    } while (0)


void *thread_func ( void *param )
{
    FILE *fp;
    char filename_fp[50];
    shared_memory_base comm;
    comm.init();    // start the shared memory communication

    // get the file name
    long thread_id = (long) param;
    sprintf (filename_fp, "%ld%s", thread_id, ".txt");
    fp = fopen(filename_fp, "w");//opening file

    struct timespec t_next, period, t_now, t_prev, t_diff;

    /* period = 0.5 ms * thread_id */
    period.tv_sec = 0;
    period.tv_nsec = ( 1 ) * 500000; // a x ms

    comm.data->second_app_on = 1; // let the second app go
    while( comm.data->first_app_on == 0 );
    clock_gettime ( CLOCK_MONOTONIC, &t_now );
    comm.data->t_ref = t_now;
    t_next = t_now;
    t_prev = t_now;

    int t_jitter[100];
    for (int i=0;i<100;i++) t_jitter[i] = 0;
    int t_j = 0;


    for ( int i = 0; i < 10000; i++ )
    {
        clock_gettime ( CLOCK_MONOTONIC, &t_now );
        t_diff = t_now;
        TIMESPEC_SUB ( t_diff, t_prev );
        t_prev = t_now;
        t_j = t_diff.tv_nsec / 10000;
        if (t_j<0) t_jitter[0]++;
        else if (t_j>99) t_jitter[99]++;
        else t_jitter[t_j]++;
        if(i%1000==1) printf("first: %d\n",i);
        TIMESPEC_ADD ( t_next, period );
        clock_nanosleep ( CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL );
    }

    for (int i=0;i<100;i++) {
        printf("%d ",t_jitter[i]);
        fprintf(fp, "%d\n",t_jitter[i]);
    }
    fclose(fp);
    comm.detach_shared_memory();
    return NULL;
}

int main ()
{
    int policy;
    struct sched_param prio;
    pthread_attr_t attr;

    pthread_t tid1;

    policy = SCHED_OTHER;
    if (pthread_setschedparam( pthread_self(),policy, &prio )){
        perror ("Error: pthread_setschedparam (root permission?)");
        exit(1);
    }

    pthread_attr_init( &attr);
    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED);
    policy = SCHED_RR;
    pthread_attr_setschedpolicy( &attr, policy);
    prio.sched_priority = 1; // priority range should be btw -20 to +19
    pthread_attr_setschedparam(&attr,&prio);

    if ( pthread_create(&tid1, &attr, thread_func, (void *)(2)) ){
        perror ( "Error: pthread1_create" );
        return 1;
    }

    /* wait for threads to finish */
    pthread_join ( tid1, NULL );

    return 0;
}

The result of the execution of two programs

mok@mok-master-s:~/dev$ mkdir build
 mok@mok-master-s:~/dev$ cd build
 mok@mok-master-s:~/dev/build$ cmake ../rt_periodic_thread
 -- The CXX compiler identification is GNU 7.4.0
 -- Check for working CXX compiler: /usr/bin/c++
 -- Check for working CXX compiler: /usr/bin/c++ -- works
 -- Detecting CXX compiler ABI info
 -- Detecting CXX compiler ABI info - done
 -- Detecting CXX compile features
 -- Detecting CXX compile features - done
 -- Configuring done
 -- Generating done
 -- Build files have been written to: /home/mok/dev/build
 mok@mok-master-s:~/dev/build$ make
 Scanning dependencies of target first_app
 [ 16%] Building CXX object CMakeFiles/first_app.dir/first_rt_app.cpp.o
 [ 33%] Building CXX object CMakeFiles/first_app.dir/shared_memory_base.cpp.o
 [ 50%] Linking CXX executable first_app
 [ 50%] Built target first_app
 Scanning dependencies of target second_app
 [ 66%] Building CXX object CMakeFiles/second_app.dir/second_rt_app.cpp.o
 [ 83%] Building CXX object CMakeFiles/second_app.dir/shared_memory_base.cpp.o
 [100%] Linking CXX executable second_app
 [100%] Built target second_app
 mok@mok-master-s:~/dev/build$ mv ../rt_periodic_thread/runboth.sh ./
 mok@mok-master-s:~/dev/build$ chmod a+x runboth.sh 
 mok@mok-master-s:~/dev/build$ sudo ./runboth.sh 
 [sudo] password for mok: 
 second: 1
 first: 1
 second: 1001
 first: 1001
 second: 2001
 first: 2001
 first: 3001
 second: 3001
 second: 4001
 first: 4001
 first: 5001
 second: 5001
 first: 6001
 second: 6001
 first: 7001
 second: 7001
 second: 8001
 first: 8001
 second: 9001
 first: 9001
 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 60 2065 675 2339 2058 573 2187 32 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 7 40 2179 518 2484 2008 449 2269 37 5 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 mok@mok-master-s:~/dev/build$ ^C

Download and Build

https://drive.google.com/file/d/1kTSBW3HqnMccRxj6cudEWy5nLYXzAuuY/view?usp=sharing

You can build and run the two applications with the command below:

mkdir build
cd build
cmake ../rt_periodic_thread
make
mv ../rt_periodic_thread/runboth.sh ./
chmod a+x runboth.sh 
sudo ./runboth.sh 

Other Topics

Shared Memory IPC Ping-pong Sequence

Overview

In this post, I am sharing an example of IPC communication with a class using shared memory.

Two processes runs together, and their applications sequentially running. The end of each loop is marked at a shared memory with a “go-flag”. Once the other process see the end-of-the-loop flag, “go-flag”, the process continues the task.

Shared Memory IPC Class

I wrote this class to make the shared memory programming more portable. What you need to do is only to change the struct called “shared_memory_packet. You will see how to use this class in the examples of the next section. You can see the code of “shared_memory_base.h” and “shared_memory_base.cpp” below:

#ifndef SHARED_MEMORY_BASE_H
#define SHARED_MEMORY_BASE_H

#include <sys/ipc.h>
#include <sys/shm.h>

#define DEFAULT_KEY_ID  5700        // default key for shared memory

class shared_memory_base
{
    struct shared_memory_packet {
        float analog_input[16];
        bool go_flag_second_loop = 1;
        bool go_flag_first_loop = 1;
    };

private:
    key_t key;
    int shmid = 0;
public:
    shared_memory_base();
    ~shared_memory_base();

    shared_memory_packet* data;
    void init();
    void change_shared_memory_key(key_t k){key= k;} // only use this function before init
    void detach_shared_memory();
};

#endif // SHARED_MEMORY_BASE_H
#include "shared_memory_base.h"

shared_memory_base::shared_memory_base()
{
    key = ftok("shmfile",DEFAULT_KEY_ID);
}

shared_memory_base::~shared_memory_base(){
    detach_shared_memory();
}

void shared_memory_base::init(){
    // shmget returns an identifier in shmid
    shared_memory_packet temp;
    shmid = shmget(key, sizeof(temp),0666|IPC_CREAT);
    // shmat to attach to shared memory
    data = (shared_memory_packet*) shmat(shmid,(void*)0,0);
}

void shared_memory_base::detach_shared_memory(){
    shmdt(data);
    shmctl(shmid,IPC_RMID,nullptr);
}

Ping-pong Sequence between Two Processes

In this example, “first_app.cpp” the number of an integer variable incrementally, and change the “go_flag_second_loop” to be one. In “second_app.cpp” the number of an integer variable is reduced, and change the “go_flag_first_loop” to be one. With this two go_flags two processes run sequencially.

#include <iostream>
#include <unistd.h>
#include "shared_memory_base.h"

using namespace std;

int main()
{
    shared_memory_base comm;
    comm.init();

    comm.data->analog_input[0] =0;
    comm.data->analog_input[8] =0;

    for (int i=0;i<10;i++){
        while( comm.data->go_flag_first_loop != 1);
        comm.data->analog_input[0] = i;
        cout << "ai[8]: " << comm.data->analog_input[8] << endl;
        comm.data->go_flag_second_loop = 1;
        sleep(1);
    }

    cout << "end of the loop!" << endl;
    comm.detach_shared_memory();
    return 0;
}
#include <iostream>
#include "shared_memory_base.h"

using namespace std;

int main()
{
    shared_memory_base comm;
    comm.init();

    comm.data->analog_input[0] =0;
    comm.data->analog_input[8] =0;
    comm.data->go_flag_first_loop = 1;

    for (int i=0;i<10;i++){
        while( comm.data->go_flag_second_loop != 1);
        comm.data->analog_input[8] = 1000-i;
        cout << "ai[0]: " << comm.data->analog_input[0] << endl;
        comm.data->go_flag_second_loop = 0;
    }

    cout << "end of the loop!" << endl;
    comm.detach_shared_memory();
    return 0;
}

Result

The figures below shows the execution results of two applications.

Execution Result of “First_app”
Execution Result of “Second_app”

Download and Build the Codes

You can download the entire code and can build the code with the command below:

Download link

mkdir build
cd build
cmake ../shared_memory_example
make

More discussion

Concurrency problem is a very well-known and challenging problem. There are many other nice techniques other than this one. Particularly after C++11, the standard C++ has introduced a nice set of concurrent thread and process running functions. In addition, this example is not the best code for efficient applications.

I found a very good reference explaining Concurrency, Parallelism, Threads, Processes, Async and Sync. For the details, read the article in the link below:

https://medium.com/swift-india/concurrency-parallelism-threads-processes-async-and-sync-related-39fd951bc61d

Delete Dynamically Allocated Memory by Ctrl-C

Intro

In this post, I will share an example C/C++ code demonstrating a method to safely delete dynamically allocated memory when a user terminates the application by Ctrl-C.

Problem

First let’s review a code which includes a problem. The code dynamically allocate a memory for the variable a. The code has delete[] function, but the application cannot arrive there due to the infinite loop which is very common in may applications. If a user terminates the application with Ctrl-C, then the memory will be leaked.

#include <iostream>

int main(){
    signal(SIGINT, myInterruptHandler);

    double* a;
    a = new double [1000];

    std::cout << "press ctrl-c\n" ;
    while(1){  }

    delete[] a;
}

The figure below shows the execution results.

As you can see the, the free memory continuously is reduced every time after the termination of the application by Ctrl-C.

Solution by Using Signal

In Linux system, if a user press Ctrl-C, a signal is sent to the process from the OS. We can catch the signal and make a different routine. One example is as below:

#include <iostream>
#include <signal.h>

uint8_t loop_flag = 1;

void myInterruptHandler (int signum) {
    loop_flag = 0;
}

int main(){
    signal(SIGINT, myInterruptHandler);

    double* a;
    a = new double [1000];

    std::cout << "press ctrl-c\n" ;
    while(loop_flag){

    }

    delete[] a;
    std::cout << "\nelegantly terminated wihout memory leakage\n";
}

The result of the code above is shown in the figure below:

In contrast to the previous result, the memory is not leaked and elegantly terminated.

Download/Build of Source Code

You can download the source code at this link.

More topics to read

There is another function called “sigaction()”. It seems more robust and well -defined. But it seems to need more lines of codes. Thus, I decided to use signal. For the details, please read this post .

Reference

RT Periodic Thread Code and Scheduler Policy and Priority

in this post, I am going to share an example code creating two threads running with a periodic cycle in an RT Preempt Linux.

You can download the code in this link.

https://github.com/queristq/rt_periodic_thread/archive/master.zip or you can git clone by git clone https://github.com/queristq/rt_periodic_thread.git

To build the code,

  • mkdir build
  • cd build
  • cmake ..
  • make

RT Performance between SCHED_RT and SCHED_IDLE

In the code, I have created two threads, and tested the RT performance for two different thread schedule policy between SCHED_RT and SCHED_IDLE. The figure below shows the result. The blue line shows the log10-scaled histogram of the loop time, and the orange line shows the log10-scaled histogram of the loop time. As shown in the plot, SCHED_RT made low jitters in the periodic loops. The test environment was not strictly controlled (I did internet browsing… while the loop was running).

1

RT Performance over Different Thread Priorities

I have conducted similar tests with different thread priority. I have selected the same thread policy SCHED_FIFO, and the priority of two threads were chosen to 1 and 99 respectively. The jitters of the each loop is shown in the figure below. As shown in the figure, interestingly the difference was very minor. Once you see the details, you can see the result of Priority 1 is slightly better.

2

If you want a full result, you can see the test result in the attached excel sheet.

Example code

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>

#define TIMESPEC_ADD(A,B) /* A += B */ \
    do {                                   \
    (A).tv_sec += (B).tv_sec;          \
    (A).tv_nsec += (B).tv_nsec;        \
    if ( (A).tv_nsec >= 1000000000 ) { \
    (A).tv_sec++;                  \
    (A).tv_nsec -= 1000000000;     \
    }                                  \
    } while (0)

#define TIMESPEC_SUB(A,B) /* A -= B */ \
    do {                                   \
    (A).tv_sec -= (B).tv_sec;          \
    (A).tv_nsec -= (B).tv_nsec;        \
    if ( (A).tv_nsec < 0 ) {           \
    (A).tv_sec--;                  \
    (A).tv_nsec += 1000000000;     \
    }                                  \
    } while (0)


void *thread_func ( void *param )
{
    FILE *fp;
    char filename_fp[50];

    long thread_id = (long) param;

    sprintf (filename_fp, "%ld%s", thread_id, ".txt");
    fp = fopen(filename_fp, "w");//opening file

    struct timespec t_next, period, t_now, t_prev, t_diff;

    /* period = 1 ms * thread_id */
    period.tv_sec = 0;
    period.tv_nsec = ( 1 ) * 500000; // a x ms

    clock_gettime ( CLOCK_MONOTONIC, &t_now );
    t_next = t_now;
    t_prev = t_now;

    int t_jitter[100];
    for (int i=0;i<100;i++) t_jitter[i] = 0;
    int t_j = 0;

    for ( int i = 0; i < 100000; i++ )
    {
        clock_gettime ( CLOCK_MONOTONIC, &t_now );
        t_diff = t_now;
        TIMESPEC_SUB ( t_diff, t_prev );
        t_prev = t_now;
        t_j = t_diff.tv_nsec / 10000;
        if (t_j<0) t_jitter[0]++;
        else if (t_j>99) t_jitter[99]++;
        else t_jitter[t_j]++;
        if(i%10000==1) printf("%d\n",i);
        TIMESPEC_ADD ( t_next, period );
        clock_nanosleep ( CLOCK_MONOTONIC, TIMER_ABSTIME, &t_next, NULL );
    }

    for (int i=0;i<100;i++) {
        printf("%d ",t_jitter[i]);
        fprintf(fp, "%d\n",t_jitter[i]);
    }
    fclose(fp);
    return NULL;
}

int main ()
{
    int policy;
    struct sched_param prio;
    pthread_attr_t attr;

    pthread_t tid1;
    pthread_t tid2;

    policy = SCHED_OTHER;
    if (pthread_setschedparam( pthread_self(),policy, &prio )){
        perror ("Error: pthread_setschedparam (root permission?)");
        exit(1);
    }

    pthread_attr_init( &attr);
    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED);
    policy = SCHED_FIFO;
    pthread_attr_setschedpolicy( &attr, policy);
    prio.sched_priority = 99; // priority range should be btw -20 to +19
    pthread_attr_setschedparam(&attr,&prio);

    if ( pthread_create(&tid1, &attr, thread_func, (void *)(1)) ){
        perror ( "Error: pthread1_create" );
        return 1;
    }

    pthread_attr_init( &attr);
    pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED);
    policy = SCHED_FIFO;
    pthread_attr_setschedpolicy( &attr, policy);
    prio.sched_priority = 1; // priority range should be btw -20 to +19
    pthread_attr_setschedparam(&attr,&prio);

    if ( pthread_create(&tid2, &attr, thread_func, (void *)(2)) ){
        perror ( "Error: pthread2_create" );
        return 1;
    }

    /* wait for threads to finish */
    pthread_join ( tid1, NULL );
    pthread_join ( tid2, NULL );

    return 0;
}

If you are interested in how to make an RT Linux, please see another post of mine.

I found a very good material to study deeper on RT thread.

  • https://csperkins.org/teaching/2004-2005/rtes5/lecture10.pdf
  • http://retis.sssup.it/~lipari/courses/str09/10.rtprogramming-handout.pdf

If you have any questions on this code or this post, please leave a reply. Then, good luck!

[1] Nanosleep, http://man7.org/linux/man-pages/man2/nanosleep.2.html

[2] Timespec basic operation, http://www.zemris.fer.hr/~leonardo/srsv/skripta/src/periodic-tasks-2.c

Tutorial: How to make RT Preempt Linux with Ubuntu 18.04.02

In this tutorial, I will present how to make a RT Preempt Linux with Ubuntu 18.04.02

1. install Ubuntu 18.04.02 in your computer. Let me skip the details since there are so many other tutorials for this.

2. Once the install is finished. Download Linux kernel and RT Patch

  • Linux Kernel Download at

https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/

Screenshot from 2020-02-20 23-20-00

  • RT patch download at https://mirrors.edge.kernel.org/pub/linux/kernel/projects/rt/4.4/

Screenshot from 2020-02-20 23-21-54

3. Prepare to compile the kernel

cd Downloads/
xz -cd linux-4.4.208.tar.xz | tar xvf -
cd linux-4.4.208/
xzcat ../patch-4.4.208-rt191.patch.xz | patch -p1
sudo apt install libncurses5-dev build-essential cmake libssl-dev git flex bison
make menuconfig
  • Set “High Resulution Timer Support” Screenshot from 2020-02-21 00-08-07 Screenshot from 2020-02-21 00-08-13
  • Set “Fully Preemptible Kernel (RT)

Screenshot from 2020-02-21 00-08-47 Screenshot from 2020-02-21 00-09-26 Screenshot from 2020-02-21 00-09-43

  • (optional) set Local version nameScreenshot from 2020-02-21 00-10-24 Screenshot from 2020-02-21 00-10-28
  • Save the config fileScreenshot from 2020-02-21 00-11-08

4. Compile and install the kernel ( WARNING: It takes very long time)

make -j20
sudo make modules_install -j20
sudo make install -j20

Here -jx is to specify the number of CPU cores, if you just choose a high number, it go with your all CPU cores.

5. Grub setting

sudo gedit /etc/default/grub

Then, edit the text as below:

To select the booting option in GRUB

GRUB_TIMEOUT_STYLE=hidden -> GRUB_TIMEOUT_STYLE=menu

To increase the time out for selecting a menu

GRUB_TIMEOUT=0 -> GRUB_TIMEOUT=3

To reduce the visual effect

GRUB_CMDLINE_LINUX_DEFAULT=”quiet splash” -> GRUB_CMDLINE_LINUX_DEFAULT=”quiet”

If you want to boot without graphical desktop (terminal mode)

GRUB_CMDLINE_LINUX=”” -> GRUB_CMDLINE_LINUX=”3″

5. Rebooting

sudo update-grub
sudo reboot

6. Select RT-preempt kernel in GRUB

select Advanced and RT-Linux

(Optional)  If you want to customize GRUB more, then use grub-customizer (grub editor with GUI)

sudo add-apt-repository ppa:danielrichter2007/grub-customizer 
sudo apt update
sudo apt install grub-customizer

Other readings

Now you are ready to develop or run an RT application on RT Preempt Linux. If you need to know how to write a RT thread running with a periodic cycle, read another article of mine.

Good luck!

3D Print File for Light Switch Plate for 3 gang hybrid option 2-1

I am sharing a CAD design for someone who want to print a Light Switch Plate for 3 gang hybrid option 2-1. The plate is for one big toggle switch and two small toggle switches.

For the details see the below:

20190819_123310 <3d printed part>

20190901_185658~2

<Installed on the wall>

front_view <Front view>

back_view <Back view>

iso_view <ISO view>

You can download the stl file for 3d printing here.

https://drive.google.com/drive/folders/1Gwn4jNH-e14B5v7UduRJ3eGo9obeO48m?usp=sharing

For design of this file, I have obtained the mechanical dimensions from the sites below:

[1] https://www.doorware.com/site/product.cfm?id=421618

[2] https://diy.stackexchange.com/questions/77960/are-all-rectangular-outlets-switches-and-plates-the-same-dimensions-and-interc

 

 

C code converting two’s complement data into signed long int

ADC ICs (e.g., ADS1256, ADS1246) often outputs an analog voltage value in the format of  2’s complement.  I am sharing a simple function and example that convert the format of two’s complement into signed long int.

for the detailed knowledge on the format of 2’s complement, please refer this site.

https://en.wikipedia.org/wiki/Two%27s_complement

I hope this post is helpful for your projects.