Dualshock4 R2/L3 문제 해결을 위한 분해 수리

언제 가격이 내리나 했던 메탈기어 솔리드 5가 그라운드 제로/펜텀패인 합본(definitive experience)으로 더 싼가격에 출시 된 걸 보고는 얼른 사버렸다. 영화 같은 긴 인트로가 지나고 나서 경비병을 처치하는 장면에 들어갔는데 R2 트리거가 전혀 먹질 않았다!

다른 게임에서는 문제가 없는데 이 게임에서만 그런걸 보고 처음에는 설정의 문제이거나 버그라고 생각했었다. 인터넷을 조금 더 찾아보니 메탈기어 솔리드는 R2입력을 디지털로 눌렀다/떨어졌다가 아닌 0~1.0 사이의 아날로그 값으로 인식한다는 설명이 있었는데, 만약 특정한 손상이 있어서 격발로 인식해야 하는 값이 제대로 전달되지 못하고 있는 문제라면 다른 게임에서는 되고 메탈기어 솔리드 5에서는 안되는 문제가 설명 될 수도 있을것 같다는 생각이 들었다. 게다가 데스티니에서 L3로 달리기(sprint)를 하면 자꾸 풀려버리는 문제도 있었기에 여러모로 컨트롤러에 문제가 있지 않나 의심할 만 했다.

가격이 문제인데 PS4 pro와 함께 새로운 버전의 Dualshock 4가 출시되었지만 여전히 예전 버전도 6만원대 초반에 판매되고 있어서 지금 막 게임을 지르고 난 상태에서는 선뜻 사기가 망설여졌다. 여러 수리기들을 읽다가 “분해 조립 후 마법처럼 고쳐졌다”는 글을 읽고 나서는 점점 6만원을 세이브 할 수 있을 수도 있지 않을까 하는 근거없는 희망이 생기기 시작하더니, WD-40은 ‘접점 부활제’로 전기적 특성을 회복 시키는 기능이 있다는 글을 읽고 나서는 드디어 주저함이 없어졌다. 다행히 결과는 성공적 이어서 그나마 되던 게임도 못하게 되는 참극은 벌어지지 않았다. lol

분해 수리를 통해 고쳐진 문제는 두가지 이다.

  1. 메탈기어 솔리드 5에서 R2 트리거가 동작하지 않는 문제
  2. 데스티니에서 L3 sprint 도중 멈추는 문제

분해/조립 과정은 설명하는 인터넷 문서나 동영상이 많으니 이것을 참조 하면 된다. 나는 IFIXIT에 올려진 글을 참고 했다.

dualshock_repair

찍어둔 사진이 없어 IFIXIT의 사진으로 설명하면, 위 사진의 초록색 네모 부분은 고무재질로 된 부분은 R1/L1 버튼을 빼면 떼어 낼 수 있다. 이 부분이 닳거나 해서 인식에 문제가 생긴다는 이야기가 있어서 떼어낸 후 접점 부위에 면봉으로 WD40을 발라주고 L측과 R측을 서로 교체했다. 타이어 마냥…

주황색 네모 부분은 스틱을 잡아 당기면 빠지고 그 아래에 L3/R3 버튼이 보이는데, 여기에 WD40을 분사한 후 잘 스며 들도록 여러번 눌러주었다.

“조립은 분해의 역순”

약간 조심해야 할 부분이 있긴 하지만, 그리 어렵지 않으니 같은 문제를 겪으시는 분이 있으시다면 마법의 액체 WD40의 도움을 받아 보시길.

Android Studio에서 Googletest 사용을 위한 설정

Android Studio는 내 PC에서 좀 느리긴 하지만, 다른 IDE들에 비해서는 Emacs key binding이 비교적 잘되어 있어서 만족 하면서 조금씩 배워가고 있다. NDK로 JNI에서 불러다 쓸 native code를 구현하다 보니 Googletest를 사용하기 위해 매번 device로 push 하고 실행하는 과정이 꽤나 번거로와서 script로 만들어 보았다. 이 글에서는 Android Studio에서 Googletest를 사용하기 위한 기본적인 설정과 device에 push하는 과정을 편하게 해주는 script에 대해 설명한다.

환경

Bash script를 사용할 것이므로 Linux 환경이나 Cygwin이 설치되어 있어야 한다. 사실 여기의 내용은 Windows + Cygwin에서 시험되었으나 Bash가 동작하는 환경이라면 특별히 문제는 없을 것이다.

Googletest

Google의 C++ testing framework인 Googletest는 Googletest GitHub에서도 받아서 사용할 수 있으나, NDK package안에도 들어 있다. 여기서는 NDK안의 다음 경로에 있는 Googletest를 사용하기로 한다. Native test case들을 작성할 공간을 app/src/main/jni 아래에 ‘tests’라는 이름으로 만들고 이곳으로 gogoletest를 복사해 온다.

$>mkdir ./app/src/main/jni/tests
$>cp -r $ANDROID_NDK_PATH/sources/third_party/googletest ./app/src/main/jni/tests/

Android.mk

기존에 사용하던 native용 Android.mk file에 Googletest를 사용하기 위한 추가 수정을 해준다.

#
# 1. 시험할 기능을 포함하는 라이브러리
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := 라이브러리_이름
LOCAL_SRC_FILES := 소스파일들

include $(BUILD_SHARED_LIBRARY)


#
# 2. Googletest static library
#
# Google test static library
include $(CLEAR_VARS)
GTEST_PATH := tests/googletest

LOCAL_MODULE := googletest_main
LOCAL_CFLAGS := -Ijni/tests/googletest/include -Ijni/tests/googletest/

LOCAL_SRC_FILES := \
    $(GTEST_PATH)/src/gtest-all.cc

include $(BUILD_STATIC_LIBRARY)


#
# 3. 작성된 test case 실행파일
#
include $(CLEAR_VARS)

LOCAL_MODULE := testcases
LOCAL_CFLAGS := -Ijni/tests/googletest/include -Ijni

LOCAL_SRC_FILES := \
    tests/Test_Main.cpp \
    tests/테스트케이스_소스파일들

LOCAL_SHARED_LIBRARIES := 라이브러리_이름
LOCAL_STATIC_LIBRARIES := googletest_main
include $(BUILD_EXECUTABLE)

위에서 첫 번째 항목 “라이브러리_이름“은 시험 대상이 되는 code를 포함하는 shared library file이고 두 번째 항목은 Googletest의 기능을 static library로 컴파일 하는 과정이다. 사실 googletest 디렉토리 안에는 이것 외에도 많은 소스파일들이 들어 있는데, 시험해 본 바로는 gtest-all.cc만으로도 동작에 문제가 없는것 같다.

이제 마지막으로 테스트 케이스들과 이 테스트 케이스들을 호출하는 Test_Main.cpp를 작성하고, 이 때 필요한 “라이브러리_이름”과 googletest_mian static 라이브러리를 링크시켜준다.

Test_Main.cpp는 예제에 있는것을 그대로 사용했는데 내용은 다음과 같다.

#include <stdio.h>

#include "gtest/gtest.h"

GTEST_API_ int main(int argc, char **argv) {
  printf("Running main() from gtest_main.cc\n");
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Gooletest에서 사용하는 테스트 케이스를 작성하는 방법들은 여러 곳에서 찾을 수 있으므로 여기에서는 설명하지 않는다.

runtest.sh

이제 빌드를 수행하면 동적 라이브러리인 lib라이브러리_이름.sotestcases 파일이 만들어진다. 이것을 시험하려면 디바이스에 push한 다음 library 경로를 설정해주고 실행시켜서 결과를 봐야 하는데, 매번 시험할 때마다 이 과정을 반복하기는 매우 귀찮다. 여러개의 so file로 나눠서 작성한 경우라면 더욱 그렇다.

그래서 이 귀찮은 과정을 bash로 작성해 두고 Android Studio의 External Tools 기능을 이용해서 부를 수 있도록 설정한다. (단축키 까지 달아 두면 훨씬 편하겠지?)

우선, 귀찮은 일을 해주는 bash script는 다음과 같다. 실행파일 이름과 함께 사용할 라이브러리 파일의 목록을 인자로 받아서 디바이스에 push하고 라이브러리 path를 잡아서 실행시킨다.

#!/bin/bash
#
# This script pushes specified gtest related files into devices'
# /cache/xxx directory and runs it.
#

if [ "$#" -eq 0 ]; then
    echo "USAGE: ${0} exe_to_push [libs_to_push...]"
    exit 1
fi

exe=$1
exedir=$exe
libs=$@

# A directory at the device where binaries to be pushed.
remote_dest_dir=/cache/${exedir}

# A directory at local where binaries exist.
local_src_dir=app/src/main/libs/armeabi-v7a

adb wait-for-device
adb shell rm -rf ${remote_dest_dir}
adb shell mkdir ${remote_dest_dir}

# Push libraries.
for lib in ${libs}
do
    adb push ${local_src_dir}/${lib} ${remote_dest_dir}
done

# Push the executable then run.
adb push ${local_src_dir}/${exe} ${remote_dest_dir}
adb shell chmod 755 ${remote_dest_dir}/${exe}
adb shell "LD_LIBRARY_PATH=${remote_dest_dir} ${remote_dest_dir}/${exe}"

이제 Android Studio의 File -> Settings -> Tools -> External Tools 메뉴에 runtest.sh를 등록하자.

androidstudio_edittool

Program은 script를 수행 시켜줄 bash.exe의 위치를 지정해주고, Parameters로 실행할 script인 runtest.sh와  실행파일인 testcases 그리고 관련된 라이브러리 목록을 적어준다. 여기서는 lib라이브러_이름.so에만 의존한다고 가정했다.

그리고 마지막으로 Working directory는 project의 최상위 디렉토리를 의미하는 $ProjectFileDir$을 적어 준다.

수행결과

지정한 단축키 혹은 위의 설정대로 라면 Tools -> Android -> Run native test를 실행시키면 다음과 같이 test case들이 실행되고 결과가 출력된다.

androidstudio_runtest_result

MinnowboardMAX에 Yocto 올려본 내용 정리

Yocto는 embedded 환경에 Linux를 편리하게 적용하기위한 목적의 프로젝트로 보다 자세한 내용은 project home page인 https://www.yoctoproject.org에서 확인할 수 있다. 이 글에서는 Intel Baytrail을 사용하는 MinnowboardMAX에  Yocto linux를 올리는 과정을 설명한다.

환경설정

  • Ubuntu 14.04 (64bit)
    sudo apt-get install gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat libsdl1.2-dev xterm
  • 64bit firmware가 설치된 MinnowBoardMax: Firmware update에 대한 자세한 내용은 MinnowboardMax에 대한 Intel의 문서를 참조.
  • Yocto build system (poky)와 Intel corei64 BSP
    :2016년 현재의 최종 stable release인 Jethro branch를 받는다.
    • Poky build system
      git clone -b jethro git://git.yoctoproject.org/poky.git 
    • Intel core-i7 64 BSP
      git://git.yoctoproject.org/meta-intel -b jethro

Build

Poky는 build system이고 meta-intel은 Intel core-i7 64를 위한 BSP이다. Poky에서 meta-intel BSP를 build할 수 있도록 약간의 수정이 필요 하다. bblayers.conf file에 meta-intel BSP를 build에 포함하도록 BBLAYERS에 추가하고, local.conf file에는 MACHINE을 intel-corei7-64로 설정해 준다.

$> cd poky
poky$> source oe-init-build-env
build$> echo "BBLAYERS += \"$HOME/Yocto/meta-intel\"" >> conf/bblayers.conf
build$> echo "MACHINE = \"intel-corei7-64\"" >> conf/local.conf
build$> bitbake core-image-sato
yocto_sato_running

Flashing

Build가 완료되면 build/tmp/deploy/images/intel-corei7-64/core-image-minimal-intel-corei7-64.hddimg에 image가 만들어지는데 이것을 Yocto에서 지원하는 mkefidisk.shscript 를 이용해서 USB drive 혹은 SDcard에 flash한다.

sudo $HOME/Yocto/poky/scripts/contrib/mkefidisk.sh /dev/sdb tmp/deploy/images/intel-corei7-64/core-image-minimal-intel-corei7-64.hddimg /dev/sda

이 예제에서 사용된 /dev/sdb는 build machine에 연결된 USB drive의 경로로 device 연결 후 dmesg 혹은 mount command로 확인할 수 있고 가장 마지막에 있는 /dev/sda는 target device에서의 경로라고 하는데 명확한 내용을 찾기 힘들어서 그냥 /dev/sda로 설정했더니 별 문제는 없었다.  😉

Booting-up

Flashing한 USB drive를 연결한 상태에서 booting을 완료하면 UEFI shell로 진입하는데 다음의 command로 Yocto를 실행시킬 수 있다.

Shell> fs0:
Shell> bootx64

Build 환경에 대한 정보표시

현재의 layer들 보기

$> bitbake-layers show-layers
layer path priority
==========================================================================
meta /home/XXX/Yocto/poky/meta 5
meta-yocto /home/XXX/Yocto/poky/meta-yocto 5
meta-yocto-bsp /home/XXX/Yocto/poky/meta-yocto-bsp 5
meta-intel /home/XXX/Yocto/meta-intel 5

Overlay된 recipe들 보기

$> bitbake-layers show-overlayed
Parsing recipes..done.
=== Overlayed recipes ===
xf86-input-evdev:
meta 2:2.8.2
meta-intel 2:2.6.0
xf86-input-synaptics:
meta 2:1.7.3
meta 2:0.15.2+gitAUTOINC+934bc0012f
meta-intel 2:1.6.3
xserver-xorg:
meta 2:1.15.0
meta-intel 1:1.9.3

적용된 BB appends 보기

$> bitbake-layers show-appends
Parsing recipes..done.
=== Appended recipes ===
alsa-state.bb:
/home/XXX/Yocto/poky/meta-yocto-bsp/recipes-bsp/alsa-state/alsa-state.bbappend
formfactor_0.0.bb:
/home/XXX/Yocto/poky/meta-yocto-bsp/recipes-bsp/formfactor/formfactor_0.0.bbappend
linux-yocto_3.14.bb:
/home/XXX/Yocto/poky/meta-yocto-bsp/recipes-kernel/linux/linux-yocto_3.14.bbappend
/home/XXX/Yocto/meta-intel/common/recipes-kernel/linux/linux-yocto_3.14.bbappend
linux-yocto-rt_3.14.bb:
/home/XXX/Yocto/meta-intel/common/recipes-kernel/linux/linux-yocto-rt_3.14.bbappend
packagegroup-core-tools-profile.bb:
/home/XXX/Yocto/poky/meta-yocto-bsp/recipes-core/packagegroups/packagegroup-core-tools-profile.bbappend
psplash_git.bb:
/home/XXX/Yocto/poky/meta-yocto/recipes-core/psplash/psplash_git.bbappend
xserver-xf86-config_0.1.bb:
/home/XXX/Yocto/poky/meta-yocto-bsp/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend
linux-yocto_3.10.bb (skipped):
/home/XXX/Yocto/poky/meta-yocto-bsp/recipes-kernel/linux/linux-yocto_3.10.bbappend
uclibc_git.bb (skipped):
/home/XXX/Yocto/poky/meta-yocto-bsp/recipes-core/uclibc/uclibc_git.bbappend
linux-yocto-dev.bb (skipped):
/home/XXX/Yocto/meta-intel/common/recipes-kernel/linux/linux-yocto-dev.bbappend
linux-yocto_3.4.bb (skipped):
/home/XXX/Yocto/poky/meta-yocto-bsp/recipes-kernel/linux/linux-yocto_3.4.bbappen

Trouble shooting

“ERROR: No recipes available for:”

예전 버전의 Yocto (daisy)에서 kernel version과 다른 recipe가 포함되어 있는 경우 이와 같은 오류를 내면서 build를 멈추는 경우가 있다. 사용하지 않는 버전의 bbappend file을 삭제하고 재시도 해본다. 예를들어 Daisy version에서는 kernel version 3.14가 사용되는데, 3.10에 대한 bbappend file이 있으면 이런 문제가 생긴다. 이 떄는 다음과 같이 3.10에 해당하는 file들을 삭제한다.

$> rm yocto_i7_64/meta-intel/common/recipes-kernel/linux/linux-yocto_3.10.bbappend yocto_i7_64/meta-intel/common/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend

“ERROR: Fetcher failure: Unable to find revision XXX in branch YYY even from upstream”

Git fetching에 실패하는 경우인데, git에 관련한 설정이 올바르게 되어 있는 경우에도 이 문제가 생기고 있는것이라면 사용중인 BSP와 Poky의 version이 맞는지 다시한번 확인해 보자. Poky build system과 BSP의 version이 맞지 않는 경우에 특정 commit ID를 찾지 못해서 이러한 문제가 생기기도 한다.

...
ERROR: Function failed: Fetcher failure for URL: 'git://git.yoctoproject.org/yocto-kernel-cache;type=kmeta;name=meta;branch=yocto-3.14;destsuffix=kernel-meta'. Unable to fetch URL from any source.
ERROR: Logfile of failure stored in: /home/XXX/Yocto/poky-jethro-14.0.0/build/tmp/work/corei7-64-intel-common-poky-linux/linux-yocto/3.14.4+gitAUTOINC+62f236c734_cb22733185-r0/temp/log.do_fetch.3006
NOTE: recipe linux-yocto-3.14.4+gitAUTOINC+62f236c734_cb22733185-r0: task do_fetch: Failed
ERROR: Task 48 (/home/XXX/Yocto/poky-jethro-14.0.0/meta/recipes-kernel/linux/linux-yocto_3.14.bb, do_fetch) failed with exit code '1'
...

References