brook@vista:~/protobuf$ git clone git://github.com/google/protobuf.git
Cloning into 'protobuf'...
...
brook@vista:~/protobuf/protobuf$ git checkout 3.6.x
Branch 3.6.x set up to track remote branch 3.6.x from origin.
...
brook@vista:~/protobuf/protobuf$ . /opt/oecore-x86_64/environment-setup-cortexa7-neon-vfpv4-oe-linux-gnueabi
brook@vista:~/protobuf/protobuf$ vim configure.ac
export CFLAGS
export CXXFLAGS
### remove below line ###
AC_CONFIG_SUBDIRS([third_party/googletest])
brook@vista:~/home6t/protobuf/protobuf$ ./autogen.sh
+ mkdir -p third_party/googletest/m4
+ autoreconf -f -i -Wall,no-obsolete
...
brook@vista:~/protobuf/protobuf$ ./configure ${CONFIGURE_FLAGS} --prefix=/home/brook/protobuf/
configure: loading site script /opt/oecore-x86_64/site-config-cortexa7-neon-vfpv4-oe-linux-gnueabi
checking whether to enable maintainer-specific portions of Makefiles... yes
checking build system type... x86_64-pc-linux-gnu
...
brook@vista:~/protobuf/protobuf$ make all -j 8
make all-recursive
Making install in .
make[1]: Entering directory '/home/brook/protobuf/protobuf'
...
brook@vista:~/protobuf/protobuf$ make install
Making install in .
make[1]: Entering directory '/home/brook/protobuf/protobuf'
...
change "/home/brook/protobuf/lib/libprotoc.la"
from
# Libraries that this one depends upon.
dependency_libs=' =/home6t/brook/protobuf/lib/libprotobuf.la =/usr/lib/libstdc++.la'
to
# Libraries that this one depends upon.
dependency_libs=''
brook@vista:~$ mkdir protobuf-c
brook@vista:~$ cd protobuf-c
brook@vista:~/protobuf-c$ git clone git://github.com/protobuf-c/protobuf-c.git
Cloning into 'protobuf-c'...
remote: Enumerating objects: 59, done.
remote: Counting objects: 100% (59/59), done.
...
brook@vista:~/protobuf-c/protobuf-c$ ./autogen.sh
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
...
brook@vista:~/protobuf-c/protobuf-c$ PROTOC=/usr/bin/protoc-c protobuf_CFLAGS="-I/home/brook/protobuf/include" protobuf_LIBS="-L/home/brook/protobuf/lib" ./configure ${CONFIGURE_FLAGS} --prefix=/home/brook/protobuf-c
configure: loading site script /opt/oecore-x86_64/site-config-cortexa7-neon-vfpv4-oe-linux-gnueabi
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
...
brook@vista:~/protobuf-c/protobuf-c$ make -j 8
make all-am
make[1]: Entering directory '/home/brook/protobuf-c/protobuf-c'
CC protobuf-c/protobuf-c.lo
...
2019年7月7日 星期日
Using openembedded SDK to build protobuf-c
2019年6月23日 星期日
Build the Linux Kernel and Busybox for ARM and run them on QEMU
安裝corss-compiler brook@vista:~/qemu$ wget http://releases.linaro.org/components/toolchain/binaries/7.4-2019.02/arm-linux-gnueabihf/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz brook@vista:~/qemu$ tar xvf gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz brook@vista:~/qemu$ sudo mv gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf /opt/ 編譯kernel brook@vista:~/qemu$ cd linux-arm brook@vista:~/qemu/linux-arm$ export ARCH=arm brook@vista:~/qemu/linux-arm$ export CROSS_COMPILE=arm-linux-gnueabihf- brook@vista:~/qemu/linux-arm$ export PATH=/opt/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf/bin:$PATH brook@vista:~/qemu/linux-arm$ make vexpress_defconfig brook@vista:~/qemu/linux-arm$ make -j8 編譯busybox brook@vista:~/qemu/busybox$ export ARCH=arm brook@vista:~/qemu/busybox$ export CROSS_COMPILE=arm-linux-gnueabihf- brook@vista:~/qemu/busybox$ make O=/home/brook/qemu/busybox-build menuconfig --> change to static busyboxbrook@vista:~/qemu/busybox$ cd ../busybox-build brook@vista:~/qemu/busybox-build$ make -j8 brook@vista:~/qemu/busybox-build$ cp busybox ../initrd-arm/bin/busybox generate initrd-image brook@vista:~/qemu$ ./linux-arm/usr/gen_initramfs_list.sh -d initrd-arm > /tmp/brook_initramfs_list brook@vista:~/qemu$ ./linux-arm/usr/gen_init_cpio /tmp/brook_initramfs_list > initrd-arm.img 執行QEMU brook@vista:~/qemu$ /usr/local/bin/qemu-system-arm -M vexpress-a9 -m 512M -kernel ./linux-arm/arch/arm/boot/zImage -dtb ./linux-arm/arch/arm/boot/dts/vexpress-v2p-ca9.dtb -initrd ./initrd-arm.img -nographic -append "console=ttyAMA0"
![]()
-
參考資料:
- http://albert-oma.blogspot.com/2017/12/qemu-arm-linux.html, [QEMU] 模擬一個實際的 ARM Linux 嵌入式系統
- https://www.centennialsoftwaresolutions.com/blog/build-the-linux-kernel-and-busybox-for-arm-and-run-them-on-qemu, Build the Linux Kernel and Busybox for ARM and run them on QEMU
2019年6月15日 星期六
Build QEMU 4 on ubuntu 16.04
brook@vista$ ./configure --target-list="arm-softmmu,i386-softmmu,x86_64-softmmu,arm-linux-user,i386-linux-user,x86_64-linux-user" --enable-debug --enable-sdl --enable-kvm --enable-curl --enable-snappy --enable-tools
ERROR: User requested feature sdl
configure was not able to find it.
Install SDL2-devel
brook@vista$ sudo apt-get install libsdl2-2.0-0
brook@vista$ ./configure --target-list="arm-softmmu,i386-softmmu,x86_64-softmmu,arm-linux-user,i386-linux-user,x86_64-linux-user" --enable-debug --enable-sdl --enable-kvm --enable-curl --enable-snappy --enable-tools
Install prefix /usr/local
BIOS directory /usr/local/share/qemu
firmware path /usr/local/share/qemu-firmware
binary directory /usr/local/bin
library directory /usr/local/lib
module directory /usr/local/lib/qemu
libexec directory /usr/local/libexec
include directory /usr/local/include
config directory /usr/local/etc
local state directory /usr/local/var
Manual directory /usr/local/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path /home/brook/qemu4/qemu-4.0.0-rc4
GIT binary git
GIT submodules
C compiler cc
Host C compiler cc
C++ compiler c++
Objective-C compiler cc
ARFLAGS rv
CFLAGS -g
...
module support no
host CPU x86_64
host big endian no
target list arm-softmmu i386-softmmu x86_64-softmmu arm-linux-user i386-linux-user x86_64-linux-user
gprof enabled no
sparse enabled no
strip binaries no
profiler no
static build no
SDL support yes (2.0.4)
SDL image support no
GTK support no
GTK GL support no
VTE support no
TLS priority NORMAL
GNUTLS support no
libgcrypt no
nettle no
libtasn1 no
PAM no
iconv support yes
curses support yes
virgl support no
curl support yes
mingw32 support no
Audio drivers pa oss
Block whitelist (rw)
Block whitelist (ro)
VirtFS support no
Multipath support no
VNC support yes
VNC SASL support no
VNC JPEG support yes
VNC PNG support yes
xen support no
brlapi support no
bluez support no
Documentation no
PIE yes
vde support no
netmap support no
Linux AIO support no
ATTR/XATTR support yes
Install blobs yes
KVM support yes
HAX support no
HVF support no
WHPX support no
TCG support yes
TCG debug enabled yes
TCG interpreter no
malloc trim support yes
RDMA support no
PVRDMA support no
fdt support git
membarrier no
preadv support yes
fdatasync yes
madvise yes
posix_madvise yes
posix_memalign yes
libcap-ng support no
vhost-net support yes
vhost-crypto support yes
vhost-scsi support yes
vhost-vsock support yes
vhost-user support yes
Trace backends log
spice support no
rbd support no
xfsctl support no
smartcard support no
libusb no
usb net redir no
OpenGL support no
OpenGL dmabufs no
libiscsi support no
libnfs support no
build guest agent yes
QGA VSS support no
QGA w32 disk info no
QGA MSI support no
seccomp support no
coroutine backend ucontext
coroutine pool yes
debug stack usage no
mutex debugging yes
crypto afalg no
GlusterFS support no
gcov gcov
gcov enabled no
TPM support yes
libssh2 support no
TPM passthrough
TPM emulator
QOM debugging yes
Live block migration yes
lzo support no
snappy support yes
bzip2 support no
lzfse support no
NUMA host support no
libxml2 no
tcmalloc support no
jemalloc support no
avx2 optimization yes
replication support yes
VxHS block device no
bochs support yes
cloop support yes
dmg support yes
qcow v1 support yes
vdi support yes
vvfat support yes
qed support yes
parallels support yes
sheepdog support yes
capstone internal
docker yes
libpmem support no
libudev yes
default devices yes
brook@vista$ make all
GEN arm-softmmu/config-devices.mak.tmp
GEN arm-softmmu/config-devices.mak
GEN i386-softmmu/config-devices.mak.tmp
...
brook@vista$ sudo make all install
[sudo] password for brook:
make[1]: Entering directory '/home/brook/qemu4/qemu-4.0.0-rc4/slirp'
brook@vista$ /usr/local/bin/qemu-system-x86_64 -kernel linux/arch/x86/boot/bzImage -initrd initrd.img -curses
-
參考資料:
- https://blog.csdn.net/candcplusplus/article/details/78320602, QEMU 2.10.1 编译安装
2019年6月1日 星期六
Protocol Buffers - for C++
Protocol buffers基本上我把他想成是一個資料庫應用的延伸, 這話該如何說呢? 基本上他就是透過名為proto的meta file, 用以描述資料形態與內容(做encode/decode).
How does the Protocol Buffers work?
先定義你的message結構, 如
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
再用protoc將該檔案轉成code, 目前支援(C++, Java and Python), 如下例子, 將brook.proto轉成C++(brook.pb.cc與brook.pb.h).
brook@vista:~/protobuf/CPP$ protoc --cpp_out=. brook.proto brook@vista:~/protobuf/CPP$ ls brook.pb.cc brook.pb.h brook.proto
這些code會包含存取每一個欄位的API(如下由doxygen產生的圖), 如email()與set_email(), 用以serialize/parse資料,
接著我們就可以用這些API寫一段code, 做serialize/parse資料
#include <iostream>
#include <fstream>
#include "brook.pb.h"
using namespace std;
static void _Serialize(void)
{
Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("jdoe@example.com");
fstream output("myfile", ios::out | ios::binary);
person.SerializeToOstream(&output);
}
static void _Parse(void)
{
Person person;
fstream input("myfile", ios::in | ios::binary);
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
}
int main(int argc, char *argv[])
{
_Serialize();
_Parse();
return 0;
}
brook@vista:~/protobuf/CPP$ g++ main.c brook.pb.cc -lprotobuf
brook@vista:~/protobuf/CPP$ ./a.out
Name: John Doe
E-mail: jdoe@example.com
- 參考資料:
- protocol buffer簡介, https://developers.google.com/protocol-buffers/docs/overview
2019年1月13日 星期日
Note for SCons 3.0.3 User Guide, CH5 Node Objects
所有的檔案與目錄在SCons中都被視為"Nodes",善用"Node"可以使您的SConscript文件可移植且易於閱讀。
5.1. Builder Methods Return Lists of Target Nodes
所有builder methods都回傳一個Node list,用於辨識要構建的目標文件。這Node list可作為參數傳遞給其他builder methods。
brook@vista:~/scons/04.7$ cat SConstruct
a_list = Object('a.c', CCFLAGS='-DHELLO')
b_list = Object('b.c', CCFLAGS='-DWORLD')
Program(a_list + b_list)
brook@vista:~/scons/04.7$ scons -Q
gcc -o a.o -c -DHELLO a.c
gcc -o b.o -c -DWORLD b.c
gcc -o a a.o b.o
5.2. Explicitly Creating File and Directory Nodes
SCons的File()與Dir()可回傳file或directory Node,而Entry()可回傳file或directory Node。
hello_c = File('hello.c')
Program(hello_c)
classes = Dir('classes')
Java(classes, 'src')
xyzzy = Entry('xyzzy')
5.3. Printing Node File Names
您可以對Node執行print,打Node所代表的檔名。
brook@vista:~/scons/05.3$ cat SConstruct
object_list = Object(['a.c', 'b.c'])
program_list = Program(object_list)
print("The object file is: %s"%object_list)
print("The program file is: %s"%program_list[0])
brook@vista:~/scons/05.3$ scons -Q
The object file is: ['a.o', 'b.o']
The program file is: a
scons: `.' is up to date.
5.4. Using a Node's File Name as a String
您可以使用Python的str函數將Node轉成字串加以處理。
brook@vista:~/scons/05.5$ cat SConstruct
import os
object_list = Object(['a.c', 'b.c'])
obj_str = str(object_list[0])
print("The object file is: %s"% obj_str)
if not os.path.exists(obj_str):
print("%s does not exist!"% obj_str)
else:
print("%s exist!"% obj_str)
brook@vista:~/scons/05.5$ scons -Q
The object file is: a.o
a.o exist!
scons: `.' is up to date.
5.5. GetBuildPath: Getting the Path From a Node or String
env.GetBuildPath(file_or_list)可以用來取得file/Node的路徑。
brook@vista:~/scons/05.6$ cat SConstruct
object_list = Object(['a.c', 'b.c'])
env=Environment(VAR="value")
n=File("foo.c")
print(env.GetBuildPath([n, "sub/dir/$VAR", '/tmp'] + object_list))
brook@vista:~/scons/05.6$ scons -Q
['foo.c', 'sub/dir/value', '/tmp', 'a.o', 'b.o']
scons: `.' is up to date.
-
參考資料:
- SCons 3.0.3 User Guide
Note for SCons 3.0.3 User Guide, CH4 Building and Linking with Libraries
4.1. Building Libraries
在軟體開發過程中,將軟體切成數個library是很常見的,build成library在SCons中也是很容易完成的。如果是要build成library,只需將builder method從Program換成Library即可。
Library('foo', ['f1.c', 'f2.c', 'f3.c'])
SCons會根據當前的系統,build出該Library,如Linux
% scons -Q cc -o f1.o -c f1.c cc -o f2.o -c f2.c cc -o f3.o -c f3.c ar rc libfoo.a f1.o f2.o f3.o ranlib libfoo.a
Windows
C:\>scons -Q cl /Fof1.obj /c f1.c /nologo cl /Fof2.obj /c f2.c /nologo cl /Fof3.obj /c f3.c /nologo lib /nologo /OUT:foo.lib f1.obj f2.obj f3.obj
Library會build成static library,你也可以使用StaticLibrary來build static library
brook@vista:~/scons/04.2$ cat SConstruct
StaticLibrary('foo',['a.c', 'b.c'])
brook@vista:~/scons/04.2$ scons -Q
gcc -o a.o -c a.c
gcc -o b.o -c b.c
ar rc libfoo.a a.o b.o
ranlib libfoo.a
你也可以使用SharedLibrary 來build shared library
brook@vista:~/scons/04.3$ cat SConstruct
SharedLibrary('foo',['a.c', 'b.c'])
brook@vista:~/scons/04.3$ scons -Q
gcc -o a.os -c -fPIC a.c
gcc -o b.os -c -fPIC b.c
gcc -o libfoo.so -shared a.os b.os
4.2. Linking with Libraries
如果你的Program需要link某個Library,你只需在Program中指定$LIBS與$LIBPATH
brook@vista:~/scons/04.5$ cat SConstruct
SharedLibrary('foo',['a.c'])
StaticLibrary('bar',['b.c'])
Program('prog', 'prog.c', LIBS=['foo', 'bar'], LIBPATH='.')
brook@vista:~/scons/04.5$ scons -Q
gcc -o a.os -c -fPIC a.c
gcc -o b.o -c b.c
ar rc libbar.a b.o
ranlib libbar.a
gcc -o libfoo.so -shared a.os
gcc -o prog.o -c prog.c
gcc -o prog prog.o -L. -lfoo -lbar
4.3. Finding Libraries: the $LIBPATH Construction Variable
如果你要SCons尋找系統以外的library目錄,你指定$LIBPATH
brook@vista:~/scons/04.5$ cat SConstruct
SharedLibrary('foo',['a.c'])
StaticLibrary('bar',['b.c'])
Program('prog', 'prog.c', LIBS=['foo', 'bar'], LIBPATH=['/brook/lib', '.'])
brook@vista:~/scons/04.5$ scons -Q
gcc -o a.os -c -fPIC a.c
gcc -o b.o -c b.c
ar rc libbar.a b.o
ranlib libbar.a
gcc -o libfoo.so -shared a.os
gcc -o prog.o -c prog.c
gcc -o prog prog.o -L/brook/lib -L. -lfoo -lbar
-
參考資料:
- SCons 3.0.3 User Guide
2019年1月5日 星期六
Note for SCons 3.0.1 User Guide, CH3 Less Simple Things to Do With Builds
3.1. Specifying the Name of the Target (Output) File
當你呼叫Program()時,Scons會build出跟source file一樣檔名的程式,如果要build不同檔名的程式,可以Program()左邊參數放檔名,右邊放source file
brook@vista:~/scons/03.1$ cat SConstruct
Program('new_hello', 'hello.c')
brook@vista:~/scons/03.1$ scons -Q
gcc -o hello.o -c hello.c
gcc -o new_hello hello.o
brook@vista:~/scons/03.1$ scons -c -Q
Removed hello.o
Removed new_hello
3.2. Compiling Multiple Source Files
如果要從多個source file建立程式,只需在Program()放置python list,則會建立以第一個source file為檔名的程式檔brook@vista:~/scons/03.1$ cat SConstruct Program(['hello.c', 'a.c']) brook@vista:~/scons/03.1$ scons -Q gcc -o a.o -c a.c gcc -o hello.o -c hello.c gcc -o hello hello.o a.o
如果要建立不同程式名稱,只需在Program()左邊參數放檔名,右邊放source file list即可
brook@vista:~/scons/03.1$ cat SConstruct
Program('new_hello', ['hello.c', 'a.c'])
brook@vista:~/scons/03.1$ scons -Q
gcc -o a.o -c a.c
gcc -o hello.o -c hello.c
gcc -o new_hello hello.o a.o
3.3. Making a list of files with Glob
你可以適用Glob()來找尋matching的檔案,其語法可以使用*, ? and [abc]等shell的regular expression
brook@vista:~/scons/03.02$ cat SConstruct
Program('new_hello', Glob("*.c"))
brook@vista:~/scons/03.02$ scons -Q
gcc -o a.o -c a.c
gcc -o hello.o -c hello.c
gcc -o new_hello a.o hello.o
3.4. Specifying Single Files Vs. Lists of Files
SCons將所有source file視為list,只要符合list即可
# The following two calls both work correctly:
Program('program1', 'program1.c')
Program('program2', ['program2.c'])
common_sources = ['file1.c', 'file2.c']
# THE FOLLOWING IS INCORRECT AND GENERATES A PYTHON ERROR
# BECAUSE IT TRIES TO ADD A STRING TO A LIST:
Program('program1', common_sources + 'program1.c')
# The following works correctly, because it's adding two
# lists together to make another list.
Program('program2', common_sources + ['program2.c'])
3.5. Making Lists of Files Easier to Read
SCons中的Split()可以將字串內的檔案換成list,讓developer寫一個容易閱讀的list
brook@vista:~/scons/03.4$ cat SConstruct
print('a.c b.c c.c')
print(Split('a.c b.c c.c'))
src_files = Split('a.c b.c c.c')
print(src_files)
brook@vista:~/scons/03.4$ scons -Q
a.c b.c c.c
['a.c', 'b.c', 'c.c']
['a.c', 'b.c', 'c.c']
scons: `.' is up to date.
3.6. Keyword Arguments
Python預設是positional argument(位置參數),是按順序傳入function。關鍵字參數(keyword argument),顧名思義是以關鍵字方式傳入,使用keyword argument時,對順序沒有要求。Program(target, source)
src_files = Split('main.c file1.c file2.c')
Program(target = 'program', source = src_files)
src_files = Split('main.c file1.c file2.c')
Program(source = src_files, target = 'program')
3.7. Compiling Multiple Programs
如果要編譯多個程式,只需多描述幾行Program()即可
brook@vista:~/scons/03.7$ cat SConstruct
Program('a.c')
Program('b.c')
brook@vista:~/scons/03.7$ scons -Q
gcc -o a.o -c a.c
gcc -o a a.o
gcc -o b.o -c b.c
gcc -o b b.o
3.8. Sharing Source Files Between Multiple Programs
SCons會自行判斷build的dependence,所以你只需照實描述各個program所需的source file即可
brook@vista:~/scons/03.7$ cat SConstruct
Program('a', ['a.c', 'comm.c'])
Program('b', ['b.c', 'comm.c'])
brook@vista:~/scons/03.7$ scons -Q
gcc -o a.o -c a.c
gcc -o comm.o -c comm.c
gcc -o a a.o comm.o
gcc -o b.o -c b.c
gcc -o b b.o comm.o
3.9. Overriding construction variables when calling a Builder
當你在呼叫這些builder時,Scons允許你帶入一些參數或覆蓋原本的參數,如 adds 'include' to $CPPPATH, 'EBUG' to $CPPDEFINES, and 'm' to $LIBS.
Program('hello', 'hello.c', parse_flags = '-Iinclude -DEBUG -lm')
-
參考資料:
- SCons 3.0.1 User Guide
2019年1月1日 星期二
Note for SCons 3.0.1 User Guide, CH2 Simple Builds
SCons是一個用Python的新一代軟體建構工具(SCons is a next-generation software construction tool),就像Make一樣可以建構軟體的工具。
CH 2.1. Build Simple C/C++ Programs
主要依具名為SConstruct的檔案進行建構,最小的SConstruct內容如下
Program('hello.c')
這裡面包含兩個資訊,你要建構的程式名稱(hello),以及從哪個檔案建構(hello.c),"Program"在文中被稱為builder_method,主要用於告訴SCons要建構執行檔。
% scons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... cc -o hello.o -c hello.c cc -o hello hello.o scons: done building targets.
CH 2.2. Building Object Files
Object('hello.c')
Objcet這個builder method用於告訴SCons如何從指定的source files中建立一個Object file
% scons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... cc -o hello.o -c hello.c scons: done building targets.
2.4. Cleaning Up After a Build
在SCons清除(Cleaning Up)一個build只需要在scons後面新增"-c"/"--clean"即可2.5. The SConstruct File
SConstruct之於SCons就等同於Makefile之於Make,而SConstruct是個Python Script,注意,SConstruct的順序並非SCons實際執行的順序 比如該SConstruct的內容與其執行結果分別為
print("Calling Program('hello.c')")
Program('hello.c')
print("Calling Program('goodbye.c')")
Program('goodbye.c')
print("Finished calling Program()")
hello.c先被呼叫,而後才是goodbye.c
% scons
scons: Reading SConscript files ...
Calling Program('hello.c')
Calling Program('goodbye.c')
Finished calling Program()
scons: done reading SConscript files.
scons: Building targets ...
cc -o goodbye.o -c goodbye.c
cc -o goodbye goodbye.o
cc -o hello.o -c hello.c
cc -o hello hello.o
scons: done building targets.
goodbye先被建置,而後才是hello
2.6. Making the SCons Output Less Verbose
參數"-Q"可以讓SCons輸出較少的建置訊息brook@vista:~$ scons -Q gcc -o hello.o -c hello.c brook@vista:~$ scons -c scons: Reading SConscript files ... scons: done reading SConscript files. scons: Cleaning targets ... Removed hello.o scons: done cleaning targets. brook@vista:~$ scons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... gcc -o hello.o -c hello.c scons: done building targets.
-
參考資料:
- SCons 3.0.1 User Guide
2018年11月25日 星期日
Note for LTE Frequency bands and channel bandwidths
- Band 33 - Band 52為TDD,其餘為FDD。如果要簡單了解TDD/FDD的運作,可以看這段簡介Duplex in LTE Fundamentals of 4G LTE,在FDD的Downlink與Uplink中間會有Guard band,它將兩個頻率分開。這確保了同時使用的通信信道不會受到干擾,這將導致兩種傳輸的質量降低。TDD與FDD在Duplex in LTE Fundamentals of 4G LTE有簡單易懂的解釋。
- LTE中定義了幾種不同的bandwidth,分別為1.4MHz、3MHz、5MHz、10MHz、15MHz與20MHz。不同的bandwidth會有不同大小的Guard band(概略約10%,實際算法可以參考LTE guard band calculation)。
-
參考資料:
- https://arimas.com/lte-guard-band-calculation/
- LTE frequency bands
- Duplex in LTE Fundamentals of 4G LTE
2018年11月4日 星期日
AWS IoT Testing with MQTT.FX
AWS IoT基本上就是MQTT,這篇文章簡介如何Create一個AWS IoT device並使用MQTT.FX測試。
Create a IoT Device on AWS
Create a thing
Create a CERT
Enable CERT
Link CERT to instance
Download CERT
[Learn] -> [Connect to AWS IoT] -> [Configuring a device] -> [Get Start] -> [Choose a platform] / [Choose a AWS IoT Device SDK]
Check/Show your URL
Testing with MQTT.FX
2018年10月28日 星期日
2018年9月22日 星期六
note for autoconf - CH1 Introduction
Autoconf是一個用於生成shell script的工具(我們稱這個script為“configure”),可自動配置source code以適應Posix系統。“configure”可獨立運行(用戶不需要使用Autoconf)。“configure”在運行時不需要手動用戶干預; 甚至不需要指定係統類型的參數。 而且“configure”會測試source code/package所需的環境。Autoconf的目標是讓每個user都能夠輕鬆的執行“configure”。Autoconf在其目標方面非常成功,多數抱怨都是關於編寫Autoconf,而不是由此產生的“configure”的行為。
-
參考資料:
- https://www.gnu.org/software/autoconf/manual/index.html, Autoconf documentation
- https://bootlin.com/pub/conferences/2016/elc/petazzoni-autotools-tutorial/petazzoni-autotools-tutorial.pdf, GNU Autotools: a tutorial
2018年9月9日 星期日
Mount UBI with nandsim
UBI/UBIFS無法使用loop-back方式mount, 不過我們可以使用NAND simulator將UBI燒入到nandsim中.
root@vista:~# mkfs.ubifs -m 2KiB -e 129024 -c 2048 -r ubifs-root -x zlib ubifs.img root@vista:~# cat ubi.ini [ubi_rfs] mode=ubi image=ubifs.img vol_id=0 vol_type=dynamic vol_name=ubi_rfs vol_alignment=1 vol_flags=autoresize root@vista:~# ubinize -o my.ubi -p 128KiB -m 2KiB -O 512 ubi.ini ubinize: volume size was not specified in section "ubi_rfs", assume minimum to fit image "ubifs.img"1806336 bytes (1.7 MiB) root@vista:~# modprobe nandsim first_id_byte=0x20 second_id_byte=0xaa third_id_byte=0x00 fourth_id_byte=0x15 root@vista:~# ubiformat /dev/mtd0 -f my.ubi ubiformat: mtd0 (nand), size 268435456 bytes (256.0 MiB), 2048 eraseblocks of 131072 bytes (128.0 KiB), min. I/O size 2048 bytes libscan: scanning eraseblock 2047 -- 100 % complete ubiformat: 2048 eraseblocks have valid erase counter, mean value is 3 ubiformat: flashing eraseblock 15 -- 100 % complete ubiformat: formatting eraseblock 2047 -- 100 % complete ubiformat: formatting eraseblock 2047 -- 100 % complete root@vista:~# ubiattach -m 0 UBI device number 0, total 2048 LEBs (264241152 bytes, 252.0 MiB), available 0 LEBs (0 bytes), LEB size 129024 bytes (126.0 KiB) root@vista:~# ubinfo -a UBI version: 1 Count of UBI devices: 1 UBI control device major/minor: 10:55 Present UBI devices: ubi0 ubi0 Volumes count: 1 Logical eraseblock size: 129024 bytes, 126.0 KiB Total amount of logical eraseblocks: 2048 (264241152 bytes, 252.0 MiB) Amount of available logical eraseblocks: 0 (0 bytes) Maximum count of volumes 128 Count of bad physical eraseblocks: 0 Count of reserved physical eraseblocks: 40 Current maximum erase counter value: 9 Minimum input/output unit size: 2048 bytes Character device major/minor: 245:0 Present volumes: 0 Volume ID: 0 (on ubi0) Type: dynamic Alignment: 1 Size: 2002 LEBs (258306048 bytes, 246.3 MiB) State: OK Name: ubi_rfs Character device major/minor: 245:1 root@vista:~# mount -t ubifs /dev/ubi0_0 www
Usage: mkfs.ubifs [OPTIONS] target
Make a UBIFS file system image from an existing directory tree
Options:
-r, -d, --root=DIR build file system from directory DIR
-m, --min-io-size=SIZE minimum I/O unit size
-e, --leb-size=SIZE logical erase block size
-c, --max-leb-cnt=COUNT maximum logical erase block count
-x, --compr=TYPE compression type - "lzo", "favor_lzo", "zlib" or
"none" (default: "lzo")
# mkfs.ubifs -F -r </path/to/your/rootfs/tree> -m <min io size> -e <LEB size> -c
<Erase Blocks count> -o </path/to/output/Image.ubifs>
<min io size> Equals the page-size of the used NAND-Flash
<LEB size> Logical Erase Block size
<Erase Blocks count> maximum logical erase block count
mkfs.ubifs -m 2KiB -e 129024 -c 2048 -r ubifs-root -x zlib ubifs.img這些相關參數是先用ubiformat確認的, 不過-e是在mount failed的時候看dmesg的
Usage: ubinize [-o filename] [-pubinize -o my.ubi -p 128KiB -m 2KiB -O 512 ubi.ini這些參數也是在ubiformat修正的, 如-O 512] [-m ] [-s ] [-O ] [-e ] [-x ] [-Q ] [-v] [-h] [-V] [--output= ] [--peb-size= ] [--min-io-size= ] [--sub-page-size= ] [--vid-hdr-offset= ] [--erase-counter= ] [--ubi-ver= ] [--image-seq= ] [--verbose] [--help] [--version] ini-file -p, --peb-size= size of the physical eraseblock of the flash this UBI image is created for in bytes, kilobytes (KiB), or megabytes (MiB) (mandatory parameter) -m, --min-io-size= minimum input/output unit size of the flash in bytes -O, --vid-hdr-offset= offset if the VID header from start of the physical eraseblock (default is the next minimum I/O unit or sub-page after the EC header) # ubinize -vv -o <output image> -m <min io size> -p <PEB size>KiB -s <subpage-size> -O <VID-hdr-offset> <configuration file> <min io size> Equals the page-size of the used NAND-Flash <PEB size> Physical Erase Block size (in KiB) - Equals the block size of the NAND-Flash <Erase Blocks count> Count of the available Erase Blocks <subpage-size> Subpage size in bytes. Default value is the minimum input/output size (page-size) <VID-hdr-offset> offset if the VID header from start of the PEB (default is the next min I/O unit or sub-page after the EC header) <configuration file> Path to a configuration file.
-
參考資料:
- http://www.linux-mtd.infradead.org/faq/ubifs.html#L_loop_mount, Can UBIFS mount loop-back devices?
- https://elinux.org/UBIFS, UBIFS
- http://www.linux-mtd.infradead.org/faq/nand.html#L_nand_nandsim, How do I use NAND simulator?
標籤:
Linux - MTD
2018年9月2日 星期日
How to clone MDM9207 codeaurora/openembedded
筆記一下How to clone MDM9207 codeaurora/openembedded
brook@vista:~/oe-9x07$ git clone https://gerrit.googlesource.com/git-repo Cloning into 'git-repo'... remote: Counting objects: 139, done remote: Total 4069 (delta 2714), reused 4069 (delta 2714) Receiving objects: 100% (4069/4069), 1.21 MiB | 0 bytes/s, done. Resolving deltas: 100% (2714/2714), done. Checking connectivity... done. brook@vista:~/oe-9x07$ ln -s git-repo/repo brook@vista:~/oe-9x07$ ./repo init -u git://codeaurora.org/quic/le/le/manifest.git -b release -m LE.UM.1.0.2-34100-9x07.xml Get https://gerrit.googlesource.com/git-repo/clone.bundle Get https://gerrit.googlesource.com/git-repo Get git://codeaurora.org/quic/le/le/manifest.git remote: Counting objects: 4009, done. remote: Compressing objects: 100% (191/191), done. remote: Total 4009 (delta 84), reused 0 (delta 0) KiB/s Receiving objects: 100% (4009/4009), 1.07 MiB | 706.00 KiB/s, done. Resolving deltas: 100% (2191/2191), done. From git://codeaurora.org/quic/le/le/manifest * [new branch] IMM.LE.1.0 -> origin/IMM.LE.1.0 * [new branch] release -> origin/release ... ... Your identity is: Brook Kuo <rene3210 at gmail.com> If you want to change this, please re-run 'repo init' with --config-name repo has been initialized in /home/brook/oe-9x07 brook@vista:~/oe-9x07$ ./repo sync Fetching project platform/vendor/qcom/titanium_32 remote: Counting objects: 5758, done. remote: Compressing objects: 100% (375/375), done. remote: Total 5758 (delta 305), reused 380 (delta 177) Receiving objects: 100% (5758/5758), 1.02 MiB | 868.00 KiB/s, done. Resolving deltas: 100% (3639/3639), done. From git://codeaurora.org/platform/vendor/qcom/titanium_32 * [new branch] LA.BR.1.3.7_rb1.11 -> caf/LA.BR.1.3.7_rb1.11 ... ... Fetching projects: 100% (58/58), done. Checking out files: 100% (52804/52804), done. files: 23% (12539/52804) Checking out files: 100% (622/622), done. out files: 26% (167/622) Syncing work tree: 100% (58/58), done.
-
參考資料
- https://gerrit.googlesource.com/git-repo/, repo - The Multiple Git Repository Tool
- https://wiki.codeaurora.org/xwiki/bin/QLBEP/, Open Embedded for MSM
標籤:
Embedded - qcm
note - Blue Ocean Strategy
2018年9月1日 星期六
note - The Balanced ScoreCard
平衡計分卡不能為企業創造策略,但能幫組織有效執行策略。平衡計分卡以組織的共同願景與戰略為內核,將公司的願景與戰略轉化為下屬各責任部門(如各事業部)在財務(Financial)、顧客(Customer)、內部流程(Internal Processes)、創新與學習(Innovation&Learning)等四個方面的系列具體目標(即成功的因素),並設置相應的四張計分卡,其基本框架見下圖:
優點:
企業向來以財務數字做為績效衡量的標準,但無論是業績目標或營收、投資報酬率等,都是反映過去行動所獲致的成果;簡單說,財務數字衡量的是「過去的績效」,是一種「落後指標」,而非創造未來績效的指引。
平衡計分卡的理念在於:在財務衡量(落後指標)之外,積極找出能夠創造未來財務成果的「績效驅動因素」(performance driver),也就是相較財務成果而言的「領先指標」,例如顧客滿意度、高效率的流程、員工能力、士氣等,讓「績效衡量制度」能與「策略」配合一致。
平衡計分卡不僅是一種管理手段,也體現了一種管理思想,就是:只有量化的指標才是可以考核的,必須將要考核的指標進行量化
缺點:
平衡計分卡中有一些條目是很難解釋清楚或者是衡量出來的。財務指標當然不是問題,而非財務指標往往很難去建立起來。
-
參考資料:
- http://wiki.mbalib.com/zh-tw/%E5%B9%B3%E8%A1%A1%E8%AE%A1%E5%88%86%E5%8D%A1, 平衡計分卡
- https://www.managertoday.com.tw/articles/view/2489, 5分鐘!了解「平衡計分卡」
2018年8月25日 星期六
Using gdbserver to debug MDM9xxx
openembedded提供了一個良好的gdb環境,設定步驟如下。
brook@vista:/home/brook/apps_proc/poky/build$ tar zxvf tmp-glibc/deploy/images/mdm9607/machine-image-mdm9607-dbg.tar.gz ./ ./var/ ./var/lib/ ./var/lib/opkg/ ./var/lib/opkg/info/ ... brook@vista:/home/brook/apps_proc/poky/build$ mv usr/lib/.debug/* usr/lib/ brook@vista:/home/brook/apps_proc/poky/build$ mv lib/.debug/* lib brook@vista:/home/brook/apps_proc/poky/build$ ln -s libconfig.so.9.2.0 usr/lib/libconfig.so.9 ... brook@vista:/home/brook/apps_proc/poky/build$ ln -s libpthread-2.22.so lib/libpthread.so.0 brook@vista:/home/brook/apps_proc/poky/build$ ln -s librt-2.22.so lib/librt.so.1 brook@vista:/home/brook/apps_proc/poky/build$ ln -s libm-2.22.so lib/libm.so.6 brook@vista:/home/brook/apps_proc/poky/build$ ln -s libc-2.22.so lib/libc.so.6 brook@vista:/home/brook/apps_proc/poky/build$ ln -s ld-2.22.so lib/ld-linux.so.3 brook@vista:/home/brook/apps_proc/poky/build$ ln -s libdl-2.22.so lib/libdl.so.2 ... brook@vista:/home/brook/apps_proc/poky/build/tmp-glibc/work/armv7a-vfp-neon-oe-linux-gnueabi/myprog/git-r0/build/src$ adb push myprog /usr/bin/myprog brook@vista:/home/brook/apps_proc/poky/build/tmp-glibc/work/armv7a-vfp-neon-oe-linux-gnueabi/myprog/git-r0/build/src$ adb shell sh-3.2# gdbserver :2345 /usr/bin/myprog Process /usr/bin/myprog created; pid = 9035 Listening on port 2345
接著host端就可以開啟GDB來debug了
brook@vista:/home/brook/apps_proc/poky/build/tmp-glibc/work/armv7a-vfp-neon-oe-linux-gnueabi/myprog/git-r0/build/src$ arm-oe-linux-gnueabi-gdb myprog
GNU gdb (GDB) 7.10.1
Copyright (C) 2015 Free Software Foundation, Inc.
...
Reading symbols from myprog...done.
(gdb) set sysroot /home/brook/apps_proc/poky/build/
(gdb) target remote 10.0.0.1:2345
Remote debugging using 10.0.0.1:2345
Reading symbols from /home/brook/apps_proc/poky/build//lib/ld-linux.so.3...done.
0xb6fceac0 in ?? ()
(gdb) b main
Breakpoint 1 at 0x7f5595ac: file /home/brook/apps_proc/poky/build/tmp-glibc/work/armv7a-vfp-neon-oe-linux-gnueabi/myprog/git-r0/src/main.c, line 207.
(gdb) c
Continuing.
Breakpoint 1, main (argc=1, argv=0xbefffdf4)
at /home/brook/apps_proc/poky/build/tmp-glibc/work/armv7a-vfp-neon-oe-linux-gnueabi/myprog/git-r0/src/main.c:207
207 {
(gdb) set sysroot /home/brook/apps_proc/poky/build
warning: .dynamic section for "/home/brook/apps_proc/poky/build/lib/libpthread.so.0" is not at the expected address (wrong library or version mismatch?)
warning: .dynamic section for "/home/brook/apps_proc/poky/build/lib/libm.so.6" is not at the expected address (wrong library or version mismatch?)
warning: .dynamic section for "/home/brook/apps_proc/poky/build/lib/libc.so.6" is not at the expected address (wrong library or version mismatch?)
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
Reading symbols from /home/brook/apps_proc/poky/build/usr/lib/libconfig.so.9...done.
Reading symbols from /home/brook/apps_proc/poky/build/lib/libpthread.so.0...done.
Reading symbols from /home/brook/apps_proc/poky/build/lib/librt.so.1...done.
Reading symbols from /home/brook/apps_proc/poky/build/lib/libm.so.6...done.
Reading symbols from /home/brook/apps_proc/poky/build/lib/libc.so.6...done.
Reading symbols from /home/brook/apps_proc/poky/build/lib/libdl.so.2...done.
(gdb) info share
From To Syms Read Shared Object Library
0x7473e7c0 0x7475a328 Yes /home/brook/apps_proc/poky/build/lib/ld-linux.so.3
0xb6fc42d0 0xb6fca6e0 Yes /home/brook/apps_proc/poky/build/usr/lib/libconfig.so.9
0xb6ebc210 0xb6ecb4e8 Yes /home/brook/apps_proc/poky/build/lib/libpthread.so.0
0xb6ea2720 0xb6ea6034 Yes /home/brook/apps_proc/poky/build/lib/librt.so.1
0xb6e28bf0 0xb6e5ac20 Yes /home/brook/apps_proc/poky/build/lib/libm.so.6
0xb6ced280 0xb6dee638 Yes /home/brook/apps_proc/poky/build/lib/libc.so.6
0xb6cc3928 0xb6cc4870 Yes /home/brook/apps_proc/poky/build/lib/libdl.so.2
確認所有symbol都有找到之後, 就可以開始debug之旅了.
2018年8月11日 星期六
note for "The Art of Readable Code" - CH13 Writing Less Code
The most readable code is no code at all.Programmer最重要的技能之一就是知道哪些code不用寫,因為寫出來就要測試&維護,越小的程式碼越容易被維護,coupling程度越低越好,最好彼此獨立,有幾個方向:
- Create as much generic “utility” code as possible to remove duplicated code. (See Chapter 10, Extracting Unrelated Subproblems.)
- Remove unused code or useless features. (See the following sidebar.)
- Keep your project compartmentalized into disconnected subprojects.
- Generally, be conscious of the “weight” of your codebase. Keep it light and nimble.
Be Familiar with the Libraries Around You
每隔一段時間應該要花一下時間,讀一下你的 standard library,目的在於能對standard library的API有概念,以便在coding時能聯想到,並大量且反覆地使用這些library。- 參考資料:
- The Art of Readable Code
2018年7月29日 星期日
note for "The Art of Readable Code" - CH12 Turning Thoughts into Code
You do not really understand something unless you can explain it to your grandmother.— Albert Einstein
先用口語描述演算法後,再轉成程式碼,能讓programmer寫出更自然的code,也有助於找出可以分解的子問題。
We are reading three row iterators in parallel. Whenever the rows' times don't line up, advance the rows so they do line up. Then print the aligned rows, and advance the rows again. Keep doing this until there are no more matching rows left.
上述口語轉成的code為
def PrintStockTransactions():
stock_iter = ...
price_iter = ...
num_shares_iter = ...
while True:
time = AdvanceToMatchingTime(stock_iter, price_iter, num_shares_iter)
if time is None:
return
# Print the aligned rows.
print "@", time,
print stock_iter.ticker_symbol,
print price_iter.price,
print num_shares_iter.number_of_shares
stock_iter.NextRow()
price_iter.NextRow()
num_shares_iter.NextRow()
- 參考資料:
- The Art of Readable Code
note for "The Art of Readable Code" - CH11 One Task at a Time
Code should be organized so that it’s doing only one task at a time.舉個投票例子,投UP則+1,Down則-1,結果為所有投票總和,如果依據該rule,則code應該是
var vote_changed = function (vote) {
var score = get_score();
score += vote_value(vote);
set_score(score);
};
基本上這個章節的概念跟前一章節差不多"將子問題抽離,讓function專注在處理問題本身上面"。其餘細節就不贅述了。
-
參考資料:
- The Art of Readable Code
2018年7月28日 星期六
note for "The Art of Readable Code" - CH10 Extracting Unrelated Subproblems
將子問題抽離,讓function專注在處理問題本身上面,首先要先了解這個function的"目的",接著抽離與"目的"無關的子問題,將這些子問題一一寫成獨立的function,如:(簡單說就主程式專注在邏輯上,細節部分就一一寫成sub function處理)
// Return which element of 'array' is closest to the given latitude/longitude.
// Models the Earth as a perfect sphere.
var findClosestLocation = function (lat, lng, array) {
var closest;
var closest_dist = Number.MAX_VALUE;
for (var i = 0; i < array.length; i += 1) {
// Convert both points to radians.
var lat_rad = radians(lat);
var lng_rad = radians(lng);
var lat2_rad = radians(array[i].latitude);
var lng2_rad = radians(array[i].longitude);
// Use the "Spherical Law of Cosines" formula.
var dist = Math.acos(Math.sin(lat_rad) * Math.sin(lat2_rad) +
Math.cos(lat_rad) * Math.cos(lat2_rad) *
Math.cos(lng2_rad - lng_rad));
if (dist < closest_dist) {
closest = array[i];
closest_dist = dist;
}
}
return closest;
};
抽離後的code
var spherical_distance = function (lat1, lng1, lat2, lng2) {
var lat1_rad = radians(lat1);
var lng1_rad = radians(lng1);
var lat2_rad = radians(lat2);
var lng2_rad = radians(lng2);
// Use the "Spherical Law of Cosines" formula.
return Math.acos(Math.sin(lat1_rad) * Math.sin(lat2_rad) +
Math.cos(lat1_rad) * Math.cos(lat2_rad) *
};
var findClosestLocation = function (lat, lng, array) {
var closest;
var closest_dist = Number.MAX_VALUE;
for (var i = 0; i < array.length; i += 1) {
var dist = spherical_distance(lat, lng, array[i].latitude, array[i].longitude);
if (dist < closest_dist) {
closest = array[i];
closest_dist = dist;
}
}
return closest;
};
抽離這些子問題的另一個好處容易優化,比如有更好的方式去運算spherical_distance()或是變更findClosestLocation()的運算邏輯。建立通用的function也是一個很好也很重要的習慣,當你開發一個新的program時,就可以運用這些通用function,快速建立一個prototype。
Simplifying an Existing Interface & Reshaping an Interface to Your Needs
如果既有的API不好用,那就包裝他或改寫他吧,我在A Wrap for service/thread也包裝了一些API,讓自己易於開發,有必要也會進行Reshaping/Re-factor等等步驟。- 參考資料:
- The Art of Readable Code
2018年7月8日 星期日
Table Of Content for tag "Design Patterns with C "
- A pattern for state machine
- A pattern for state machine II - SM framework
- A pattern for state machine III - SM framework
- An Sample Code for Syslogd - A log pattern with categorize, level and format
- An Sample Code for Syslogd - A log pattern with categorize, level and format II
- An Sample Code for threads control - A Wrap for service/threadstart/stop/periodical run
- An Sample Code for notification-chain
- A pattern for command table
2018年6月17日 星期日
Linux Kernel(15.3)- The Linux usage model for device tree data
這篇基本上就是"Documentation/devicetree/usage-model.txt", The Linux usage model for device tree data的筆記
DT(Device Tree,或稱Open Firmware Device Tree)是一個資料結構(data structure)用於讓OS讀取硬體周邊訊息動態執行,因此OS就不用hard code硬體驅動。
所謂的"bindings"就是一組通用的DTS設定,用來描述其硬體,包含了data busses, interrupt lines, GPIO connections, and peripheral devices等等。
盡可能使用現有的binding來描述硬體,以最大限度地利用現有的代碼,但由於property和node名稱只是字串,因此通過定義新property和node可以輕鬆擴展現有binding。 不要沒做功課就自己建立新的binding,i2c busses就因為沒有先確認是否已經有人定義了相關的binding,就建立了新的binding,導致現在有兩套不相容的binding發生。
DT所做的只是提供一種language將硬體設定從device driver分離開來,如此可以透過傳入不同的DT給OS,以適應不同的硬體設定裝置. 進而減少一些重複的code。
DT在Linux底下有三個主要目的 1) platform identification, 2) runtime configuration, and 3) device population.
platform identification
首先kernel會先使用DT來辨識特定的機器,並且執行相關的初始化,比如ARM會在setup_arch()呼叫setup_machine_fdt()尋找適合的DT(比對DT root底下的"compatible" property。
compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";
上面的例子定義了"ti,omap3-beagleboard-xm",也宣稱相容"OMAP 3450 SOC"與"OMAP3"系列的SoC,你會注意到這樣的宣稱會從最具體的board到SoC的家族,關於compatible的值必須進行記錄說明其含義。
runtime configuration
一般來說,DT是firmware傳遞資料給kernel的唯一方法,PowerPC呼叫of_scan_flat_dt(early_init_dt_scan_root, NULL)執行early init,ARM則是呼叫mdesc = setup_machine_fdt(__atags_pointer)device population
在early configuration之後,kernel會用 unflatten_device_tree()將DT轉成device node tree,讓之後的init_early(), init_irq() and init_machine()等等使用,init_early()用於任何需要在啟動過程中儘早執行的設置,init_irq()用於設置中斷處理,而init_machine()負責建立Linux platform device,這裡主要呼叫of_platform_populate()建構platform device。之後的driver也是透過of_platform_populate()建構platform device。
i2c_add_driver( ) @ i2c.h
|-> i2c_register_driver() @i2c-core.c /* 將device_driver中的bus_type設成i2c_bus_type */
|--> driver_register() @driver.c
|--> bus_add_driver() @bus.c /* 建立sysfs file node 與 attr */
|--> driver_attach() @dd.c
|--> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach) @bus.c
|--> __driver_attach @dd.c
|--> driver_match_device(drv, dev) @base.h
|--> i2c_device_match() @i2c-core.c
/***********************************************
如果是device tree, 會透過 of_driver_match_device()去做匹配的動作
如果不是device tree就改用 i2c_match_id()去完成匹配的動作
***************************************************/
/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
return 1;
/* Then ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
driver = to_i2c_driver(drv);
/* match on an id table if there is one */
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
|--> driver_probe_device() @dd.c
/*如果匹配成功, 接下來就要準備 call driver 中的 probe function*/
|--> really_probe() @dd.c
|--> i2c_device_probe() @i2c-core.c
|--> rt5627_i2c_probe() @rt5627.c
from http://janbarry0914.blogspot.com/2014/08/device-tree-i2c-device-driver-match.html
-
參考資料:
- "Documentation/devicetree/usage-model.txt", The Linux usage model for device tree data
- 在device tree的架構下, i2c device 與 driver 是如何 match
標籤:
Linux - kernel
2018年4月21日 星期六
A pattern for state machine II - SM framework
我將A pattern for state machine改寫成framework形式,使用者需要先使用sm_alloc()分配一個struct sm,再使用sm_fp_reg()將每個state的callback function掛上,最後有event要執行時,只要呼叫sm_run(sm, new_event)即可。
state的callback function的撰寫邏輯,大致與之前一樣,return下一個state,進入下一個state要做的動作,我都用do_state_x()包起來,而do_state_x()會return 該state。
sm.h
#ifndef SM_H #define SM_H struct sm { int cur_state; int prv_event; void *v; }; /** * state function * @return next state */ typedef int (*sm_st_fp)(struct sm *sm, int new_event); struct sm *sm_alloc(int num_of_state); int sm_run(struct sm *s, int new_event); int sm_fp_reg(struct sm *s, int state, sm_st_fp fp); #endif
sm.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "sm.h" struct _sm { struct sm s; int num_of_st; sm_st_fp fp[0]; }; struct sm *sm_alloc(int num_of_state) { struct _sm *_s; int sz; sz = sizeof(struct _sm) + sizeof(sm_st_fp) * num_of_state; _s = (struct _sm*) malloc(sz); if (!_s) { return NULL; } memset(_s, 0, sz); _s->num_of_st = num_of_state; return (struct sm*)_s; } int sm_run(struct sm *s, int new_event) { struct _sm *_s = (struct _sm*) s; if (s->cur_state > _s->num_of_st) { printf("out of st\n"); return -1; } if (!_s->fp[s->cur_state]) { printf("null fp\n"); return -1; } s->cur_state = _s->fp[s->cur_state](s, new_event); s->prv_event = new_event; return 0; } int sm_fp_reg(struct sm *s, int state, sm_st_fp fp) { struct _sm *_s = (struct _sm*) s; if (state > _s->num_of_st) { printf("out of st\n"); return -1; } _s->fp[state] = fp; return 0; }
main.c
因為是framework,所以,我把state/event都拉出來, 因此每個State Machine都應該定義自己的event與state。 enum state { STATE_1, STATE_2, STATE_3, STATE_4, }; enum event { E1 = 1, E2, E3, E4, }; int main(int argc, char *argv[]) { struct sm *s; char ch; s = sm_alloc(3); if (!s) { return -1; } sm_fp_reg(s, STATE_1, in_state_1); sm_fp_reg(s, STATE_2, in_state_2); sm_fp_reg(s, STATE_3, in_state_3); sm_fp_reg(s, STATE_4, in_state_4); while (1) { while (((ch = getc(stdin)) == '\n') || (ch < '0') || (ch > '4')); sm_run(s, ch - '0'); } return 0; }
refine callback function
因為是framework,所以,callback function的定義要改成return int。 int do_s1(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_1; } int do_s2(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_2; } int do_s3(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_3; } int do_s4(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_4; } int in_state_1(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E1: printf("change to S2\n"); return do_s2(); case E2: printf("change to S3\n"); return do_s3(); default: printf("keep the same STATE && do nothing\n"); return STATE_1; } } int in_state_2(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E3: printf("change to S3\n"); return do_s3(); default: printf("keep the same STATE && do s2 again\n"); return do_s2(); // do s2 again } } int in_state_3(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E2: printf("change to S4\n"); return do_s4(); default: printf("keep the same STATE && do nothing\n"); return STATE_3; } } int in_state_4(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E1: printf("change to S2\n"); return do_s2(); case E3: printf("change to S1\n"); return do_s1(); default: printf("keep the same STATE && do again\n"); return do_s4(); } }
2018年4月15日 星期日
赫茲伯格的雙因素激勵理論 - 筆記
雙因素理論(Two Factor Theory)又叫激勵保健理論(Motivator-Hygiene Theory),是美國的行為科學家弗雷德里克·赫茨伯格(Fredrick Herzberg)提出來的。
赫茨伯格著手研究哪些事情使人們在工作中快樂和滿足,哪些事情造成不愉快和不滿足。結果他發現,使員工感到滿意的都是屬於工作本身或工作內容方面的;使員工感到不滿的,都是屬於工作環境或工作關係方面的。他把前者叫做激勵因素,後者叫做保健因素。
那些能帶來積極態度、滿意和激勵作用的因素就叫做“激勵因素”,這是那些能滿足個人自我實現需要的因素,包括:具挑戰性的工作、自主權、嘉獎和升遷。
根據赫茨伯格的理論,在調動員工積極性方面,可以分別採用以下兩種基本做法:
(一)直接滿足
直接滿足,又稱為工作任務以內的滿足。它是一個人通過工作所獲得的滿足,這種滿足是通過工作本身和工作過程中人與人的關係得到的。它能使員工學習到新的知識和技能,產生興趣和熱情,使員工具有光榮感、責任心和成就感。
(二)間接滿足
間接滿足,又稱為工作任務以外的滿足。這種滿足不是從工作本身獲得的,而是在工作以後獲得的。例如晉升、授銜、嘉獎或物質報酬和福利等,就都是在工作之後獲得的。在使用這種激勵因素時,必須與個人的工作績效掛鉤。否則一味的“吃大鍋飯”,久而久之,獎金就會變成保健因素,再多也起不了激勵作用。
2018年4月7日 星期六
note for "The Art of Readable Code" - CH9 Variables and Readability
減少不必要的變數可以增加閱讀性, 比如
root_message.last_view_time = datetime.datetime.now() 會比下面code更容易理解 now = datetime.datetime.now() root_message.last_view_time = now
下面還有幾個需要優化的的例子, 可以好好思考如何改善.
boolean done = false;
while (/* condition */ && !done) {
...
if (...) {
done = true;
continue;
}
}
與
var remove_one = function (array, value_to_remove) {
var index_to_remove = null;
for (var i = 0; i < array.length; i += 1) {
if (array[i] === value_to_remove) {
index_to_remove = i;
break;
}
}
if (index_to_remove !== null) {
array.splice(index_to_remove, 1);
}
};
programmer都知道要盡量限縮變數的範圍, 因為可視範圍小, 要記住的變數數量也會減少, 也且可以避免global/local variable用錯的窘境.
submitted = false; // Note: global variable
var submit_form = function (form_name) {
if (submitted) {
return; // don't double-submit the form
}
...
submitted = true;
};
可以被修改成
var submit_form = (function () {
var submitted = false; // Note: can only be accessed by the function below
return function (form_name) {
if (submitted) {
return; // don't double-submit the form
}
...
submitted = true;
};
}());
-
參考資料:
- The Art of Readable Code
Table Of Content for tag "The Art of Readable Code"
這是一本好書, 建議每個programmer都應該買來翻一翻
- CH1, Code Should Be Easy to Understand
- CH2, Pack information into your names
- CH3, Names That Can’t Be Misconstrued
- CH4, Aesthetics
- CH5, Knowing What to Comment
- CH6, Making Comments Precise and Compact
- CH7, Making Control Flow Easy to Read
- CH8, Breaking Down Giant Expressions
- CH9, Variables and Readability
- CH10, Extracting Unrelated Subproblems
- CH11, One Task at a Time
- CH12 Turning Thoughts into Code
- CH13 Writing Less Code
2018年3月31日 星期六
An Sample Code for notification-chain
這個pattern設計是根據kernel的notification chain做一些修改, 主要應用於眾多subscriber註冊於某個有興趣的event ID, 會根據註冊時的權重由大到小串成link-list, 當publisher執行blocking_notif_call(event_id, int val, void *v)時, 就會依序call這些subscriber註冊的callback function, 達到通知的效果.
notification-chain.h
#ifndef NOTIFICATION_CHAIN_H #define NOTIFICATION_CHAIN_H enum notif_id { /* 新的ID請加在這裡 */ notif_id_network, notif_id_lte, notif_id_max /* must be last */ }; int notif_init(void); typedef int (*notif_call_fp)(char const * caller, unsigned long val, void *v); int _notif_reg(enum notif_id nid, notif_call_fp notif_call, char *notif_call_name, int priority); #define notif_reg(nid, notif_call, priority) _notif_reg(nid, notif_call, #notif_call, priority); int notif_unreg(enum notif_id nid, notif_call_fp notif_call); char * notif_dump(char *buf, int sz); /* call in the caller thread */ int _blocking_notif_call(enum notif_id nid, unsigned long val, /* Value passed to notifier function */ void *v, /* Pointer passed to notifier function */ char const * caller); #define blocking_notif_call(nid, val, v) _blocking_notif_call(nid, val, v, __FUNCTION__) /* call by another thread */ int async_notif_call(enum notif_id nid, unsigned long val /* Value passed to notifier function */, void *v /* Pointer passed to notifier function */, void (*free_v)(void *v)); #endif
notification-chain.c
#include <pthread.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <ctype.h> #include <time.h> #include <sys/time.h> #include <sys/timerfd.h> #include <stdint.h> #include <unistd.h> #include <pthread.h> #include "notification-chain.h" struct notif_block { notif_call_fp notif_call; char *notif_call_name; struct notif_block *next; int priority; int called; }; struct notif_chain_head { pthread_mutex_t mutex; pthread_cond_t cond; struct notif_block *next; }; struct notif_statistical { unsigned int alloc; unsigned int alloced; unsigned int freed; }; struct notif_statistical notif_statistical = {}; static struct notif_chain_head *_notif_chain_tab = NULL; static int _init_notif_chain(struct notif_chain_head **h) { int i; *h = (struct notif_chain_head *) malloc(sizeof(struct notif_chain_head) * notif_id_max); if (!*h) { return -1; } for (i = 0; i < notif_id_max; i++) { pthread_mutex_init(&((*h)[i].mutex), NULL); pthread_cond_init(&((*h)[i].cond), NULL); (*h)[i].next = NULL; } return 0; } int notif_init(void) { int ret = 0; if ((ret = _init_notif_chain(&_notif_chain_tab)) < 0) { return ret; } return ret; } static int _notif_check_parms(enum notif_id nid, notif_call_fp notif_call, char *notif_call_name) { if (!_notif_chain_tab) { return -1; } if ((nid < 0) || (nid >= notif_id_max)) { return -1; } if (!notif_call) { return -1; } if (!notif_call_name) { return -1; } return 0; } static int _notif_block_alloc(struct notif_block **n) { notif_statistical.alloc++; *n = (struct notif_block*) malloc(sizeof(struct notif_block)); if (!(*n)) { return -1; } memset(*n, 0, sizeof(struct notif_block)); notif_statistical.alloced++; return 0; } static int _notif_block_free(struct notif_block *n) { notif_statistical.freed++; if (n->notif_call_name) { free(n->notif_call_name); } if (n) { free(n); } return 0; } int _notif_reg(enum notif_id nid, notif_call_fp notif_call, char *notif_call_name, int priority) { struct notif_block **n, *nb; if (_notif_check_parms(nid, notif_call, notif_call_name) < 0) { return -1; } if (_notif_block_alloc(&nb) < 0) { return -1; } /* fill info */ nb->notif_call = notif_call; nb->notif_call_name = strdup(notif_call_name); if (!nb->notif_call_name) { _notif_block_free(nb); return -1; } nb->priority = priority; /* insert into tab */ pthread_mutex_lock(&(_notif_chain_tab[nid].mutex)); n = &(_notif_chain_tab[nid].next); while ((*n) && ((*n)->priority > nb->priority)) { n = &((*n)->next); } nb->next = *n; *n = nb; pthread_mutex_unlock(&(_notif_chain_tab[nid].mutex)); return 0; } int notif_unreg(enum notif_id nid, notif_call_fp notif_call) { struct notif_block **n, *sn = NULL; if (_notif_check_parms(nid, notif_call, (void *) 0xFF /* ignore check */) < 0) { return -1; } pthread_mutex_lock(&(_notif_chain_tab[nid].mutex)); n = &(_notif_chain_tab[nid].next); while ((*n)) { if ((*n)->notif_call == notif_call) { sn = *n; *n = (*n)->next; break; } n = &((*n)->next); } pthread_mutex_unlock(&(_notif_chain_tab[nid].mutex)); if (!sn) { // not found return -1; } _notif_block_free(sn); return 0; } /* call in the caller thread */ int _blocking_notif_call(enum notif_id nid, unsigned long val, /* Value passed to notifier function */ void *v, /* Pointer passed to notifier function */ char const * caller) { struct notif_block *n; if (_notif_check_parms(nid, (void*) 0xFF /* just ignore check */, (void *) 0xFF /* just ignore check */) < 0) { return -1; } /* insert into tab */ pthread_mutex_lock(&(_notif_chain_tab[nid].mutex)); n = _notif_chain_tab[nid].next; while (n) { n->notif_call(caller, val, v); n->called++; n = n->next; } pthread_mutex_unlock(&(_notif_chain_tab[nid].mutex)); return 0; } char * notif_dump(char *buf, int sz) { int i; char *p = buf; struct notif_block *n; memset(buf, 0, sz); p += snprintf(p, sz - (buf - p), "\tnotif_fp/notif_fp_name/pri called\n"); for (i = 0; i < notif_id_max; i++) { pthread_mutex_lock(&(_notif_chain_tab[i].mutex)); n = _notif_chain_tab[i].next; p += snprintf(p, sz - (buf - p), "notif id: %d\n", i); while (n) { p += snprintf(p, sz - (buf - p), "\t%p/%s/%d %d\n", n->notif_call, n->notif_call_name, n->priority, n->called); n = n->next; } pthread_mutex_unlock(&(_notif_chain_tab[i].mutex)); } return buf; }
main.c
#include <stdio.h> #include <unistd.h> #include "notification-chain.h" /* 這裡有用service-reg作為publisher */ #include "service-reg.h" #define LINK_DOWN 0 #define LINK_UP 1 void *publisher(void *v) { int *link_state = (int *) v; ++(*link_state); (*link_state) %= 2; blocking_notif_call(notif_id_network, *link_state, NULL); } int link_notif_call1(char const *caller, unsigned long val, void *v) { printf("%s(#%d): caller:%s, %s\n", __FUNCTION__, __LINE__, caller, val == LINK_UP ? "UP" : "DOWN"); return 0; } int link_notif_call2(char const *caller, unsigned long val, void *v) { printf("%s(#%d): caller:%s, %s\n", __FUNCTION__, __LINE__, caller, val == LINK_UP ? "UP" : "DOWN"); return 0; } int link_notif_call3(char const *caller, unsigned long val, void *v) { printf("%s(#%d): caller:%s, %s\n", __FUNCTION__, __LINE__, caller, val == LINK_UP ? "UP" : "DOWN"); return 0; } int main(int argc, char *argv[]) { int link_state = 0; char buf[1024]; /* 請先call notif_init()做初始化 */ notif_init(); srv_reg("publisher", publisher, &link_state); srv_start_periodical("publisher", 1, 0); sleep(2); printf("reg 1, 10\n"); notif_reg(notif_id_network, link_notif_call1, 10); sleep(2); printf("dump\n"); printf("%s\n", notif_dump(buf, sizeof(buf))); sleep(2); printf("reg 3, 30\n"); notif_reg(notif_id_network, link_notif_call3, 30); sleep(2); printf("reg 2, 20\n"); notif_reg(notif_id_network, link_notif_call2, 20); sleep(2); printf("dump\n"); printf("%s\n", notif_dump(buf, sizeof(buf))); sleep(2); printf("unreg 3\n"); notif_unreg(notif_id_network, link_notif_call3); sleep(2); printf("dump\n"); printf("%s\n", notif_dump(buf, sizeof(buf))); sleep(2); printf("unreg 1 lte \n"); notif_unreg(notif_id_lte, link_notif_call1); sleep(2); printf("dump\n"); printf("%s\n", notif_dump(buf, sizeof(buf))); return 0; }
result
brook@vista:~/notification-chain$ ./demo
reg 1, 10
link_notif_call1(#20): caller:publisher, UP
link_notif_call1(#20): caller:publisher, DOWN
dump
notif_fp/notif_fp_name/pri called
notif id: 0
0x400fa4/link_notif_call1/10 2
notif id: 1
link_notif_call1(#20): caller:publisher, UP
link_notif_call1(#20): caller:publisher, DOWN
reg 3, 30
link_notif_call3(#34): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call3(#34): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
reg 2, 20
link_notif_call3(#34): caller:publisher, UP
link_notif_call2(#27): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call3(#34): caller:publisher, DOWN
link_notif_call2(#27): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
dump
notif_fp/notif_fp_name/pri called
notif id: 0
0x401046/link_notif_call3/30 4
0x400ff5/link_notif_call2/20 2
0x400fa4/link_notif_call1/10 8
notif id: 1
link_notif_call3(#34): caller:publisher, UP
link_notif_call2(#27): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call3(#34): caller:publisher, DOWN
link_notif_call2(#27): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
unreg 3
link_notif_call2(#27): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call2(#27): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
dump
notif_fp/notif_fp_name/pri called
notif id: 0
0x400ff5/link_notif_call2/20 6
0x400fa4/link_notif_call1/10 12
notif id: 1
link_notif_call2(#27): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call2(#27): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
unreg 1 lte
link_notif_call2(#27): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call2(#27): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
dump
notif_fp/notif_fp_name/pri called
notif id: 0
0x400ff5/link_notif_call2/20 10
0x400fa4/link_notif_call1/10 16
notif id: 1
note for "The Art of Readable Code" - CH8 Breaking Down Giant Expressions
Explaining Variables
coding主要的主軸是readable, 其餘都是次要的, 而利用額外的變數, 來解釋某個較小的表示式, 就被稱為"explaining variable". 比如
username = line.split(':')[0].strip() if username == "root":
會比下面這行容易理解
if line.split(':')[0].strip() == "root":
上面的username就被稱為"explaining variable"
Summary Variables
利用額外的變數, 來解釋某個表示式, 稱為"Summary Variables", 比如
final boolean user_owns_document = (request.user.id == document.owner_id);
if (user_owns_document) {
// user can edit this document...
}
這裡的user_owns_document就被稱為Summary Variables, 當然你也可以不斷的使用(request.user.id == document.owner_id)
Using De Morgan’s Laws
1) not (a or b or c) ⇔ (not a) and (not b) and (not c)2) not (a and b and c) ⇔ (not a) or (not b) or (not c)
我們可以多利用Morgan’s Laws簡化一些判斷式, 當然一切還是以readable為前提, 比如
if (!file_exists || is_protected) Error("Sorry, could not read file.");
會比下面這行容易理解
if (!(file_exists && !is_protected)) Error("Sorry, could not read file.");
Finding a More Elegant Approach
有時候我們反向思考可以找到更好的
// Check if 'begin' or 'end' falls inside 'other'.
bool Range::OverlapsWith(Range other) {
return (begin >= other.begin && begin lt; other.end) ||
(end > other.begin && end lt;= other.end)
}
換個方式寫會更好閱讀
bool Range::OverlapsWith(Range other) {
if (other.end <= begin) return false; // They end before we begin
if (other.begin >= end) return false; // They begin after we end
return true; // Only possibility left: they overlap
}
Simplify Expressions
有時候我們可以用MARCO增加閱讀性, 比如
void AddStats(const Stats& add_from, Stats* add_to) {
#define ADD_FIELD(field) add_to->set_##field(add_from.field() + add_to->field())
ADD_FIELD(total_memory);
ADD_FIELD(free_memory);
ADD_FIELD(swap_memory);
ADD_FIELD(status_string);
ADD_FIELD(num_processes);
...
#undef ADD_FIELD
}
比下面這例子容易閱讀
void AddStats(const Stats& add_from, Stats* add_to) {
add_to->set_total_memory(add_from.total_memory() + add_to->total_memory());
add_to->set_free_memory(add_from.free_memory() + add_to->free_memory());
add_to->set_swap_memory(add_from.swap_memory() + add_to->swap_memory());
add_to->set_status_string(add_from.status_string() + add_to->status_string());
add_to->set_num_processes(add_from.num_processes() + add_to->num_processes());
...
}
coding主要的主軸是readable, 其餘都是次要的, 而利用額外的變數, 來解釋某表示式, 或利用MACRO更容易閱讀, 以及換個方式寫, 都是手段
-
參考資料:
- The Art of Readable Code
訂閱:
文章 (Atom)
熱門文章
-
轉自 http://www.wretch.cc/blog/redsonoma/14021073 基本概念: 1> tty(終端設備的統稱): tty一詞源於Teletypes,或者teletypewriters,原來指的是電傳打字機,是通過串行線用打印機鍵盤通過閱...
-
Work queue提供一個interface,讓使用者輕易的建立kernel thread並且將work綁在這個kernel thread上面,如下圖[1]所示。 由於work queue是建立一個kernel thread來執行,所以是在process context...
-
(V)將介紹file operations中的ioctl。ioctl的prototype為: int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); ...
-
System Call在HW和user space提供一層抽象層,主要目的有: 為user space提供硬體抽象層。比如,讀取檔案時,不用管檔案所在的媒體類型與檔案儲存類型。 System call能確保系統的安全與穩定。避免user space的無意或惡意的破壞。 ...
-
這兩天電腦的word忽然都不能存檔,即便是另存新檔也不行,最後都只能放棄修改檔案,即便重新安裝過或者更新成2007也都不能存檔,最後就乖乖的google一下,原來是暫存的資料夾不存在,按照以下方式就可以解決了。 資料來源: word 2003不能存檔問題 編輯機碼的(reg...
-
在kernel中建立thread可以使用kthread_create(),建立一個task,然後在調用wake_up_process(task)讓task真正的運行,如果要kill一個kthread可以使用kthread_stop()。 在kernel中,將kthread_cr...
-
Linux module練習手札I紀錄如何撰寫一個簡單的module,並且編輯它,以及load和unload一個module。 write a module #include <linux/init.h> #include <linux/module.h...
-
幾乎任何使用 TCP,UDP或UNIX-domain socket的動作都可以用nc來達成,常見的功能如。 simple TCP proxies shell-script based HTTP clients and servers network daemon testi...
-
很多人心中都有過一個問題 What is the difference between Platform driver and normal device driver? ,簡單的來說Platform devices就non-discoverable,也就是device本身沒辦法...
-
組成元件 要能正確顯示資料,必須包含資料倉儲(Store),資料欄位的定義(ColumnModel)。 首先我們先定義資料欄位: var cm = new Ext.grid.ColumnModel({ {header: 'Name', dataIndex...



