DM368 사용하기 에서 달라진 부분을 중심으로 개발환경 구축 방법에 대해 설명한다.
설명하는 순서대로 따라하기만 해도, 원하는 개발 환경 구축이 가능할 것이다.

개발 디렉토리 만들기

가장 먼저 작업할 메인 디렉토리를 생성한다. 여기서는 /home/wjkim 아래에 svn-wifi 라는 디렉토리를 만들고 앞으로 모든 개발을 여기서 할 것이다.

#cd /home/wjkim
#mkdir svn-wifi

환경 파일 복사하기

여기서 환경 파일이라함은 빌드에 필요한 유틸리티 또는 펌웨어 이미지 생성 시 필요한 UBL 바이너리 파일등을 의미한다. 이 파일들을 손수 복사해주는 이유는 svn 에 커밋되어 있지 않기 때문이며, 실제 이 파일들은 차후에 따로 빌드할 필요가 없다.
다시 말해, 바이너리 파일만 사용한다.

#cp ubl_486arm_360ddr_ipnc_dm368.bin /home/wjkim/svn-wifi/
#cp template_for_rdk41.tar /home/wjkim/svn-wifi/
#tar xf template_for_rdk41.tar

코드 받아오기

이제 실제로 개발할 코드를 svn 서버로부터 받아와야 한다.

가장 먼저 부트로더와 커널을 체크아웃 한다.

#cd /home/wjkim/svn-wifi/template_for_rdk41/Source/dvsdk_ipnctools/ipnc_psp_03_21_00_04
#./svn.sh

앞서 실행한 스크립트 파일(.sh)을 보면, 각각 부트로더와 커널을 체크아웃하는 명령어를 담고있다.

#ls
svn.sh  ti-davinci  u-boot

체크아웃이 완료되면, 부트로더(u-boot)와 커널(ti-davinci) 디렉토리가 보인다. 받아온 코드를 가지고 빌드해 볼 차례다.

아래와 같이 빌드한다.

#cd /home/wjkim/svn-wifi/template_for_rdk41/Source/dvsdk_ipnctools/ipnc_psp_03_21_00_04/u-boot
#make davinci_dm368_ipnc_config
#make

에러없이 빌드되었으면, u-boot-1.3.4-dm368_ipnc.bin 파일이 생성된다.

#cd /home/wjkim/svn-wifi/template_for_rdk41/Source/dvsdk_ipnctools/ipnc_psp_03_21_00_04/ti-davinci
#sh ./build.sh
Sselect Target Model. 
  1)nmd2003p                2)ipxp_hub                 3)nmd2003p-wifi
  4)nmd2003p_drv_copy       5)ipxp_hub_drv_copy        6)menuconfig
  7)Not Clean Build         8)Module Build             9)Reserved

커널 빌드를 위한 스크립트(.sh) 파일이 있다. 총 9 가지 메뉴가 있는데, 여기서 주로 사용할 것은 1번과 8번이다.
1번은 커널을 빌드하여, uImage 파일을 생성하는 것이고, 8번은 커널 모듈을 따로 빌드하여 생성된 ko 파일을 복사하는 역할을 한다.

앞서 빌드 스크립트에서 1번을 선택하면, 원래 지정된 커널 설정 파일(arch/arm/config 아래의 itx_dm368_ipnc_defconfig 파일)을 참조하여 빌드한다.
만일 커널 옵션을 수정해야 한다면, 아래의 명령을 이용해서 옵션을 조정한 후, 기존 설정 파일에 overwrite 하면 된다.

#make -j4 CROSS_COMPILE=/home/sungho/opt/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le- ARCH=arm menuconfig

Wi-Fi 관련 커널 옵션은 'M', 측 모듈로 설정되기 때문에, 별도로 빌드를 해주어야 한다. 위 빌드 스크립트에서 8번을 선택하면, 아래처럼 ko 파일을 복사할 경로를 입력받는다.

Sselect Target Model. 
  1)nmd2003p                2)ipxp_hub                 3)nmd2003p-wifi
  4)nmd2003p_drv_copy       5)ipxp_hub_drv_copy        6)menuconfig
  7)Not Clean Build         8)Module Build             9)Reserved
8
Input A Module Path Copied
// 여기에 ko 파일을 복사할 파일시스템 경로를 적어준다
#svn co http://192.168.200.250/svn/cam/dm36x/rdk4_1/wifi_driver ./

WiFi 개발에 필요한 드라이버 및 applicant(wpa_supplicant, hostapd)가 포함되어 있다.

파일시스템 준비하기

파일시스템은 svn 서버로 부터 익스포트(절대 체크아웃이 아니다!)한다. 경로는 /home/wjkim/s1_filesys/filesys_wifi 로 하겠다.

#mkdir -p /home/wjkim/s1_filesys/filesys_wifi
#cd /home/wjkim/s1_filesys/filesys_wifi
#svn export http://192.168.200.250/svn/cam/dm36x/filesys/rdk4_1_nocompression
#cd  rdk4_1_nocompression
#tar xzf dev.tar.gz

이후 개발 도중 수정된 파일을 커밋하기 위해서는 파일 시스템을 다른 디렉토리에다가 체크아웃한 뒤, 그곳에서 커밋을 해야 한다. 그 이유는 앞선 파일시스템을 가져올 때, 익스포트를 했기 때문이다.

빌드를 위한 환경 파일 수정

이제 빌드시 참조하는 환경 파일들을 수정할 차례다.

BASE_HOME := /home/$(shell whoami)/svn-wifi
IPNC_INSTALL_DIR := $(BASE_HOME)/template_for_rdk41/Source
DVSDK_INSTALL_DIR := $(BASE_HOME)/template_for_rdk41/Source
HOME := $(BASE_HOME)/template_for_rdk41/Source/ipnc_rdk
...
FILESYS_BASE_DIR  := /home/wjkim/s1_filesys/filesys_wifi
...
TARGET_FS   := $(FILESYS_BASE_DIR)/rdk4_1_nocompression
FILES_NAME=/home/wjkim/s1_filesys/filesys_wifi/rdk4_1_nocompression
UBL_FILE=/home/wjkim/svn-wifi/ubl_486arm_360ddr_ipnc_dm368.bin
KERNEL_FILE=/home/wjkim/svn-wifi/template_for_rdk41/Source/dvsdk_ipnctools/ipnc_psp_03_21_00_04/ti-davinci/arch/arm/boot/uImage
...
#sudo find $FILES_NAME -name .svn -print0 | xargs -0 rm -rf       // 주석 처리
find $FILES_NAME -name .svn -print0 | xargs -0 rm -rf                   // 추가
...
mkdir ./build/$FW_VERSION
sync
 
cp $FW_UBOOT /tftpboot/wjkim/                  // 추가 
mv $FW_UBOOT ./build/$FW_VERSION/

Wi-Fi 드라이버 빌드

[WiFi Bring up 하기] 문서를 참조한다.

빌드하기

#cd /home/wjkim/svn-wifi/template_for_rdk41/Source/ipnc_rdk
#make hostall
#make wwwall
#make avall

위의 make wwwall 을 빌드하면, 필요없는 파일들이 파일시스템으로 복사된다. 이를 삭제해주지 않으면, 나중에 이미지 파일 크기가 60 MB 가 넘어버려 제대로 부팅이 안될 수 있다.

$cd /home/wjkim/s1_filesys/filesys_wifi/rdk4_1_nocompression/var/www
$rm -rf *cbc*

이제 이미지를 만들어보자!

$make image

주요 소스코드 경로

/usr/local/data-cam/nf_sysdb_net.conf                # 네트워크 정보(SSID, PASSWORD, 인증방식등) 저장
/home/sungho/opt/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-
/home/wjkim/bcm/0503/src_0419-real-final.tar
/home/wjkim/bcm/wps-0508/falcon_rel_5_90_188_59_0507-real-final.tar.gz

기능 검증하기

다음과 같은 스크립트를 사용하여, WIFI 기능에 대한 동작 검증을 할 수 있다.

#!/bin/sh
number=0
 
while [ $number -lt 2 ]
do
 
echo "$number try!!"
echo "w-wpa itx-test111 88888888"
./w-wpa itx-test111 88888888
 
echo "sleep 20"
sleep 20
 
while [ true ]
do
echo "udhcpc -i eth1 &"
udhcpc -i eth1 &
echo "sleep 30"
sleep 30
 
if ifconfig -a eth1 | grep 192; then
        echo "success dhcp!!!!!!!!!!!!!!!!!!!!!!!"
        break
else
        echo "fail dhcp??????????????????????"
        echo "killall udhcpc"
        killall udhcpc
        echo "sleep 5"
        sleep 5
fi
done
 
echo "disconn"
./disconn
echo "ifconfig eth1 0.0.0.0 up"
ifconfig eth1 0.0.0.0 up
echo "killall udhcpc"
killall udhcpc
number=`expr $number + 1`
done
echo "TEST FINISH!!"

위의 내용을 작성하여 /srv/wifi/bcm/supplicant 아래의 auto_test.sh 라는 파일을 만들고, 실행한다. 총 500번 동안 접속 후 IP 할당 기능에 대한 테스트를 진행한다.

FAQ

Application 이 죽으면, 몇 초 후에 시스템이 재부팅되는데, 이는 Watchdog 때문이다. 오류 상황이 재현되었을 때, 확인하기 위해서는 재부팅되는 것을 막아야 한다.
ipnc_rdk/nmd_host/Makefile 파일을 아래 처럼 수정하고, 재빌드하면 된다.

#DEFINE_FLAG += -DUSE_WDOG          // 주석처리

'https://192.168.0.4:8082' 와 같이 https 프로토콜과 포트번호 8082 로 접속한다.

nmd_host 와 같은 application 이 죽을 때, 아래와 같은 메세제를 출력한다.

Got signal 11 [SIGSEGV]
[bt] Execution path:
[bt] [ 1] [0x0003e4f0] ./nmd_host [0x3e4f0]
[bt] [ 2] [0x00000000] [(nil)]
[bt] [ 3] [0x00000000] [(nil)]
[bt] [ 4] [0x00000000] [(nil)]
[bt] [ 5] [0x00000000] [(nil)]
[bt] [ 6] [0x00000000] [(nil)]
[bt] [ 7] [0x00000000] [(nil)]
[bt] [ 8] [0x00000000] [(nil)]
[bt] [ 9] [0x00000000] [(nil)]
Got signal 11 [SIGSEGV]
[bt] Execution path:
[bt] [ 1] [0x0003e4f0] ./nmd_host [0x3e4f0]
[bt] [ 2] [0x00000000] [(nil)]
[bt] [ 3] [0x00000000] [(nil)]
[bt] [ 4] [0x00000000] [(nil)]
[bt] [ 5] [0x00000000] [(nil)]
[bt] [ 6] [0x00000000] [(nil)]
[bt] [ 7] [0x00000000] [(nil)]
[bt] [ 8] [0x00000000] [(nil)]
[bt] [ 9] [0x00000000] [(nil)]
[bt] [10] [0x00000000] [(nil)]
[bt] [11] [0x00000000] [(nil)]
[bt] [12] [0x00000000] [(nil)]
[bt] [13] [0x00000000] [(nil)]
[bt] [14] [0x00000000] [(nil)]
[bt] [15] [0x00000000] [(nil)]
[bt] Execution path:
[bt] [10] [0x00000000] [(nil)]
[bt] [11] [0x00000000] [(nil)]
[bt] [12] [0x00000000] [(nil)]
[bt] [13] [0x00000000] [(nil)]
[bt] [14] [0x00000000] [(nil)]
[bt] [15] [0x00000000] [(nil)]
[bt] Execution path:

에러 메세지만 봐서는 어떤 루틴에서 발생한 것인지 알 수 없다. 힌트는 메모리 주소값인 0x3e4f0 이다. 그렇다면, 이 메모리 주소가 어디 부분에 해당될까?

이를 확인하기 위해서는 빌드할 때, 생성되는 심볼테이블을 참조해야 한다. 하지만, 대부분의 경우, 바이너리 파일의 용량을 줄이기 위해 strip 한다. 따라서 strip 하기 전에 파일이 필요하다.
strip 은 빌드과정에서 자동 실행하게 되는데, 이 부분을 주석처리하면, 심볼테이블이 포함된 실행파일을 얻을 수 있다.
nmd_host/Makefile 파일의 다음 부분을 수정한다.

all: $(TARGET)
 
#$(TARGET): $(OBJS) $(NF_SVR_OBJS) $(NF_SYS_OBJS) 
#baek.modify.onvif.start
#$(TARGET): $(OBJS) $(IPCAM_COMMON_OBJS) $(IPCAM_SYS_OBJS) $(IPCAM_SVR_OBJS) $(IPCAM_STREAM_OBJS) $(IPCAM_FILECTR_OBJS)
$(TARGET): $(OBJS) $(IPCAM_COMMON_OBJS) $(IPCAM_SYS_OBJS) $(IPCAM_SVR_OBJS) $(IPCAM_STREAM_OBJS) $(IPCAM_FILECTR_OBJS) $(IPCAM_EXT_SVR_OBJS) $(BIZ_SMS_OBJS)
#baek.modify.onvif.end
    @echo "    LD  $@ $^ $(LIBS)"
    @$(CC) $(FLAGS) $(LINK_FLAG) -o $@ $^ $(LIBS)
    @echo "    STRIP $@"
#   @$(STRIP) $@                                        // 주석 처리
    @echo "    CP  $(TARGET) $(DEST_DIR)"
    @cp -f ./$(TARGET) $(DEST_DIR)
 
.c.o:
    @echo "    CC  $@ $<"
    @$(CC) $(FLAGS) $(INCLUDE) $(INCLUDE_FLAG) $(DEFINE_FLAG) -c -o $@ $<

다시 빌드하여 확인해보자!

#file nmd_host 
nmd_host: ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/Linux 2.6.18, dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped

다음과 같이 실행하여 해당 주소가 어디인지 확인할 수 있다.

#/home/sungho/opt/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-addr2line -f -e ./nmd_host 3e4f0
WIFI_GetStatus
crtstuff.c:0

해당 주소의 위치는 WIFI_GetStatus 함수이고, 파일 이름은 crtstuff.c 인데, 실제 검색해보면, crtstuff.c 란 파일은 없다. 이제 중요한 것은 해당 함수를 찾아 디버깅하면 된다.
혹은 전체 심볼테이블도 볼수 있는데, 다음과 같이 실행한다.

#/home/sungho/opt/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le-nm ./nmd_host

위의 주소를 입력하여 가장 근접한 함수를 찾으면 된다.

통신 도중 RX/TX Error 가 발생하면, 강제로 재부팅하도록 수정한다.

#include <linux/reboot.h> 
...
emergency_restart();

위의 함수를 추가하면 된다.

이슈 히스토리

문제의 원인은 비교적 WiFi 바쁘게(busy) 동작할 때, tx 또는 rx 라인쪽에 H/W(노이즈 등) 문제로 인해 driver 가 down 되는 문제가 발생한다.
이러한 상황에서는 target 에서 wifi chip 쪽으로 ioctl 명령을 내려보내지 못한다. 지금까지 밝혀진 이 문제를 완화시키는 방법은 다음과 같다.

  1. SDIO Clock 조정 (50 → 10MHz)
  2. 주기적 스캔 주기 조정 (30 → 100 초)
  3. –Application 에 죽지않도록 WIFI API 실행 전에 체크하기(wlarm ver)–
  4. 드라이버에서 TX/RX Error 발생 시 재부팅하도록 수정

시스템을 재부팅하지 않고, 이슈를 해결할 수 있는 방안을 찾고 있다. S/W 수준에서 마지막 수단인 rmmod/insmod 조차 안되는 경우가 있음(WIFI 정상 동작 중에 rmmod/insmod 를 반복하여 aging 함).
이슈가 발생했을 때, rmmod 를 실행하는 쉘 스크립트를 실행하도록 수정하여 테스트 하였지만, aging 테스트 중 커널 패닉 발생함. 아무래도 자신이 자기자신을 rmmod 한다는 점과 시스템 전반적으로 clear 하게 rmmod 가 되지 않아 반복시 문제가 발생하는 것으로 보임.
코이네 측에서는 S/W 적으로 할 수 있는 것은 리부팅이라고 함. 이슈에 대한 원인을 파악하기 위해서는 H/W 테스트가 필요함.
지금까지의 결론 : 문제의 원인을 수정하지 않은 상황에서 이를 완벽하게 처리할 수는 없음. 설사 S/W 만으로 복구가 된다고 하더라도, 그 상태가 안정한지 보장할 수 없음. 보안장비의 특성을 고려한다면, 재부팅이 가장 현실적인 방법이다.

어쨋든 위 이슈에 대해 재부팅 하지 않고, 해결하는 방법은 100% rmmod/insmod 가 된다는 가정하에서만 가능하다. 여러가지로 방법을 고민하던 중에 위 이슈가 발생했을 때, WIFI 드라이버 스스로 rmmod 를 할 수 있는 방법을 찾아봤다.
자기(드라이버)가 자신(드라이버)을 rmmod 한다는 것 자체가 완전하지 않은 방법이다. 실제 이후 에이징 테스트를 돌린 결과, 도중에 커널 패닉이 발생하는 등 문제가 발생했다.

드라이버에 아래의 코드를 추가했다.

static int umh_test( void )                 // wjkim
{
    char *argv[] = { "/srv/wifi/bcm/test.sh", "help!", NULL };                 // 배열의 첫번째 인자는 실행할 shell 파일, 두번째는 shell 실행 인자
    static char *envp[] = {"HOME=/","TERM=linux","PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };           // 실행 시 환경 변수 정의
 
 
    return call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC );
}
...
    if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT)
    {   
        umh_test();         // 에러 횟수가 정의된 값보다 크면, 위의 함수가 호출 된다
 
        return -ETIMEDOUT;
    }
...

이제 실행할 test.sh 파일을 작성할 차례다.

#!/bin/sh
 
/srv/wifi/bcm/aaa.sh &         // 여기서 또다시 다른 shell 파일을 실행하는 이유는 커널에서 test.sh 파일을 실행하는 동안에는 lock 이 되기 때문에 백그라운드(&) 실행하도록 하였다

핵심 실행 파일이라고 할 수 있는 aaa.sh 파일을 작성할 차례다.

#!/bin/sh
 
cd /srv/wifi/bcm
 
#rmmod dhd
 
./insmod.sh
 
#touch /tmp/kernel

rmmod 와 insmod 사이에 delay 를 주기 위해 insmod.sh 파일을 수정했다.

#!/bin/sh
 
rmmod dhd            // 추가
 
sleep 2                // 추가
 
insmod dhd.ko "firmware_path=bcm43362_softap.bin nvram_path=NVRAM_20130221.txt"
 
sleep 3               // 추가
 
if /srv/wifi/bcm/wlarm ver > /dev/null; then
    touch /tmp/wifi_success
    touch /tmp/status
    touch /tmp/rssi
else
    touch /tmp/wifi_fail
fi
 
ifconfig -a | grep 'eth0' | tr -s ' ' | cut -d ' ' -f5 > /tmp/eth0
 
ifconfig eth1 hw ether $(echo "$(awk -F: '{print $1}' /tmp/eth0):$(awk -F: '{print $2}' /tmp/eth0):$(awk -F: '{print $3}' /tmp/eth0):$(awk -F: '{print $4}' /tmp/eth0):$(awk -F: '{print $5}' /tmp/eth0):$(printf "%X\n" $(expr 1 + $(echo $((`echo 0x$(sed s/:/\ /g /tmp/eth0 | awk '{print $6}')`)))))")

원래는 WIFI 는 처음 인식할 때, SDIO 2.0 의 HIGH SPEED 로 동작한다. 하지만, 커널 코드에서 강제로 HIGH SPEED 가 아닌 DEFAULT SPEED 로 동작하도록 커널을 수정하였다.
결과적으로는 WIFI 는 전보다도 더 느린 클럭으로 동작하게 되는 셈이다.
drivers/mmc/core/sd.c 파일에 다음을 추가하였다.

#define WIFI_SET_HIGHSPEED_MODE     0
 
    /*  
     * Attempt to change to high-speed (if supported)
     */
 
#if WIFI_SET_HIGHSPEED_MODE
    err = mmc_sd_switch_hs(card);
    if (err > 0)
        mmc_sd_go_highspeed(card);
    else if (err)
        goto free_card;
#endif

WIFI_SET_HIGHSPEED_MODE 값을 1로 바꾸면, 기존처럼 HIGH SPEED 모드로 설정하고, 0 으로 바꾸면, DEFAULT SPEED 로 동작한다.

실제 위의 코드를 반영하여 에이징 테스트로 확인해본 결과, 기존 보다도 훨씬 문제 발생 빈도 수가 대폭 줄어들었다.

  • computer/itx/dm368_사용하기_개정판.txt
  • Last modified: 3 years ago
  • by likewind