|Jobs| 無線通訊裡的 NAS 是什麼 ?

之前工作主要是負責 NAS 相關的事項。

不過講 NAS 大家應該都會以為是儲存裝置。無線通訊裡面的 NAS 是 Non-Access Stratum 的縮寫,中文稱為:非接入層。

以下為 3GPP 網站寫的定義:

The Non-Access Stratum is a set of protocols in the Evolved Packet System. The NAS is used to convey non-radio signalling between the User Equipment (UE) and the Mobility Management Entity (MME) for an LTE/E-UTRAN access.

WIKI 的定義:

Non-access stratum (NAS) is a functional layer in the UMTS and LTE wireless telecom protocol stacks between the core network and user equipment.

一步步用簡單的語言理解:

  1. 一開機的時候,UE 會做掃網、選網及配置網路的工作。這些事是預備要讓你的裝置"接入到網路"。
  2. 認識接入層:RNC (Radio Network Controller:3G 基地台控制器,負責通話處理、網路管理等機制)、NodeB (3G 基地台) 需要參與處理的就是接入層。
  3. 當接入層處理完成、把橋搭好後,接下來就是非接入層的事。
  4. MM (Mobile Management)、CC (Call Control)、SMS (Short Message Service) 均為非接入層的業務。
  5. 再濃縮來講:接入層是比較靠基地台的行為,非接入層比較靠使用者服務的端的事。

(以上,如有理解錯誤,歡迎指正)

以 3GPP 來說,如果要理解 NAS,就要看懂 RRC 和 EMM 相關的 Spec 囉!

至於如果你在工作內容(JD)看到 NAS,基本上,凡事 Framework 要跟 Modem 溝通,牽涉到網路狀態相關行為的都要管啦~

Ref.

3GPP: http://www.3gpp.org/more/96-nas

WIKI: https://en.wikipedia.org/wiki/Non-access_stratum

博客: https://blog.csdn.net/starperfection/article/details/78737741

|Design| Communicate with Kernel driver

User space can not exchange data with kernel space directly.
They need to use system call.
e.g. fopen, ioctl, write, read …… etc.

In Kernel Space ……
1. Register your device with “register_chrdev”, defined in linux/fs.h .
 https://ithelp.ithome.com.tw/articles/10159749
2. Implement driver functions, ioctl, open,…
 struct file_operations fops = {
  .owner = THIS_MODULE,
  .read = device1_read,
  .write = device1_write,
  .ioctl = device1_ioctl,
  .open = device1_open,
  .release = device1_release,
 };

 int ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 is in linux/ioctl.h
 http://ccckmit.wikidot.com/lk:io
 開發 driver 需要的基礎知識
 user space/kernel space 的IO觀念及實作

Copy data ……
 Kernel Space to User Space: copy_to_user()
 User Space to Kernel Space: copy_from_user()

In User Space ……
Use system call to control kernel driver.
 fopen (open)
 write
 read
 close
 seek
 poll / select
 ioctl
 mmap
 fcntl


e.g.

int main(int argc, char *argv[]){
  int devfd;
  int num = 0;

  if (argc > 1) num = atoi(argv[1]);
  if (num < 0) num = 0xff;

  devfd = open("/dev/debug", O_RDONLY);
  if (devfd == -1) {
    printf("Can't open /dev/debug\n");
    return -1;
  }

  printf("Write 0x%02x...\n", num);
  ioctl(devfd, IOCTL_WRITE, num);
  printf("Done. Wait 5 seconds...\n");
  sleep(5);
  close(devfd);

  return 0;
}

|Code| IPC methods

Originally, I though it is a basic interview question and everyone has at least a common answer .
Until I found someone did not know , I know I was wrong.

Threads can shares the same resources such as address space, file descriptors, stack and other process related attributes in the same process.
Processes can not share resources directly.

Processes will communicate to each other by IPC method.
There are two ways:
 1. Shared Memory
 2. Message passing

The following methods, which we often see, belong to message passing.
Pipe
Socket
Remote Procedural calls (RPCs)



https://www.geeksforgeeks.org/inter-process-communication-ipc/
https://stackoverflow.com/questions/200469/what-is-the-difference-between-a-process-and-a-thread

|Code| Makefile -I -L -l

e.g.
gcc -o hello hello.c -I /home/hello/include -L /home/hello/lib -lworld


Means:
-I /home/hello/include
Find headers in sequence of /home/hello/include–>/usr/include–>/usr/local/include

-L /home/hello/lib:
Find librarys in sequence of /home/hello/lib–>/lib–>/usr/lib–>/usr/local/lib

-lworld:
Find the library “libworld.so” in the path of “-L /home/hello/lib “

|Code| How to use control flow by pthread_cond_timedwait()

There are three parameters related with pthread_cond_timedwait().

Definition:
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);

Parameters:
pthread_cond_t *restrict cond : the condition you want to trigger this flow
pthread_mutex_t *restrict mutex : Mutual exclusion
const struct timespec *restrict abstime : absolutely waiting time ( = system time + waiting



【Step by Step】

Initial the mutex:
1. pthread_mutex_init(pthread_mutex_t *restrict  __mutex ,
              const pthread_mutexattr_t *restrict __mutex_attr);
   __mutex_attr can be NULL.
   __mutex_attr is the parameter about mutex.
  If it is not NULL, go to “2.”

2. pthread_mutexattr_init(pthread_mutexattr_t * __mutex_attr );
 pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
   type: PTHREAD_MUTEX_RECURSIVE,
      PTHREAD_MUTEX_NORMAL ……
3. pthread_cond_init(pthread_cond_t *restrict __cond ,
const pthread_condattr_t *restrict __cond_attr);

Start to wait for signal ” __cond “:
1. lock mutex: pthread_mutex_lock(&__mutex)
2. pthread_cond_timedwait(&__cond, &__mutex, &__abstime)
3. unlock mutex: pthread_mutex_unlock(&__mutex)

Start to send the signal ” __cond “:
1. lock mutex: pthread_mutex_lock(&__mutex)
2. pthread_cond_signal (&__cond)
3. unlock mutex: pthread_mutex_unlock(&__mutex)

Destroy the mutex:
1. pthread_mutex_destroy( pthread_mutex_t *restrict  __mutex );
2. pthread_mutexattr_destroy( pthread_mutexattr_t * __mutex_attr );
3. pthread_cond_destroy( pthread_cond_t *restrict __cond );

E.g.

// This thread will wait the signal.
void thread1(void *arg){
 int inArg = (int)arg;
 int ret = 0;
 struct timeval now;
 struct timespec outtime;

 pthread_mutex_lock(&g_mutex);

 gettimeofday(&now, NULL);
 outtime.tv_sec = now.tv_sec + 5;
 outtime.tv_nsec = now.tv_usec * 1000;
 ret = pthread_cond_timedwait(&g_cond, &g_mutex, &outtime);

 pthread_mutex_unlock(&g_mutex);
}


int main(void)
{
 pthread_t id1;
 int ret;

 // Initial mutex
 pthread_cond_init(&g_cond, NULL);
 pthread_mutex_init(&g_mutex, NULL);
 ret = pthread_create(&id1, NULL, (void *)thread1, (void *)1);

 if (0 != ret){
  printf(“thread 1 create failed!\n”);
  return 1;
 }

 printf(“Waiting %ds send the signal!\n”, SENDSIGTIME);
 sleep(SENDSIGTIME);

 // send the signal
 pthread_mutex_lock(&g_mutex);
 pthread_cond_signal(&g_cond);
 pthread_mutex_unlock(&g_mutex);
 pthread_join(id1, NULL);

 //Destroy the mutex
 pthread_cond_destroy(&g_cond);
 pthread_mutex_destroy(&g_mutex);
 return 0;
}

References:
https://blog.csdn.net/dead_g/article/details/73338960
https://linux.die.net/man/3/pthread_cond_timedwait
https://linux.die.net/man/3/pthread_cond_init
https://blog.csdn.net/yasi_xi/article/details/19112077

|Tools| Git v.s Repo

一般跟別人合作開發都是使用 git。那 repo 是什麼?
repo 是 Google 開發出來的工具,用來管理 Android 的。

一份 Android code 是由許多 project 組成的,每個 project 就是一個 git project。
repo 這個工具,就是可以管理 branches 以及眾多的 git project!

> repo init 後,可以找到 .repo/manifest.xml 這會記錄你控制的 projects

*基本工作流程與對照:

repo git
repo init -u URL -m ooxx.xml -b remote_branch git clone URL
repo sync -c git pull URL remote_branch:local_branch
repo start branch_name –all git branch branch_name
git status git status
git add git add
git commit git commit
repo upload . git push


*git 好用指令:
 > 查詢遠端的server 位置及名字
 git remote -v
 > 新增一個遠短 server
 git remote add {given_name} URL
 > 強迫 reset
 git reset –hard {local_branch}
 > 把 commit 推到遠端 branch
 git push {given_name} {local_branch}: refs/for/{remote_branch}
 > 從遠端 branch 拉 code 下來
 git pull {given_name} {remote_branch}:{local_branch}
 > 當前一個修改已 commit,又想把這次修改跟上一個修改一起 commit
 git commit –amend
 > 想上 patch 到某個已經 push 出去的 change
 git push {given_name} {local_branch}:refs/changes/{change_id}
 > 查詢某行的歷史
 git blame -L [行數] [檔案名]
 > 檢別 branch 的 commit 到目前的 branch
 git cherry-pick [sha-1]

*好用的配置
 > git commit 的模板:
 新增一個  ~/.git-template
 然後 git config commit.template ~/.git-template

 > 設置reviewers, git push rest,就會自動帶上 reviewers
 到 .git/config 編輯
 [remote “test”]
 pushurl = ssh://account@server_address:port/project_name
 push = {local_branch}:refs/for/{remote_branch}%r=someone1@mail, r=someone2@mail

*製作 patch,打 patch
 (在 branch A)
 git log
 git format-patch -1 [sha-1]
 mv ooxx.patch ~/
 (換到 branch B)
 git am [~/ooxx.patch]


值得注意的是:
pull 的 server / review 的 server / push 的 server 可能不同,
設置 push 的 server 時,請去確認 repo upload 時,到底是推到哪?


ref. [Coding] repo & git 的使用方法

WordPress.com.

Up ↑