ODROID-C1 Ubuntu에서 Raspberry Pi에서 사용되는 WiringPi를 사용할 수 있도록 porting 하였습니다.
http://odroid.com/dokuwiki/doku.php?id=en:c1_tinkering
wiringPi를 사용한 example-led 예제를 Android 에서도 사용할 수 있도록 작업을 해 보았습니다.
먼저 소스를 다운 받습니다.
git clone https://github.com/codewalkerster/example-led
다운 받은 소스를 eclipse에서 import 시킵니다.
그리고 NDK를 이용하여 wiringPi를 build합니다.
$ cd example-led/jni
$ ndk-build
Android NDK: WARNING: APP_PLATFORM android-16 is larger than android:minSdkVersion 7 in /media/codewalker/92fc070a-3bc1-43e0-af27-03d08ba9dd3e/home/codewalker/workspace/xxxx/example-led/AndroidManifest.xml
[armeabi] Compile thumb : wiringPi <= wiringPi.c
/media/codewalker/92fc070a-3bc1-43e0-af27-03d08ba9dd3e/home/codewalker/workspace/xxxx/example-led/jni/wiringPi/wiringPi.c:147:0: warning: "PAGE_SIZE" redefined [enabled by default]
#define PAGE_SIZE (4*1024)
^
In file included from /home/codewalker/projects/android-ndk-r10d/platforms/android-21/arch-arm/usr/include/signal.h:34:0,
from /home/codewalker/projects/android-ndk-r10d/platforms/android-21/arch-arm/usr/include/poll.h:34,
from /media/codewalker/92fc070a-3bc1-43e0-af27-03d08ba9dd3e/home/codewalker/workspace/xxxx/example-led/jni/wiringPi/wiringPi.c:59:
/home/codewalker/projects/android-ndk-r10d/platforms/android-21/arch-arm/usr/include/limits.h:119:0: note: this is the location of the previous definition
#define PAGE_SIZE 4096
^
/media/codewalker/92fc070a-3bc1-43e0-af27-03d08ba9dd3e/home/codewalker/workspace/xxxx/example-led/jni/wiringPi/wiringPi.c: In function 'interruptHandler':
/media/codewalker/92fc070a-3bc1-43e0-af27-03d08ba9dd3e/home/codewalker/workspace/xxxx/example-led/jni/wiringPi/wiringPi.c:1865:7: warning: return makes pointer from integer without a cast [enabled by default]
return wiringPiFailure (WPI_FATAL, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ;
^
[armeabi] Compile thumb : wiringPi <= wiringShift.c
[armeabi] Compile thumb : wiringPi <= piHiPri.c
[armeabi] Compile thumb : wiringPi <= piThread.c
[armeabi] Compile thumb : wiringPi <= wiringPiSPI.c
[armeabi] Compile thumb : wiringPi <= wiringPiI2C.c
[armeabi] Compile thumb : wiringPi <= softPwm.c
[armeabi] Compile thumb : wiringPi <= softTone.c
[armeabi] Compile thumb : wiringPi <= mcp23008.c
[armeabi] Compile thumb : wiringPi <= mcp23016.c
[armeabi] Compile thumb : wiringPi <= mcp23017.c
[armeabi] Compile thumb : wiringPi <= mcp23s08.c
[armeabi] Compile thumb : wiringPi <= mcp23s17.c
[armeabi] Compile thumb : wiringPi <= sr595.c
[armeabi] Compile thumb : wiringPi <= pcf8574.c
[armeabi] Compile thumb : wiringPi <= pcf8591.c
[armeabi] Compile thumb : wiringPi <= mcp3002.c
[armeabi] Compile thumb : wiringPi <= mcp3004.c
[armeabi] Compile thumb : wiringPi <= mcp4802.c
[armeabi] Compile thumb : wiringPi <= mcp3422.c
[armeabi] Compile thumb : wiringPi <= max31855.c
[armeabi] Compile thumb : wiringPi <= max5322.c
[armeabi] Compile thumb : wiringPi <= sn3218.c
[armeabi] SharedLibrary : libwiringPi.so
[armeabi] Install : libwiringPi.so => libs/armeabi/libwiringPi.so
[armeabi] Compile thumb : wiringPiDev <= ds1302.c
[armeabi] Compile thumb : wiringPiDev <= maxdetect.c
[armeabi] Compile thumb : wiringPiDev <= piNes.c
[armeabi] Compile thumb : wiringPiDev <= gertboard.c
[armeabi] Compile thumb : wiringPiDev <= piFace.c
[armeabi] Compile thumb : wiringPiDev <= lcd128x64.c
[armeabi] Compile thumb : wiringPiDev <= lcd.c
[armeabi] Compile thumb : wiringPiDev <= piGlow.c
[armeabi] SharedLibrary : libwiringPiDev.so
[armeabi] Install : libwiringPiDev.so => libs/armeabi/libwiringPiDev.so
[armeabi] Compile thumb : wpi_android <= wpi_android.c
[armeabi] SharedLibrary : libwpi_android.so
[armeabi] Install : libwpi_android.so => libs/armeabi/libwpi_android.so
jni/Android.mk 에 libwingPi.so와 libwingPiDev.so 빌드하도록 추가 하였습니다.
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += \
$(NDK_PATH)/platforms/android-21/arch-arm/usr/include \
$(LOCAL_PATH)/wiringPi
LOCAL_MODULE := wiringPi
LOCAL_SRC_FILES := \
wiringPi/wiringPi.c \
wiringPi/wiringShift.c \
wiringPi/piHiPri.c \
wiringPi/piThread.c \
wiringPi/wiringPiSPI.c \
wiringPi/wiringPiI2C.c \
wiringPi/softPwm.c \
wiringPi/softTone.c \
wiringPi/mcp23008.c \
wiringPi/mcp23016.c \
wiringPi/mcp23017.c \
wiringPi/mcp23s08.c \
wiringPi/mcp23s17.c \
wiringPi/sr595.c \
wiringPi/pcf8574.c \
wiringPi/pcf8591.c \
wiringPi/mcp3002.c \
wiringPi/mcp3004.c \
wiringPi/mcp4802.c \
wiringPi/mcp3422.c \
wiringPi/max31855.c \
wiringPi/max5322.c \
wiringPi/sn3218.c
LOCAL_CFLAGS += -UNDEBUG -DANDROID
LOCAL_LDLIBS := -ldl -llog
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += \
$(NDK_PATH)/platforms/android-21/arch-arm/usr/include \
$(LOCAL_PATH)/wiringPi
LOCAL_MODULE := wiringPiDev
LOCAL_SRC_FILES := \
devLib/ds1302.c \
devLib/maxdetect.c \
devLib/piNes.c \
devLib/gertboard.c \
devLib/piFace.c \
devLib/lcd128x64.c \
devLib/lcd.c \
devLib/piGlow.c
LOCAL_SHARED_LIBRARIES := libwiringPi
LOCAL_CFLAGS += -UNDEBUG
include $(BUILD_SHARED_LIBRARY)
그리고 wirinPi에서 사용해야 하는 function을 jni 형식으로 만듭니다.
jint Java_com_hardkernel_wiringpi_MainActivity_analogRead(JNIEnv* env, jobject obj, jint port) {
return analogRead(port);
}
void Java_com_hardkernel_wiringpi_MainActivity_digitalWrite(JNIEnv* env, jobject obj, jint port, jint onoff) {
digitalWrite(port, onoff);
}
int Java_com_hardkernel_wiringpi_MainActivity_wiringPiSetupSys(JNIEnv* env, jobject obj) {
wiringPiSetupSys();
return 0;
}
사용한 GPIO를 선언합니다.
private final int ledPorts[] = {
97, // GPIOX.BIT0(#97)
108, // GPIOX.BIT11(#108)
100, // GPIOX.BIT3(#100)
101, // GPIOX.BIT4(#101)
105, // GPIOX.BIT8(#105)
106, // GPIOX.BIT9(#106)
107, // GPIOX.BIT10(#107)
115, // GPIOX.BIT18(#115)
116, // GPIOX.BIT19(#116)
88, // GPIOY.BIT8(#88)
83, // GPIOY.BIT3(#83)
87, // GPIOY.BIT7(#87)
104, // GPIOX.BIT7(#104)
102, // GPIOX.BIT5(#102)
103, // GPIOX.BIT6(#103)
117, // GPIOX.BIT20(#117)
99, // GPIOX.BIT2(#99)
118, // GPIOX.BIT21(#118)
98, // GPIOX.BIT1(#98)
};
MainActivity에 jni function들을 선언합니다.
public native int wiringPiSetupSys();
public native int analogRead(int port);
public native void digitalWrite(int port, int onoff);
static {
System.loadLibrary("wpi_android");
}
/sys/class/gpio/export를 이용하여 GPIO sysfs 노드를 만듭니다.
sysfs 방식은 pinMode()를 사용할 수 없기 때문에 direction에 out으로 설정 합니다.
그리고 value, direction의 접근 권한을 바꿉니다.
boolean exportGPIO() {
try {
DataOutputStream os = new DataOutputStream(mProcess.getOutputStream());
for (int port: ledPorts) {
os.writeBytes("echo " + port + " > /sys/class/gpio/export\n");
os.writeBytes("chmod 666 /sys/class/gpio/gpio" + port + "/direction\n");
os.writeBytes("echo out > /sys/class/gpio/gpio" + port + "/direction\n");
os.writeBytes("chmod 666 /sys/class/gpio/gpio" + port + "/value\n");
}
os.flush();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return false;
}
return true;
}
wiringPi의 "/dev/mem"을 open 하여 mmap을 사용하는 방식으로 만들려고 하였으니 "/dev/mem"은 root가 아니면 접근을 제한하도록 되어 있어서 불가능합니다.
jni의 library에는 root 권한을 줄 방법이 없습니다.
그래서 wiringPiSetupSys()를 호출 하여 wiringPi library를 초기화 합니다.
주기적으로 update()를 호출 하도록 만들고 UI와 LED를 control 합니다.
public void update() {
int i = 0;
int adcValue = 0;
int ledPos = 0;
if ((adcValue = analogRead (PORT_ADC1)) > 0) {
ledPos = (adcValue * ledPorts.length * 1000) / 1024;
ledPos = (ledPorts.length - (ledPos / 1000));
mADC.setProgress(adcValue);
} else
ledPos = 0;
for (i = 0; i < ledPorts.length; i++) {
digitalWrite (ledPorts[i], 0);
mLeds.get(i).setChecked(false);
}
for (i = 0; i < ledPos; i++) {
digitalWrite (ledPorts[i], 1);
mLeds.get(i).setChecked(true);
}
if (!mStop)
handler.postDelayed(runnable, 100);
}