LED DEVICE DRIVER 2

Save this PDF as:
 WORD  PNG  TXT  JPG

Size: px
Start display at page:

Download "LED DEVICE DRIVER 2"

Transcription

1 한백전자교육사업부 안드로이드기반리눅스디바이스드라이버제작 - 한백전자 -

2 LED DEVICE DRIVER 2

3 LED 디바이스드라이버핀할당 3

4 LED 디바이스드라이버 LED 드라이버를작성하기위해다음과같이프로젝트를생성 구분 Project name Toolchains Driver File Name 내용 m2_led Other tool chain m2_led 4

5 LED 디바이스드라이버소스코드 : m2_led.c 001: #include <linux/miscdevice.h> 002: #include <asm/uaccess.h> 003: #include <linux/init.h> 004: #include <linux/module.h> 005: #include <linux/kernel.h> 006: #include <linux/fs.h> 007: #include <linux/types.h> 008: #include <linux/ioport.h> 009: #include <mach/gpio.h> 010: #include <plat/gpio-cfg.h> 011: 012: #define DRIVER_AUTHOR "hanback" 013: #define DRIVER_DESC "Led program" 014: 015: #define LED_NAME "m2_led" 016: #define LED_MODULE_VERSION "LED V1.0" 017: 018: static int m2_led_open(struct inode * inode, struct file * file){ 019: int err,i; 020: 5

6 LED 디바이스드라이버소스코드 : m2_led.c 021: for (i=0; i<7; i++) 022: { 023: err = gpio_request(exynos4_gpk3(i), "Led"); 024: 025: if (err) 026: printk("led.c failed to request GPK3(%d) \n",i); 027: 028: s3c_gpio_setpull(exynos4_gpk3(i), S3C_GPIO_PULL_NONE); 029: gpio_direction_output(exynos4_gpk3(i), 0); 030: } 032: return 0; 033: } 034: 035: static int m2_led_release(struct inode * inode, struct file * file){ 036: int i; 037: for (i=0; i<7; i++) 038: gpio_free(exynos4_gpk3(i)); 039: 040: return 0; 6

7 LED 디바이스드라이버소스코드 : m2_led.c 041: } 042: 043: static ssize_t m2_led_read(struct file * file, char * buf, size_t length, loff_t * ofs){ 044: printk("m2_led_read, \n"); 045: 046: return 0; 047: } 048: 049: static ssize_t m2_led_write(struct file * file, const char * buf, size_t length, loff_t * ofs){ 050: int ret; 051: unsigned char cbuf[8]; 052: ret = copy_from_user(cbuf,buf,length); 053: 054: gpio_direction_output(exynos4_gpk3(0), (unsigned int) cbuf[0]); 055: gpio_direction_output(exynos4_gpk3(1), (unsigned int) cbuf[1]); 056: gpio_direction_output(exynos4_gpk3(2), (unsigned int) cbuf[2]); 057: gpio_direction_output(exynos4_gpk3(3), (unsigned int) cbuf[3]); 058: gpio_direction_output(exynos4_gpk3(4), (unsigned int) cbuf[4]); 059: gpio_direction_output(exynos4_gpk3(5), (unsigned int) cbuf[5]); 060: gpio_direction_output(exynos4_gpk3(6), (unsigned int) cbuf[6]); 7

8 LED 디바이스드라이버소스코드 : m2_led.c 062: return length; 063: } 064: 065: static DEFINE_MUTEX(m2_led_mutex); 066: static long m2_led_ioctl(struct inode *inode, unsigned char cmd[], size_t length, loff_t *off_what){ 067: gpio_direction_output(exynos4_gpk3(0), (unsigned int) cmd[0]); 068: gpio_direction_output(exynos4_gpk3(1), (unsigned int) cmd[1]); 069: gpio_direction_output(exynos4_gpk3(2), (unsigned int) cmd[2]); 070: gpio_direction_output(exynos4_gpk3(3), (unsigned int) cmd[3]); 071: gpio_direction_output(exynos4_gpk3(4), (unsigned int) cmd[4]); 072: gpio_direction_output(exynos4_gpk3(5), (unsigned int) cmd[5]); 073: gpio_direction_output(exynos4_gpk3(6), (unsigned int) cmd[6]); 074: 075: return 0; 076: } 077: 078: static struct file_operations m2_led_fops = { 079:.owner = THIS_MODULE, 080:.open = m2_led_open, 8

9 LED 디바이스드라이버소스코드 : m2_led.c 081:.unlocked_ioctl = m2_led_ioctl, 082:.write = m2_led_write, 083:.release = m2_led_release, 084: }; 085: 086: static struct miscdevice m2_led_driver = { 087:.fops = &m2_led_fops, 088:.name = LED_NAME, 089:.minor = MISC_DYNAMIC_MINOR, 090: }; 092: static int m2_led_init(void){ 093: printk("driver: %s DRIVER INIT\n",LED_NAME); 094: return misc_register(&m2_led_driver); 095: } 096: 097: static void m2_led_exit(void){ 098: misc_deregister(&m2_led_driver); 099: printk("driver: %s DRIVER EXIT\n",LED_NAME); 100: } 9

10 LED 디바이스드라이버소스코드 : m2_led.c 101: 102: module_init(m2_led_init); 103: module_exit(m2_led_exit); 104: 105: MODULE_AUTHOR(DRIVER_AUTHOR); 106: MODULE_DESCRIPTION(DRIVER_DESC); 107: MODULE_LICENSE("Dual BSD/GPL"); 10

11 LED 테스트코드구성 LED 테스트코드를작성하기위하여다음과같이프로젝트를생성 구분 Project name Toolchains C File Name 내용 m2_led_test Android GCC m2_led_test 11

12 LED 테스트코드소스코드 : m2_led_test.c 001: #include <stdio.h> 002: #include <stdlib.h> 003: #include <unistd.h> 004: #include <sys/types.h> 005: #include <sys/stat.h> 006: #include <fcntl.h> 007: 008: int main(int argc, char * argv[]) { 009: int dev,i; 010: char temp,buf[8]={0}; 011: unsigned char t = 0; 012: 013: if(argc <= 1) { 014: printf("please input the parameter! ex)./test 0xff\n"); 015: return -1; 016: } 017: 018: dev = open("/dev/m2_led", O_WRONLY); 019: 020: if (dev!= -1) { 12

13 LED 테스트코드소스코드 : m2_led_test.c 021: if(argv[1][0] == 0 && (argv[1][1] == x argv[1][1] == X )) 022: { 023: temp = (unsigned short)strtol(&argv[1][2],null,16); 024: } 025: else 026: { 027: temp = atoi(argv[1]); 028: } 030: for(i=0;i<7;i++) 031: { 032: t<<=1; 033: if((temp>>i) & 1) 034: buf[i] = 1; 035: } 036: } 037: else { 038: printf( "Device Open ERROR!\n"); 039: return -1; 040: } 041: 042: write(dev,buf,7); 043: close(dev); 044: 045: return 0; 046: } 13

14 LED 테스트코드실행 프로젝트를빌드하면, 실행파일은 /data/local/tmp 폴더내에복사가완료 AndroX Studio 의 Remote Shell 을실행하여 HBE-SM7-S4412 에접속하고, 아래의명령어를입력하여실행파일을실행 > cd /data/local/tmp >./m2_led_test 14

15 LED 테스트코드실행결과 다음과같이프로그램을실행하면서인자에값을입력하면 HBE- SM7-S4412 M2 모듈의 LED 가점등되는것이확인가능 0x00~0x7F 까지입력가능 0x2F 를입력하면아래와같이 LED 가점등됨 15

16 JNI 프로그래밍실습 16

17 JNI 란? Java Native Interface 다른언어로작성된프로그램을자바에서실행할수있게연결해주는인터페이스 JNI 용도 Code Reusability Performance(speed) H/W dependent Code 17

18 JNI 란? Java 환경에서의 C 사용절차 1 단계 : Native Method 를선언하는자바클래스작성 (Wrapper) 2 단계 : 자바 Main 코드작성 3 단계 : 작성한클래스컴파일 4 단계 : javah 를사용해서 Native Method 가사용할헤더파일생성 5 단계 : C 언어로 Native Method 실제구현 6 단계 : C 로구현된 Native Method 컴파일 à 공유라이브러리만들기 7 단계 : 자바프로그램실행 18

19 Greeting 예제 [ 목표 ] 리눅스환경에서 JNI 를사용하는방법및절차를이해한다. JNI C 함수이름이어떻게만들어지는지이해한다. JNI C 함수에서자동으로생성되는인자 2 개의의미를이해한다. C 공유라이브러리만드는명령어를이해한다. JNI 실습은 PC 리눅스에서진행 VMWare 설치 Ubuntu 리눅스이미지 (VMWare 용 ) 리눅스용 gcc tool-chain 리눅스용 JDK 19

20 Greeting 예제 ; 리눅스명령어모음 # cd / # mkdir working # cd working # mkdir jni # cd jni # mkdir Greeting # cd Greeting # gedit Wrapper.java # gedit Main.java # javac Wrapper.java # javac Main.java # javah Wrapper # ls // Wrapper.h 생성 # gedit greeting.c # gcc o libgreeting.so greeting.o shared I [jni.h 위치 ] I [jni_md.h] # ls // libgreeting.so 확인 # export LD_LIBRARY_PATH=. # java Main 20

21 Greeting 예제 ; Wrapper.java 001: class Wrapper { 002: // static part. 003: static { 004: System.loadLibrary("greeting"); // libgreeting.so 005: } 006: 007: // native func. declaration 008: public native void print(); 009: } 21

22 Greeting 예제 ; Main.java 001: class Main { 002: public static void main(string [] args) { 003: Wrapper wrapper = new Wrapper(); 004: wrapper.print(); 005: } 006: } 007: 22

23 Greeting 예제 ; greeting.c 001: #include <stdio.h> 002: #include "Wrapper.h" 003: 004: JNIEXPORT void JNICALL Java_Wrapper_print(JNIEnv *env, jobject obj) 005: { 006: printf("hello, JNI!!!\n"); 007: } 008: 23

24 Greeting 예제 ; 코드설명 Wrapper.java static 블록 + native 메소드선언 System.loadLibrary() 메소드를사용하여라이브러리를로드함 라이브러리이름 greeting ß libgreeting.so ; 앞의 lib 와마지막.so 를뺀가운데이름! native 메소드 [ 접근지정자 ] native [ 반환형 ] [ 메소드이름 ]([ 인자 ]); ex) public native void print(); Main.java native 메소드호출 Java 에서는객체를통해서메소드호출가능! Wrapper 클래스타입입의객체를만들고 wrapper 객체를통해서 print() 메소드호출 24

25 Greeting 예제 ; 코드설명 greeting.c javah 를통해서생성된함수이름 check! Java 키워드 + 패키지 + Wrapper 클래스 + native 함수 Java_[ 패키지 ]_[Wrapper 클래스 ]_[native 함수이름 ](JNIEnv *, jobject, ); ex) Java_Wrapper_print(); // 패키지사용 X JNI 함수는인자가무조건두개추가! JNIEnv * ; JNI 에서사용되는함수 table 을가리키는함수 (*env)->xxx_function(env, ) 형식으로함수호출해서사용함 jobject ; native 함수를호출한객체 (java 언어의 this 와같음 ) 25

26 JniType 예제 [ 목표 ] Java 의함수인자전달방식과 C 언어의인자전달방식을이해한다. Java 기본타입 8 가지가 C 언어에서어떤타입으로바뀌는지이해한다. 객체지향언어의함수중복 (function-overloading) 을 C 언어에서는어떻게처리하는지이해한다. 인자전달방식 Java ; pass-by-value C ; call-by-value (; 자바와개념적으로똑같다!) cf) call-by-reference? 26

27 JniType 예제 ; Wrapper.java 001: class Wrapper { 002: static { 003: System.loadLibrary("jni_type"); //libjni_type.so 004: } 005: 006: public native void print(boolean b); 007: public native void print(char c); 008: public native void print(byte b, short s, int i, long l); 009: public native void print(float f, double d); 010: } 011: 27

28 JniType 예제 ; Main.java 001: class Wrapper { 002: static { 003: System.loadLibrary("jni_type"); //libjni_type.so 004: } 005: 006: public native void print(boolean b); 007: public native void print(char c); 008: public native void print(byte b, short s, int i, long l); 009: public native void print(float f, double d); 010: } 011: 28

29 JniType 예제 ; jni_type.c 001: #include <stdio.h> 002: #include "Wrapper.h" 003: 004: JNIEXPORT void JNICALL Java_Wrapper_print Z(JNIEnv *env, jobject obj, jboolean b) 005: { 006: printf("boolean --> unsigned char : %s\n", (b)? "true" : "false"); 007: } 008: 009: JNIEXPORT void JNICALL Java_Wrapper_print C(JNIEnv *env, jobject obj, jchar c) 010: { 011: printf("char --> unsigned short int : %c\n", (unsigned char)c); 012: } 013: 014: JNIEXPORT void JNICALL Java_Wrapper_print BSIJ(JNIEnv *env, jobject obj, 015: jbyte b, jshort s, jint i, jlong l) 016: { 017: printf("byte --> signed char : %d\n", b); 018: printf("short --> short int : %d\n", s); 019: printf("int --> int : %d\n", i); 020: printf("long --> long long int : %lld\n", l); 29

30 JniType 예제 ; jni_type.c 021: } 022: 023: JNIEXPORT void JNICALL Java_Wrapper_print FD(JNIEnv *env, jobject obj, 024: jfloat f, jdouble d) 025: { 026: printf("float --> float : %f\n", f); 027: printf("double --> double : %f\n", d); 028: } 029: 030: 031: 30

31 JniType 예제 Java Primitive Type 논리형 boolean ; true/false 상수값을가짐. 문자형 char ; java 에서는 2byte 유니코드를사용함 정수형 byte(8bit), short(16bit), int(32bit), long(64bit) 부동소수점형 float, double ; IEEE754 <jni.h>, <jni_md.h> 내용분석 Java 기본형 JNI type 실제타입 boolean jboolean unsigned char char jchar unsigned short int byte jbyte signed char short jshort short int int jint int long jlong long long int float jfloat float double jdouble double 31

32 JniType 예제 오버로딩된메소드의구별 타입시그니처 Z B C S I J F D Lfully-qualified-class; [type (arg-types) ret-type 자바타입 boolean byte char short int long float double Fully-qualified-class Type[] Method type 32

33 JniStr 예제 [ 목표 ] Java 문자열과 C 문자열의차이점을이해한다. Java 문자열과 C 문자열을변환하는함수를사용할수있다. 33

34 JniStr 예제 자바유니코드문자열 à C 언어문자열 const char *c_str = (*env)->getstringutfchars(env, j_str, 0); 가상머신에게 C 언어문자열의사용이끝남을알리고메모리에서자원을해지 (*env)->releasestringutfchars(env, j_str, c_str); C 언어문자열 à 자바유니코드문자열 jstring java_str = (*env)->newstringutf(env, c_str); 34

35 JniStr 예제 ; Wrapper.java 001: class Wrapper { 002: static { 003: System.loadLibrary("jni_str"); // libjni_str.so 004: } 005: 006: public native void print(string str); 007: public native String getstring(); 008: public native String addstring(string s1, String s2); 009: } 010: 35

36 JniStr 예제 ; Main.java 001: class Main { 002: public static void main(string [] args) { 003: Wrapper wrapper = new Wrapper(); 004: 005: wrapper.print("hello, world"); 006: String str = wrapper.getstring(); 007: System.out.println(str); 008: 009: System.out.println(wrapper.addString("Hello, ", "world")); 010: } 011: } 012: 36

37 JniStr 예제 ; jni_str.c 001: #include <stdio.h> 002: #include <stdlib.h> 003: #include <string.h> 004: #include "Wrapper.h" 005: 006: JNIEXPORT void JNICALL Java_Wrapper_print(JNIEnv *env, jobject obj, jstring str) 007: { 008: const char *pstr = (*env)->getstringutfchars(env, str, 0); 009: printf("%s\n", pstr); 010: (*env)->releasestringutfchars(env, str, pstr); 011: } 012: 013: JNIEXPORT jstring JNICALL Java_Wrapper_getString(JNIEnv *env, jobject obj) 014: { 015: return (*env)->newstringutf(env, "Wonderful world"); 016: } 017: 37

38 JniStr 예제 ; jni_str.c 018: JNIEXPORT jstring JNICALL Java_Wrapper_addString(JNIEnv *env, jobject obj, 019: jstring s1, jstring s2) 020: { 021: jstring str; 022: const char *pstr1 = (*env)->getstringutfchars(env, s1, 0); 023: const char *pstr2 = (*env)->getstringutfchars(env, s2, 0); 024: 025: char *pstr = (char *)malloc(strlen(pstr1) + strlen(pstr2) + 1); 026: strcpy(pstr, pstr1); 027: strcat(pstr, pstr2); 028: str = (*env)->newstringutf(env, pstr); 029: free(pstr); 030: (*env)->releasestringutfchars(env, s1, pstr1); 031: (*env)->releasestringutfchars(env, s2, pstr2); 032: 033: return str; 034: } 035: 38

39 JniArr 예제 [ 목표 ] Java 기본형타입의배열을 C 언어에서접근해서사용할수있다. 배열을인자로받는메소드가함수중복을사용하는경우를처리할수있다. 39

40 JniArr 예제 ; Wrapper.java 001: class Wrapper { 002: static { 003: System.loadLibrary("jni_arr"); // libjni_arr.so 004: } 005: 006: public native int sum(int [] nums); 007: public native double sum(double [] nums); 008: } 009: 40

41 JniArr 예제 ; Main.java 001: class Main { 002: public static void main(string [] args) { 003: int [] nums1 = {10, 20, 30, 40, 50}; 004: double [] nums2 = {1.0, 2.0, 3.0, 4.0, 5.0}; 005: 006: Wrapper wrapper = new Wrapper(); 007: System.out.println("int array sum : " + wrapper.sum(nums1)); 008: System.out.println("double array sum : " + wrapper.sum(nums2)); 009: } 010: } 011: 41

42 JniArr 예제 ; jni_arr.c 001: #include "Wrapper.h" 002: 003: JNIEXPORT jint JNICALL Java_Wrapper_sum 3I(JNIEnv *env, jobject obj, jintarray arr) 004: { 005: int i; 006: int sum = 0; 007: 008: int size = (*env)->getarraylength(env, arr); 009: int *parr = (*env)->getintarrayelements(env, arr, 0); 010: for (i = 0; i < size; ++i) 011: sum += parr[i]; 012: (*env)->releaseintarrayelements(env, arr, parr, 0); 013: 014: return sum; 015: } 016: 42

43 JniArr 예제 ; jni_arr.c 017: JNIEXPORT jdouble JNICALL Java_Wrapper_sum 3D(JNIEnv *env, jobject obj, jdoublearray arr) 018: { 019: int i; 020: double sum = 0.0; 021: 022: int size = (*env)->getarraylength(env, arr); 023: double *parr = (*env)->getdoublearrayelements(env, arr, 0); 024: for (i = 0; i < size; ++i) 025: sum += parr[i]; 026: (*env)->releasedoublearrayelements(env, arr, parr, 0); 027: 028: return sum; 029: } 030: 43

44 JniArr 예제 ; 코드설명 배열을인자로전달 int[] à jintarray double[] à jdoublearray 배열의크기알아내기 jint arrsize = (*env)->getarraylength(env, arr); 배열로변환하기 jint *parr = (*env)->getintarrayelements(env, arr, 0); // C 언어의배열과같이 for 문으로순차접근가능 배열변환에사용된임시메모리영역해제 (*env)->releaseintarrayelements(env, arr, parr, 0); 44

45 JniArr 예제 ; 코드설명 자바타입과 JNI 타입매칭표 자바타입 Java.lang.Object Java.lang.Class Java.lang.String Java array Object [] boolean[] byte [] char [] short [] int [] long [] float [] double Java.lang.Throwable JNI 타입 jobject Jclass Jstring jarray jobjectarray jbooleanarray jbytearray jchararray JshortArray jintarray jlongarray jflortarray jdoublearray jthrowable 45

46 JniArr2 예제 [ 목표 ] 클래스타입의배열을 C 언어에서다루는방법을이해한다. 46

47 JniArr2 예제 ; Wrapper.java 001: class Wrapper { 002: static { 003: System.loadLibrary("jni_arr2"); // libjni_arr2.so 004: } 005: 006: public native void print(string [] strs); 007: } 008: 47

48 JniArr2 예제 ; Main.java 001: class Main { 002: public static void main(string [] args) { 003: String [] strs = { 004: "Just the way you are", 005: "Wonderful tonight", 006: "Uptown girl", 007: "knocking on the heaven's door" 008: }; 009: 010: Wrapper wrapper = new Wrapper(); 011: wrapper.print(strs); 012: } 013: } 014: 48

49 JniArr2 예제 ; jni_arr2.c 001: #include <stdio.h> 002: #include "Wrapper.h" 003: 004: JNIEXPORT void JNICALL Java_Wrapper_print(JNIEnv *env, jobject obj, jobjectarray arr) 005: { 006: int i; 007: int size = (*env)->getarraylength(env, arr); 008: 009: for (i = 0; i < size; ++i) 010: { 011: jstring str = (*env)->getobjectarrayelement(env, arr, i); 012: const char *pstr = (*env)->getstringutfchars(env, str, 0); 013: 014: printf("%s\n", pstr); 015: (*env)->releasestringutfchars(env, str, pstr); 016: } 017: } 018: 49

50 JniArr2 예제 ; 코드설명 String [] ; jobjectarray jobjectarray 의원소 String 값을 C 언어형식으로변환 jstring str = (jstring)(*env)->getobjectarrayelement(env, objarr, i); 50

51 JniMem 예제 [ 목표 ] 클래스멤버변수 / 멤버함수접근방법을이해한다. 51

52 JniMem 예제 ; Date.java 001: class Date { 002: private int year; 003: private int month; 004: private int day; 005: 006: public Date() { 007: // this.set(0, 0, 0); 008: this.year = this.month = this.day = 0; 009: } 010: 011: public Date(int year, int month, int day) { 012: this.set(year, month, day); 013: } 014: 015: public void set(int year, int month, int day) { 016: this.year = year; 017: this.month = month; 018: this.day = day; 019: } 020: 021: public String tostring() { 022: // (yyyy/mm/dd) 023: String str = "(" + year + "/" + month + "/" + day + ")"; 024: 025: return str; 026: } 027: } 028: 52

53 JniMem 예제 ; Wrapper.java 001: class Wrapper { 002: static { 003: System.loadLibrary("jni_mem"); // libjni_mem.so 004: } 005: 006: public native void print(date d); 007: } 008: 53

54 JniMem 예제 ; Main.java 001: class Main { 002: public static void main(string [] args) { 003: Date birthday = new Date(); 004: Date today = new Date(2013, 11, 8); 005: 006: birthday.set(2005, 8, 2); 007: 008: System.out.println("today : " + today.tostring()); 009: System.out.println("birthday : " + birthday.tostring()); 010: 011: Wrapper wrapper = new Wrapper(); 012: wrapper.print(today); 013: wrapper.print(birthday); 014: } 015: } 016: 54

55 JniMem 예제 ; jni_mem.c 001: #include <stdio.h> 002: #include "Wrapper.h" 003: 004: JNIEXPORT void JNICALL Java_Wrapper_print(JNIEnv *env, jobject obj, jobject d) 005: { 006: jclass classtype = (*env)->getobjectclass(env, d); 007: 008: jmethodid tostringid = (*env)->getmethodid(env, classtype, 009: "tostring", "()Ljava/lang/String;"); 010: 011: jstring str = (*env)->callobjectmethod(env, d, tostringid); 012: 013: const char *pstr = (*env)->getstringutfchars(env, str, 0); 014: printf("%s\n", pstr); 015: (*env)->releasestringutfchars(env, str, pstr); 016: } 017: 018: 55

56 JniMem 예제 ; jni_mem.c 019: /* 020: JNIEXPORT void JNICALL Java_Wrapper_print(JNIEnv *env, jobject obj, jobject d) 021: { 022: jclass classtype = (*env)->getobjectclass(env, d); 023: 024: jfieldid yearid = (*env)->getfieldid(env, classtype, "year", "I"); 025: jfieldid monthid = (*env)->getfieldid(env, classtype, "month", "I"); 026: jfieldid dayid = (*env)->getfieldid(env, classtype, "day", "I"); 027: 028: int year = (*env)->getintfield(env, d, yearid); 029: int month = (*env)->getintfield(env, d, monthid); 030: int day = (*env)->getintfield(env, d, dayid); 031: 032: printf("(%d/%d/%d)\n", year, month, day); 033: } 034: */ 035: 56

57 JniMem 예제 ; 코드설명 멤버접근하기 접근지정자무시! Private 멤버도접근가능! GetObjectClass() Jobject 타입의인자를받아, jclass 타입의값을반환 GetFieldID() jclass 타입의인자와, 변수명, 인자구성을인자로받아 jfieldid 값을반환 ex) jfieldid yearid = (*env)->getfieldid(env, classtype, "year", "I"); GetXXXField() XXX 위치에는멤버변수의타입을적는다. ex) int year = (*env)->getintfield(env, d, yearid); 57

58 JniMem 예제 ; 코드설명 GetObjectClass() Jobject 타입의인자를받아, jclass 타입의값을반환 GetMethodID() jclass 타입의인자와, 변수명, 시그너쳐를인자로받아 jmethodid 값을반환 시그너쳐 ; javap tool 을사용하면편리하게알수있음 ex) jmethodid tostringid = (*env)->getmethodid(env, classtype, "tostring", "()Ljava/lang/String;"); CallXXXField() XXX 위치에는메소드의반환타입을적는다. ex) jstring str = (*env)->callobjectmethod(env, d, tostringid); 58

59 JniMem2 예제 [ 목표 ] Has-a 관계의클래스멤버변수 / 멤버함수접근방법을이해한다. 59

60 JniMem2 예제 ; Member.java 001: class Date { 002: private int year; 003: private int month; 004: private int day; 005: 006: public Date() { 007: // this.set(0, 0, 0); 008: this.year = this.month = this.day = 0; 009: } 010: 011: public Date(int year, int month, int day) { 012: this.set(year, month, day); 013: } 014: 015: public void set(int year, int month, int day) { 016: this.year = year; 017: this.month = month; 018: this.day = day; 019: } 020: 021: public String tostring() { 022: // (yyyy/mm/dd) 023: String str = "(" + year + "/" + month + "/" + day + ")"; 024: 025: return str; 026: } 027: } 028: 60

61 JniMem2 예제 ; Wrapper.java 001: class Wrapper { 002: static { 003: System.loadLibrary("jni_mem"); // libjni_mem.so 004: } 005: 006: public native void print(member member); 007: } 008: 61

62 JniMem2 예제 ; Main.java 001: class Main { 002: public static void main(string [] args) { 003: Member member1 = new Member(); 004: Member member2 = new Member("john", 20, new Date(2013, 11, 8)); 005: member1.setname("jane"); 006: member1.setage(30); 007: member1.setregisterdate(new Date(2000, 1, 1)); 008: 009: System.out.println("member1 : " + member1.tostring()); 010: System.out.println("member2 : " + member2.tostring()); 011: 012: Wrapper wrapper = new Wrapper(); 013: wrapper.print(member1); 014: wrapper.print(member2); 015: } 016: } 017: 62

63 JniMem2 예제 ; jni_mem.c 001: #include "Wrapper.h" 002: 003: JNIEXPORT void JNICALL Java_Wrapper_print(JNIEnv *env, jobject obj, jobject member) 004: { 005: jclass memberclass = (*env)->getobjectclass(env, member); 006: 007: jfieldid nameid = (*env)->getfieldid(env, memberclass, "name", "Ljava/lang/String;"); 008: jfieldid ageid = (*env)->getfieldid(env, memberclass, "age", "I"); 009: jfieldid registerdateid = 010: (*env)->getfieldid(env, memberclass, "registerdate", "LDate;"); 011: 012: jstring name = (*env)->getobjectfield(env, member, nameid); 013: jint age = (*env)->getintfield(env, member, ageid); 014: jobject registerdate = (*env)->getobjectfield(env, member, registerdateid); 015: 016: jclass dateclass = (*env)->getobjectclass(env, registerdate); 017: jmethodid tostringid = 018: (*env)->getmethodid(env, dateclass, "tostring", "()Ljava/lang/String;"); 019: jstring date = (*env)->callobjectmethod(env, registerdate, tostringid); 020: 021: const char *pname = (*env)->getstringutfchars(env, name, 0); 022: const char *pdate = (*env)->getstringutfchars(env, date, 0); 023: 024: printf("(%s, %d, %s)\n", pname, age, pdate); 025: 026: (*env)->releasestringutfchars(env, name, pname); 027: (*env)->releasestringutfchars(env, date, pdate); 028: } 029: 63

64 디바이스제어안드로이드앱제작 64

65 LED 예제 LED 프로그램을작성하기위해다음과같이프로젝트를생성 65

66 LED 예제 추가적으로패키지와클래스, 폴더, 파일을생성 66

67 LED 예제 : uartjni 패키지 모든프로젝트들은동일하게추가적으로타깃과디바이스사이의데이터를주고받을수있는 Uart 통신을위한패키지와클래스, 파일을생성하야함 추가파일을생성하는방법은우선 com.hbe.uartjni 패키지의 UartJNI 클래스를등록하기위해 Package Explorer 에서오른쪽버튼을클릭한후, New > Class 를선택 67

68 LED 예제 : uartjni 패키지 + UartJNI.java 그림과같은창이생성되면, Package 에 com.hbe.uartjni 를입력하고, Name 에 UartJNI 를입력 패키지이름은반드시 com.hbe.uartjni 와동일하게입력 소스코드를참고하여 UartJNI.java 작성 68

69 LED : UartJNI.java 001: package com.hbe.uartjni; 002: 003: import android.util.log; 004: 005: public class UartJNI implements UartJNIListener { 006: 007: private boolean mconnectflag; 008: private UartJNIListener mmainactivity; 009: 010: static { 011: System.loadLibrary("UartJNI"); 012: } 013: 014: private native static int open(string path); 015: private native void close(); 016: private native void setled(char led); 017: 018: public UartJNI(){ 019: mconnectflag = false; 020: portopen(); 69

70 LED : UartJNI.java 021: } 022: 023: public void portopen(){ 024: if(mconnectflag) return; 025: 026: int ret = open("/dev/m2_led"); 027: if(ret==1){ 028: mconnectflag = true; 029: } else { 030: Log.d("sm7m2", "device connect failed"); 031: } 032: } 033: 034: public void portclose(){ 035: if(mconnectflag==false) return; 036: mconnectflag = false; 037: close(); 038: } 039: 040: protected void finalize() throws Throwable{ 70

71 LED : UartJNI.java 041: portclose(); 042: super.finalize(); 043: } 044: 046: public void onreceive(int val) { 047: if(mmainactivity!=null){ 048: mmainactivity.onreceive(val); 049: } 050: } 051: 052: public void setlistener(uartjnilistener a){ 053: mmainactivity = a; 054: } 055: 056: public void setled(int c1, int c2, int c3, int c4, int c5, int c6, int c7){ 057: char ch = (char)((c1&1)<<6 (c2&1)<<5 (c3&1)<<4 (c4&1)<<3 (c5&1)<<2 (c6&1)<<1 c7&1); 058: setled(ch); 059: } 71

72 LED : UartJNI.java 061: public void setled(int led){ 062: if(led>=7) setled(1,1,1,1,1,1,1); 063: else if(led>=6) setled(1,1,1,1,1,1,0); 064: else if(led>=5) setled(1,1,1,1,1,0,0); 065: else if(led>=4) setled(1,1,1,1,0,0,0); 066: else if(led>=3) setled(1,1,1,0,0,0,0); 067: else if(led>=2) setled(1,1,0,0,0,0,0); 068: else if(led>=1) setled(1,0,0,0,0,0,0); 069: else setled(0,0,0,0,0,0,0); 070: } 071: } 72

73 소스코드 UartJNIListener.java 001: package com.hbe.uartjni; 002: 003: public interface UartJNIListener { 004: public void onreceive(int val); 005: } 73

74 LED 예제 : Uart 통신 External Tools > JNI Interface 를선택후 Library name 은 UartJNI 를입력 74

75 LED 예제 : Uart 통신 Class path 는 com.hbe.uartjni.uartjni 를입력 Package Explorer 에다음과같이 jni 폴더와 UartJNI.c 파일이생성된것을확인. 소스코드를참고하여 Android.mk 와 UartJNI.c 파일작성 75

76 소스코드 UartJNI.c 001: #include <string.h> 002: #include <jni.h> 003: #include <stdio.h> 004: #include <stdlib.h> 005: #include <fcntl.h> 006: #include <unistd.h> 007: #include <termios.h> 008: #include <sys/mman.h> 009: #include <errno.h> 010: 011: int fd=0; 012: 013: JNIEXPORT jint JNICALL Java_com_hbe_uartjni_UartJNI_open(JNIEnv *env, jclass c, jstring path){ 014: jboolean iscopy; 015: const char *path_utf = (*env)->getstringutfchars(env, path, &iscopy); 016: fd = open(path_utf,o_wronly); 017: (*env)->releasestringutfchars(env, path, path_utf); 018: 019: if(fd<0) return 0; 020: else return 1; 76

77 소스코드 UartJNI.c 021: } 022: 023: JNIEXPORT void JNICALL Java_com_hbe_uartjni_UartJNI_close(JNIEnv *env, jobject o){ 024: close(fd); 025: } 026: 027: JNIEXPORT void JNICALL Java_com_hbe_uartjni_UartJNI_setBuzzer(JNIEnv *env, jobject o, jchar c){ 028: int i=(int)c; 029: write(fd, &i, sizeof(i)); 030: } 77

78 소스코드 Android.mk 001: # Copyright (C) 2009 The Android Open Source Project 002: # 003: # Licensed under the Apache License, Version 2.0 (the "License"); 004: # you may not use this file except in compliance with the License. 005: # You may obtain a copy of the License at 006: # 007: # 008: # 009: # Unless required by applicable law or agreed to in writing, software 010: # distributed under the License is distributed on an "AS IS" BASIS, 011: # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012: # See the License for the specific language governing permissions and 013: # limitations under the License. 014: # 015: LOCAL_PATH:= $(call my-dir) 016: 017: include $(CLEAR_VARS) 018: 019: LOCAL_MODULE := UartJNI 020: LOCAL_CFLAGS := -Werror 021: LOCAL_SRC_FILES := UartJNI.c 022: 023: include $(BUILD_SHARED_LIBRARY) 78

79 LED 예제 : Uart 공유라이브러리생성 JNI 라이브러리컴파일 우측상단의 C/C++ Perspective 를선택 Project Explorer 에서변환하고자하는프로젝트를선택하고, File > New > Convert to a C/C++ Project (Adds C/C++ Nature) 를선택 79

80 LED 예제 Uart 통신및 LED 예제클래스완성 80

81 LED 예제 : 이미지추가 이미지파일복사 앱을구성하는파일을생성했다면, 앱에포함되는이미지를복사 프로젝트에서쓰이는이미지폴더는 /res/drawable-xhdpi 폴더외의이미지폴더는모두삭제 삭제해야할폴더는다음과같음 ( 삭제하지않아도무관 ) /res/drawable-hdpi /res/drawable-ldpi /res/drawable-mdpi 폴더삭제를완료하였다면, 준비한이미지파일을프로젝트의 /res/drawable-xhdpi 폴더에복사 81

82 LED 예제 Setting Password 에불이들어왔다면, 숫자일곱자리를입력하여암호를설정 숫자하나를입력할때마다 M2 모듈의 LED 가하나씩점등 모두입력하면 Input Password 에불이들어온다. Input Password 에불이들어왔을때또다시일곱자리암호를입력 숫자하나를입력할때마다 M2 모듈의 LED 가하나씩점등 입력된일곱자리암호가 Setting Password 모드에서입력된암호와동일하다면 M2 모듈의 LED 가오른쪽부터차례대로소등 암호가틀렸다면 7 개의 LED 전체가깜빡임 암호를다시설정하고싶다면하단의 Initialize Password 를터치 82

83 소스코드 M2LEDActivity.java 001: package com.hbe.m2led; 002: 003: import com.hbe.uartjni.uartjni; 004: import android.os.bundle; 005: import android.os.handler; 006: import android.os.message; 007: import android.app.activity; 008: import android.view.menu; 009: 010: public class M2LEDActivity extends Activity { 011: 012: M2LEDView mcustomview; 013: 014: UartJNI mjnidriver; 015: int[] marrsetpw = new int[7]; 016: int[] marrinputpw = new int[7]; 017: int mpwpt = 0; 018: boolean mpwok = false; 019: boolean minputlock = false; 020: 83

84 소스코드 M2LEDActivity.java 021: private Handler mhandler = new Handler(){ 023: public void handlemessage(message msg){ 024: super.handlemessage(msg); 025: if(minputlock) return; 026: if(msg.what==' '){ 027: initpw(); 028: } else { 029: if(mpwok) inputpw(msg.what); 030: else setpw(msg.what); 031: } 032: } 033: }; 034: 036: protected void oncreate(bundle savedinstancestate) { 037: super.oncreate(savedinstancestate); 038: setcontentview(r.layout.main); 039: 040: mcustomview = (M2LEDView)findViewById(R.id.custom_view); 84

85 소스코드 M2LEDActivity.java 041: mjnidriver = new UartJNI(); 042: } 043: 045: public boolean oncreateoptionsmenu(menu menu) { 046: // Inflate the menu; this adds items to the action bar if it is present. 047: getmenuinflater().inflate(r.menu.main, menu); 048: return true; 049: } 050: 051: public void setmessage(message msg){ 052: mhandler.sendmessage(msg); 053: } 054: 056: protected void onpause() { 057: mjnidriver.portclose(); 058: super.onpause(); 059: } 85

86 소스코드 M2LEDActivity.java 062: protected void onresume() { 063: mjnidriver.portopen(); 064: super.onresume(); 065: } 066: 067: private void inputpw(int p){ 068: marrinputpw[mpwpt++]=p; 069: mjnidriver.setled(mpwpt); 070: if(mpwpt>=7){ 071: for(int i=0;i<7;i++){ 072: if(marrinputpw[i]!=marrsetpw[i]){ 073: setfailurethread(); 074: mpwpt = 0; 075: return; 076: } 077: } 078: setpassthread(); 079: mpwpt = 0; 080: } 86

87 소스코드 M2LEDActivity.java 081: } 082: 083: private void setpw(int p){ 084: marrsetpw[mpwpt++] = p; 085: mjnidriver.setled(mpwpt); 086: if(mpwpt>=7){ 087: mpwok = true; 088: mpwpt = 0; 089: mcustomview.setinputmode(); 090: } 091: } 093: private void initpw(){ 094: mpwok = false; 095: mpwpt = 0; 096: mjnidriver.setled(0); 097: mcustomview.setsettingmode(); 098: } 099: 100: private void setpassthread(){ 87

88 소스코드 M2LEDActivity.java 101: PassLED thread = new PassLED(); 102: thread.start(); 103: } 104: 105: private void setfailurethread(){ 106: FailureLED thread = new FailureLED(); 107: thread.start(); 108: } 109: 110: private class PassLED extends Thread{ 112: public void run() { 113: super.run(); 114: minputlock = true; 115: try { 116: for(int i=6;i>=0;i--){ 117: Thread.sleep(100); 118: mjnidriver.setled(i); 119: } 120: } catch (InterruptedException e) { 88

89 소스코드 M2LEDActivity.java 121: e.printstacktrace(); 122: } 123: minputlock = false; 124: } 125: } 126: 127: private class FailureLED extends Thread{ 129: public void run() { 130: super.run(); 131: minputlock = true; 132: try { 133: for(int i=0;i<=3;i++){ 134: Thread.sleep(200); 135: mjnidriver.setled(7); 136: Thread.sleep(200); 137: mjnidriver.setled(0); 138: } 139: } catch (InterruptedException e) { 140: e.printstacktrace(); 89

90 소스코드 M2LEDActivity.java 141: } 142: minputlock = false; 143: } 144: } 145: 146: 147: 148: 149: } 90

91 소스코드 M2LEDView.java 001: package com.hbe.m2led; 002: 003: import android.content.context; 004: import android.content.res.resources; 005: import android.graphics.bitmap; 006: import android.graphics.bitmapfactory; 007: import android.graphics.canvas; 008: import android.graphics.paint; 009: import android.graphics.point; 010: import android.os.message; 011: import android.util.attributeset; 012: import android.view.display; 013: import android.view.motionevent; 014: import android.view.view; 015: import android.view.windowmanager; 016: 017: public class M2LEDView extends View { 018: private M2LEDActivity mcon; 019: 020: private Bitmap mimgbg, mimgledon, mimgledoff, mimgpwinit; 91

92 소스코드 M2LEDView.java 021: private Bitmap mimgtxtset, mimgtxtinput; 022: 023: private int[] mled_x, mled_y; 024: private int mpwtext_x, mpwtext_y; 025: private int mtxtset_x, mtxtset_y; 026: private int mtxtinput_x, mtxtinput_y; 027: private boolean[] mchkled; 029: Paint mpaint = new Paint(); 030: 031: // screen size 032: private int mscreenwidth, mscreenheight; 033: private double mzoomwidth, mzoomheight; 034: 035: public M2LEDView(Context context, AttributeSet attrs) { 036: super(context, attrs); 037: 038: mcon = (M2LEDActivity)context; 039: mled_x = new int[2]; 040: mled_y = new int[2]; 92

93 소스코드 M2LEDView.java 041: mchkled = new boolean[2]; 042: mchkled[0] = true; 043: mchkled[1] = false; 044: 045: initscreensize(); 046: initimagedata(); 047: initimageposition(); 048: } 049: 051: public void ondraw(canvas canvas){ 052: 053: canvas.drawbitmap(mimgbg, 0, 0, null); 054: 055: for(int i=0;i<2;i++){ 056: if(mchkled[i]) canvas.drawbitmap(mimgledon, mled_x[i], mled_y[i], null); 057: else canvas.drawbitmap(mimgledoff, mled_x[i], mled_y[i], null); 058: } 060: canvas.drawbitmap(mimgtxtset, mtxtset_x, mtxtset_y, null); 93

94 소스코드 M2LEDView.java 061: canvas.drawbitmap(mimgtxtinput, mtxtinput_x, mtxtinput_y, null); 062: canvas.drawbitmap(mimgpwinit, mpwtext_x, mpwtext_y, null); 063: } 064: 065: private void sendmessage(int what){ 066: Message msg = new Message(); 067: msg.what = what; 068: mcon.setmessage(msg); 069: } 070: 071: private boolean istouch(int touchx, int touchy, int x1, int y1, int x2, int y2){ 072: if( touchx>=x1 && touchx<=x2 && touchy>=y1 && touchy<=y2) return true; 073: else return false; 074: } 075: 077: public boolean ontouchevent(motionevent event){ 078: int x = (int)event.getx(); 079: int y = (int)event.gety(); 080: 94

95 소스코드 M2LEDView.java 081: if(event.getaction()==motionevent.action_down){ 082: int btnwidth = 150; 083: int btnheight = 145; 084: if(istouch(x, y, 120, 330, 120+btnWidth, 330+btnHeight)){ 085: sendmessage('1'); 086: } else if(istouch(x, y, 325, 330, 325+btnWidth, 330+btnHeight)){ 087: sendmessage('2'); 088: } else if(istouch(x, y, 525, 330, 525+btnWidth, 330+btnHeight)){ 089: sendmessage('3'); 090: } else if(istouch(x, y, 120, 535, 120+btnWidth, 535+btnHeight)){ 091: sendmessage('4'); 092: } else if(istouch(x, y, 325, 535, 325+btnWidth, 535+btnHeight)){ 093: sendmessage('5'); 094: } else if(istouch(x, y, 525, 535, 525+btnWidth, 535+btnHeight)){ 095: sendmessage('6'); 096: } else if(istouch(x, y, 120, 730, 120+btnWidth, 730+btnHeight)){ 097: sendmessage('7'); 098: } else if(istouch(x, y, 325, 730, 325+btnWidth, 730+btnHeight)){ 099: sendmessage('8'); 100: } else if(istouch(x, y, 525, 730, 525+btnWidth, 730+btnHeight)){ 95

96 소스코드 M2LEDView.java 101: sendmessage('9'); 102: } else if(istouch(x, y, 120, 925, 120+btnWidth, 925+btnHeight)){ 103: sendmessage('*'); 104: } else if(istouch(x, y, 325, 925, 325+btnWidth, 925+btnHeight)){ 105: sendmessage('0'); 106: } else if(istouch(x, y, 525, 925, 525+btnWidth, 925+btnHeight)){ 107: sendmessage('#'); 108: } else if(istouch(x, y, 85, 1095, 700, 1200)){ 109: sendmessage(' '); 110: } 112: invalidate(); 113: return true; 114: } 115: return super.ontouchevent(event); 116: } 117: 118: private void initscreensize(){ 119: Display display = ((WindowManager)mCon.getSystemService (Context.WINDOW_SERVICE)).getDefaultDisplay(); 120: 96

97 소스코드 M2LEDView.java 121: /* before HoneyComb 122: mscreenwidth = display.getwidth(); 123: mscreenheight = display.getheight(); 124: */ 125: 126: // after HoneyComb 127: Point point = new Point(); 128: display.getsize(point); 129: 130: mscreenwidth = point.x; 131: mscreenheight = point.y; 132: mzoomwidth = (double)mscreenwidth/(double)800; 133: mzoomheight = (double)mscreenheight/(double)1280; 134: } 135: 136: private Bitmap createimage(int r){ 137: Resources res = getresources(); 138: Bitmap imgprevconv = BitmapFactory.decodeResource(res, r); 139: int w = (int)(imgprevconv.getwidth()*mzoomwidth); 140: int h = (int)(imgprevconv.getheight()*mzoomheight); 141: return Bitmap.createScaledBitmap(imgPrevConv, w, h, true); 142: } 97

98 소스코드 M2LEDView.java 144: private Bitmap createimageallscreen(int r){ 145: Resources res = getresources(); 146: Bitmap imgprevconv = BitmapFactory.decodeResource(res, r); 147: int w = mscreenwidth; 148: int h = mscreenheight; 149: return Bitmap.createScaledBitmap(imgPrevConv, w, h, true); 150: } 151: 152: private void initimagedata(){ 153: mimgbg = createimageallscreen(r.drawable.led_bg); 154: mimgledon = createimage(r.drawable.led_on); 155: mimgledoff = createimage(r.drawable.led_off); 156: mimgpwinit = createimage(r.drawable.led_pwinit); 157: mimgtxtset = createimage(r.drawable.led_txtset); 158: mimgtxtinput = createimage(r.drawable.led_txtinput); 159: } 160: 98

99 소스코드 M2LEDView.java 161: private void initimageposition(){ 162: int halfscreen = mscreenwidth/2; 163: 164: mtxtset_x = halfscreen - mimgtxtset.getwidth() - (int)(20*mzoomwidth); 165: mtxtset_y = (int)(200*mzoomheight); 166: 167: mled_x[0] = mtxtset_x - mimgledon.getwidth() - (int)(5*mzoomwidth); 168: mled_y[0] = (int)(208*mzoomheight); 169: 170: mled_x[1] = halfscreen + (int)(20*mzoomwidth); 171: mled_y[1] = mled_y[0]; 173: mtxtinput_x = mled_x[1] + mimgledon.getwidth() + (int)(5*mzoomwidth); 174: mtxtinput_y = mtxtset_y; 175: 176: mpwtext_x = halfscreen - (mimgpwinit.getwidth()/2); 177: mpwtext_y = (int)(1120*mzoomheight); 178: } 179: 180: public void setsettingmode(){ 99

100 소스코드 M2LEDView.java 181: mchkled[0]=true; 182: mchkled[1]=false; 183: } 184: public void setinputmode(){ 185: mchkled[1]=true; 186: mchkled[0]=false; 187: } 188: } 100

101 LED 예제 : 실행화면 101