Tinker Board S : RDP (원격 데스크톱) 설치

OS/Tinker Board S 2018.09.17 01:12 Posted by 파란크리스마스

출처

xrdp 설치

$ sudo apt-get install xrdp
$ sudo apt-cache policy xrdp
xrdp:
  Installed: 0.9.1-9+deb9u3
  Candidate: 0.9.1-9+deb9u3
  Version table:
 *** 0.9.1-9+deb9u3 500
        500 http://http.debian.net/debian stretch/main armhf Packages
        100 /var/lib/dpkg/status

xorgxrdp 설치

$ sudo apt-get install xorgxrdp
$ sudo apt-cache policy xorgxrdp
xorgxrdp:
  Installed: 0.9.1-9+deb9u3
  Candidate: 0.9.1-9+deb9u3
  Version table:
 *** 0.9.1-9+deb9u3 500
        500 http://http.debian.net/debian stretch/main armhf Packages
        100 /var/lib/dpkg/status

IP 확인

$ ip addr | grep inet
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
    inet 192.168.137.142/24 brd 192.168.137.255 scope global dynamic eth0
    inet6 fe80::2edd:91a0:cbe0:6514/64 scope link

원격 데스크톱 연결

Tinker Board S : Lazarus 설치

OS/Tinker Board S 2018.09.16 12:26 Posted by 파란크리스마스

출처

OS 업그레이드

$ sudo apt-get update
$ sudo apt-get upgrade

기존 전치된 lazarus 삭제

$ sudo apt-get remove lazarus
$ sudo apt-get remove fpc
$ sudo apt-get autoremove
$ sudo shutdown -r now

Swap 파일 크기 늘리기

여유 공간 확인

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        15G  8.3G  5.5G  61% /
devtmpfs        943M     0  943M   0% /dev
tmpfs          1007M     0 1007M   0% /dev/shm
tmpfs          1007M  8.9M  998M   1% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs          1007M     0 1007M   0% /sys/fs/cgroup
/dev/mmcblk1p1   63M  7.5M   56M  12% /boot
tmpfs           202M  8.0K  202M   1% /run/user/1000

Swap 설정 파일 수정

$ sudo vi /etc/dphys-swapfile

Swap 사이즈 설정

CONF_SWAPSIZE=1000

Swap 설정 파일을 저장하고 스와핑을 다시 시작

$ sudo /etc/init.d/dphys-swapfile stop
Stopping dphys-swapfile (via systemctl): dphys-swapfile.service.
$ sudo /etc/init.d/dphys-swapfile start
Starting dphys-swapfile (via systemctl): dphys-swapfile.service.
$ ls -lh /var
total 1001M
drwxr-xr-x  2 root root   4.0K Sep 16 01:22 backups
drwxr-xr-x 11 root root   4.0K Jul 21 10:44 cache
drwxr-xr-x 49 root root   4.0K Jul 21 20:09 lib
drwxrwsr-x  2 root staff  4.0K Nov 19  2017 local
lrwxrwxrwx  1 root root      9 Jan 10  2018 lock -> /run/lock
drwxr-xr-x  7 root root   4.0K Sep 16 03:29 log
drwxrwsr-x  2 root mail   4.0K Jan 10  2018 mail
drwxr-xr-x  2 root root   4.0K Jan 10  2018 opt
lrwxrwxrwx  1 root root      4 Jan 10  2018 run -> /run
drwxr-xr-x  7 root root   4.0K Jul 21 10:43 spool
-rw-------  1 root root  1000M Sep 16 03:43 swap
drwxrwxrwt  6 root root   4.0K Sep 16 03:30 tmp

Seed/Bootstrap Pascal Compiler 설치

$ mkdir /usr/local/fpc
$ wget ftp://ftp.hu.freepascal.org/pub/fpc/dist/3.0.4/arm-linux/fpc-3.0.4.arm-linux-eabihf-raspberry.tar
$ tar xvf fpc-3.0.4.arm-linux-eabihf-raspberry.tar 
fpc-3.0.4.arm-linux/
fpc-3.0.4.arm-linux/doc-pdf.tar.gz
fpc-3.0.4.arm-linux/binary.arm-linux.tar
fpc-3.0.4.arm-linux/install.sh
fpc-3.0.4.arm-linux/demo.tar.gz
$ mv fpc-3.0.4.arm-linux /usr/local/fpc/
$ cd /usr/local/fpc/fpc-3.0.4.arm-linux/
$ sudo ./install.sh

설치과정

linaro@tinkerboard:/usr/local/fpc/fpc-3.0.4.arm-linux$ sudo ./install.sh 
This shell script will attempt to install the Free Pascal Compiler
version 3.0.4 with the items you select

Install prefix (/usr or /usr/local)  [/usr] : 
Installing compiler and RTL for arm-linux...

Install Textmode IDE (Y/n) ? 
Done.

Install documentation (Y/n) ? 
Installing documentation in /usr/share/doc/fpc-3.0.4 ...
Done.

Install demos (Y/n) ? 
Install demos in [/usr/share/doc/fpc-3.0.4/examples] : 
Installing demos in /usr/share/doc/fpc-3.0.4/examples ...
Done.

Running on linux
Write permission in /etc.
Writing sample configuration file to /etc/fpc.cfg
Writing sample configuration file to /usr/lib/fpc/3.0.4/ide/text/fp.cfg
Writing sample configuration file to /usr/lib/fpc/3.0.4/ide/text/fp.ini
Writing sample configuration file to /etc/fppkg.cfg
Writing sample configuration file to /etc/fppkg/default

End of installation.

Refer to the documentation for more information.

svn 클라이언트 설치

$ sudo apt-get install subversion

관련 라이브러리 설치

$ sudo apt-get install libgtk2.0-dev libcairo2-dev libpango1.0-dev libgdk-pixbuf2.0-dev libatk1.0-dev libghc-x11-dev libx11-dev

Free Pascal 설치

$ cd /usr/local/fpc
$ svn co http://svn.freepascal.org/svn/fpc/trunk source 
$ cd source
$ sudo make all OPT="-dFPC_ARMHF -CpARMV7A -OpARMV7A"
$ sudo make install OPT="-dFPC_ARMHF -CpARMV7A -OpARMV7A" PREFIX=/usr/local
$ sudo make install sourceinstall OPT="-dFPC_ARMHF -CpARMV7A -OpARMV7A" PREFIX=/usr/local

설치된 pascal 버전 확인

$ ls /usr/lib/fpc
3.0.4  lexyacc

fpc 최신 버전으로 심볼릭 링크 걸기

$ ls -al /usr/bin/ppcarm
lrwxrwxrwx 1 root root 25 Sep 16 11:23 /usr/bin/ppcarm -> /usr/lib/fpc/3.0.4/ppcarm

fpc 컴파일러 버전 확인

$ fpc -iW
3.0.4

Lazarus 설치

관련 라이브러리 설치

$ sudo apt-get install libx11-dev libgdk-pixbuf2.0-dev libcairo2-dev gir1.2-coglpango-1.0 libpangox-1.0-dev xorg-dev libgtk2.0-dev libpango1.0-dev

Lazarus 다운로드 및 컴파일

$ mkdir /usr/local/lazarus
$ cd /usr/local/lazarus
$ svn co http://svn.freepascal.org/svn/lazarus/trunk source
$ cd source
$ sudo make all OPT="-dFPC_ARMHF -CpARMV7A -OpARMV7A"
$ sudo make install OPT="-dFPC_ARMHF -CpARMV7A -OpARMV7A" PREFIX=/usr/local

gcc 라이브러리 경로 설정

컴파일하면 crtbegin.o 및 crtend.o를 찾을 수 없다는 경고가 출력됩니다. 경고가 표지 되지 않도록 설정

crtbegin.o 찾기

$ sudo find / -name crtbegin.o
/usr/lib/gcc/arm-linux-gnueabihf/6/crtbegin.o

fpc 환경 파일 (fpc.cfg) 수정

$ sudo vi /etc/fpc.cfg

내용 추가

# path to the gcclib
-Fl/usr/lib/gcc/arm-linux-gnueabihf/6

gdb 설치

$ sudo apt-get install gdb-multiarch

Lazarus 실행

fpc 경로 오류

fpc 경로 찾기

fpc 경로 설정

Lazarus 실행화면

Tinker Board S : pi4j

OS/Tinker Board S 2018.09.08 13:04 Posted by 파란크리스마스

출처

Tinker Board S : pi4j

Tinker Board의 pwm 제어 하는 예제는 python을 제외하고는 c언어나 java 예제를 찾을 수 없어서 wiringPi 라이브러리를 직접 컴파일 해보았지만 모터의 떨림도 심하고, 발열도 심해서 아직은 불안한것 같습니다. python의 pwm관련 소스를 wiringPi에 추가하고 다시 pi4j 라이브러리에 적용했습니다. pi4j라이브러리와 pi4j를 이용한 Servo.java 예제도 첨부했습니다.동영상을 보시면 알겠지만, 떨림도, 발열도 발생하지 않았습니다.

pi4j-core-1.2-SNAPSHOT.jar

TinkerBoardPin.java

package com.pi4j.io.gpio;

import java.util.EnumSet;

public class TinkerBoardPin extends PinProvider {

    // GPIO0_C1
    public static final Pin GPIO0_C1 = createDigitalPin(7, "GPIO0_C1");          // addGpioPinInfo(16+1, "GPIO0_C1", 7, PinInfo.DIGITAL_IN_OUT);

    // GPIO5B (GP5B0-GP5B7)
    public static final Pin GPIO5_B0 = createDigitalPin(16, "GPIO5_B0");         // addGpioPinInfo(160, "GPIO5_B0", 10, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO5_B1 = createDigitalPin(15, "GPIO5_B1");         // addGpioPinInfo(160+1, "GPIO5_B1", 8, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO5_B2 = createDigitalPin(4, "GPIO5_B2");          // addGpioPinInfo(160+2, "GPIO5_B2", 16, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO5_B3 = createDigitalPin(5, "GPIO5_B3");          // addGpioPinInfo(160+3, "GPIO5_B3", 18, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO5_B4 = createDigitalPin(0, "GPIO5_B4");          // addGpioPinInfo(160+4, "GPIO5_B4", 11, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO5_B5 = createDigitalPin(21, "GPIO5_B5");         // addGpioPinInfo(160+5, "GPIO5_B5", 29, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO5_B6 = createDigitalPin(2, "GPIO5_B6");          // addGpioPinInfo(160+6, "GPIO5_B6", 13, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO5_B7 = createDigitalPin(3, "GPIO5_B7");          // addGpioPinInfo(160+7, "GPIO5_B7", 15, PinInfo.DIGITAL_IN_OUT);

    // GPIO5C (GP5C0-GP5C3)                                                       // GPIO5C (GP5C0-GP5C3)
    public static final Pin GPIO5_C0 = createDigitalPin(22, "GPIO5_C0");          // addGpioPinInfo(168, "GPIO5_C0", 31, PinInfo.DIGITAL_IN_OUT);
    //public static final Pin GPIO5_C1 = createDigitalPin(168+1, "GPIO5_C1");     // addGpioPinInfo(168+1, "GPIO5_C1", -1, PinInfo.DIGITAL_IN_OUT);
    //public static final Pin GPIO5_C2 = createDigitalPin(168+2, "GPIO5_C2");     // addGpioPinInfo(168+2, "GPIO5_C2", -1, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO5_C3 = createDigitalPin(6, "GPIO5_C3");           // addGpioPinInfo(168+3, "GPIO5_C3", 22, PinInfo.DIGITAL_IN_OUT);

    // GPIO6A (GP6A0-GP6A1)
    public static final Pin GPIO6_A0 = createDigitalPin(1, "GPIO6_A0");           // addGpioPinInfo(184, "GPIO6_A0", 12, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO6_A1 = createDigitalPin(24, "GPIO6_A1");          // addGpioPinInfo(184+1, "GPIO6_A1", 35, PinInfo.DIGITAL_IN_OUT);
    // GPIO6A (GP6A3-GP6A4)
    public static final Pin GPIO6_A3 = createDigitalPin(28, "GPIO6_A3");          // addGpioPinInfo(184+3, "GPIO6_A3", 38, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO6_A4 = createDigitalPin(29, "GPIO6_A4");          // addGpioPinInfo(184+4, "GPIO6_A4", 40, PinInfo.DIGITAL_IN_OUT);

    // GPIO7A (GP7A7)
    public static final Pin GPIO7_A7 = createDigitalPin(27, "GPIO7_A7");          // addGpioPinInfo(216+7, "GPIO7_A7", 36, PinInfo.DIGITAL_IN_OUT);

    // GPIO7B (GP7B0-GP7B2)
    public static final Pin GPIO7_B0 = createDigitalPin(25, "GPIO7_B0");          // addGpioPinInfo(224, "GPIO7_B0", 37, PinInfo.DIGITAL_IN_OUT);
    //public static final Pin GPIO7_B1 = createDigitalPin(224+1, "GPIO7_B1");     // addGpioPinInfo(224+1, "GPIO7_B1", -1, PinInfo.DIGITAL_IN_OUT);
    //public static final Pin GPIO7_B2 = createDigitalPin(224+2, "GPIO7_B2");     // addGpioPinInfo(224+2, "GPIO7_B2", -1, PinInfo.DIGITAL_IN_OUT);

    // GPIO7CL (GP7C1-GP7C2)
    public static final Pin GPIO7_C1 = createDigitalPin(30, "GPIO7_C1");          // addGpioPinInfo(232+1, "GPIO7_C1", 27, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO7_C2 = createDigitalPin(31, "GPIO7_C2");          // addGpioPinInfo(232+2, "GPIO7_C2", 28, PinInfo.DIGITAL_IN_OUT);
    // GPIO7CH (GP7C6-GP7C7)
    public static final Pin GPIO7_C6 = createDigitalAndPwmPin(23, "GPIO7_C6");    // addPwmPinInfo(232+6, "GPIO7_C6", 33, 0, PinInfo.DIGITAL_IN_OUT_PWM);
    public static final Pin GPIO7_C7 = createDigitalAndPwmPin(26, "GPIO7_C7");    // addPwmPinInfo(232+7, "GPIO7_C7", 32, 1, PinInfo.DIGITAL_IN_OUT_PWM);

    // GPIO8A (GP8A3-GP8A7)
    public static final Pin GPIO8_A3 = createDigitalPin(11, "GPIO8_A3");          // addGpioPinInfo(248+3, "GPIO8_A3", 26, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO8_A4 = createDigitalPin(8, "GPIO8_A4");           // addGpioPinInfo(248+4, "GPIO8_A4", 3, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO8_A5 = createDigitalPin(9, "GPIO8_A5");           // addGpioPinInfo(248+5, "GPIO8_A5", 5, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO8_A6 = createDigitalPin(14, "GPIO8_A6");          // addGpioPinInfo(248+6, "GPIO8_A6", 23, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO8_A7 = createDigitalPin(10, "GPIO8_A7");          // addGpioPinInfo(248+7, "GPIO8_A7", 24, PinInfo.DIGITAL_IN_OUT);

    // GPIO8B (GP8B0-GP8B1)
    public static final Pin GPIO8_B0 = createDigitalPin(13, "GPIO8_B0");          // addGpioPinInfo(256, "GPIO8_B0", 21, PinInfo.DIGITAL_IN_OUT);
    public static final Pin GPIO8_B1 = createDigitalPin(12, "GPIO8_B1");          // addGpioPinInfo(256+1, "GPIO8_B1", 19, PinInfo.DIGITAL_IN_OUT);

    protected static Pin createDigitalPin(int address, String name) {
        return createDigitalPin(TinkerBoardGpioProvider.NAME, address, name);
    }

    protected static Pin createDigitalPinNoEdge(int address, String name, EnumSet<PinPullResistance> resistance) {
        return createDigitalPin(TinkerBoardGpioProvider.NAME, address, name, resistance, EnumSet.noneOf(PinEdge.class));
    }

    protected static Pin createDigitalPinNoEdge(int address, String name) {
        return createDigitalPin(TinkerBoardGpioProvider.NAME, address, name, EnumSet.noneOf(PinEdge.class));
    }

    protected static Pin createDigitalAndPwmPin(int address, String name) {
        return createDigitalAndPwmPin(TinkerBoardGpioProvider.NAME, address, name);
    }

    protected static Pin createDigitalAndPwmPinNoEdge(int address, String name) {
        return createDigitalAndPwmPin(TinkerBoardGpioProvider.NAME, address, name, EnumSet.noneOf(PinEdge.class));
    }

    // *override* static method from subclass
    // (overriding a static method is not supported in Java
    //  so this method definition will hide the subclass static method)
    public static Pin getPinByName(String name) {
        return PinProvider.getPinByName(name);
    }

    // *override* static method from subclass
    // (overriding a static method is not supported in Java
    //  so this method definition will hide the subclass static method)
    public static Pin getPinByAddress(int address) {
        return PinProvider.getPinByAddress(address);
    }

    // *override* static method from subclass
    // (overriding a static method is not supported in Java
    //  so this method definition will hide the subclass static method)
    public static Pin[] allPins() { return PinProvider.allPins(); }

    // *override* static method from subclass
    // (overriding a static method is not supported in Java
    //  so this method definition will hide the subclass static method)
    public static Pin[] allPins(PinMode ... mode) { return PinProvider.allPins(mode); }
}

servo.c

#include <stdio.h>
#include "RKIO.h"
#include "wiringTB.h"
#include "constants.h"
#include "common.h"
#include "c_gpio.h"
#include "py_gpio.h"
#include "py_pwm.h"

int main ()
{
	printf("servo.main\n");
	
	int myservo = 239;
	
	//GPIO.setmode(GPIO.ASUS)
	py_setmode(ASUS);
	
	//GPIO.setup(myservo,GPIO.OUT)
	py_setup_channel(myservo, OUTPUT);
	
	//pwm = GPIO.PWM(myservo,50) # 50hz yani 20mslik periyod
	PWMObject pwm;
	PWM_init(&pwm, myservo, 50);
	printf("pwm.gpio = %d\n", pwm.gpio);
	
	//pwm.start(2.5) # 0 derece
	PWM_start(&pwm, 2.5);
	
	//pwm.ChangeDutyCycle(2.5) #0 derece
	PWM_ChangeDutyCycle(&pwm, 2.5);
	sleep( 1 );
  
	//pwm.ChangeDutyCycle(7.5) #90 derece
	PWM_ChangeDutyCycle(&pwm, 7.5);
	sleep( 1 );
	
	//pwm.ChangeDutyCycle(12.5) #180 derece
	PWM_ChangeDutyCycle(&pwm, 12.5);
	sleep( 1 );
	
	//pwm.ChangeDutyCycle(7.5)
	PWM_ChangeDutyCycle(&pwm, 7.5);
	sleep( 1 );
	
	//pwm.ChangeDutyCycle(2.5) #0 derece
	PWM_ChangeDutyCycle(&pwm, 2.5);
	sleep( 1 );
  
 	//pwm.ChangeDutyCycle(7.5)
	PWM_ChangeDutyCycle(&pwm, 7.5);
	sleep( 1 );
	
	PWM_dealloc(pwm);
}

컴파일

$ gcc -lm -lpwmBx servo.c -o servo

Servo.java

import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.TinkerBoardGpioProvider;
import com.pi4j.wiringpi.ASUSGpio;
import com.pi4j.wiringpi.PWMObject;

public class Servo {

	public static void main(String[] args) throws Exception {

		GpioFactory.setDefaultProvider(new TinkerBoardGpioProvider());

		int myservo = 239;

		//GPIO.setmode(GPIO.ASUS)
		ASUSGpio.pySetmode(ASUSGpio.ASUS);

		//GPIO.setup(myservo,GPIO.OUT)
		ASUSGpio.pySetupChannel(myservo, ASUSGpio.OUTPUT);

		//pwm = GPIO.PWM(myservo,50) # 50hz yani 20mslik periyod
		PWMObject pwm = ASUSGpio.pwmInit(myservo, 50);
		System.out.println("pwm.gpio = "+ pwm.gpio + "/" + pwm.freq + "/" + pwm.dutycycle);

		//pwm.start(2.5) # 0 derece
		ASUSGpio.pwmStart(pwm, 2.5f);
		Thread.sleep( 1000 );

		//pwm.ChangeDutyCycle(2.5) #0 derece
		ASUSGpio.pwmChangeDutyCycle(pwm, 2.5f);
		Thread.sleep( 1000 );

		//pwm.ChangeDutyCycle(7.5) #90 derece
		ASUSGpio.pwmChangeDutyCycle(pwm, 7.5f);
		Thread.sleep( 1000 );

		//pwm.ChangeDutyCycle(12.5) #180 derece
		ASUSGpio.pwmChangeDutyCycle(pwm, 12.5f);
		Thread.sleep( 1000 );

		//pwm.ChangeDutyCycle(7.5)
		ASUSGpio.pwmChangeDutyCycle(pwm, 7.5f);
		Thread.sleep( 1000 );

		//pwm.ChangeDutyCycle(2.5) #0 derece
		ASUSGpio.pwmChangeDutyCycle(pwm, 2.5f);
		Thread.sleep( 1000 );

		//pwm.ChangeDutyCycle(7.5)
		ASUSGpio.pwmChangeDutyCycle(pwm, 7.5f);
		Thread.sleep( 1000 );
		
		ASUSGpio.pwmDealloc(pwm);
	}
}

컴파일

$ javac -cp .:pi4j-core-1.2-SNAPSHOT.jar Servo.java

실행

$ java -cp .:pi4j-core-1.2-SNAPSHOT.jar Servo

실행 동영상

Tinker Board S : C언어를 이용한 GPIO LED 제어

OS/Tinker Board S 2018.09.03 00:55 Posted by 파란크리스마스

출처

led.c

#include <stdio.h>
#include <wiringpi.h>

// #define LED 0 matches with ASUS_GPIO 164! This can be checked with command 'sudo gpio readall'.
#define LED     8

int main (void)
{
         printf ("TB blink\n");

         wiringPiSetup ();
         pinMode (LED, OUTPUT);

         for (;;)
         {
                 printf ("led on\n");
                 digitalWrite (LED, HIGH);
                 delay (500);
                 printf ("led off\n");
                 digitalWrite (LED, LOW);
                 delay (500);
         }
         return 0;
}

컴파일

$ gcc -o led led.c -lwiringPi

실행

$ ./led

Tinker Board S : PWM(서보모터) 제어

OS/Tinker Board S 2018.09.02 16:13 Posted by 파란크리스마스

출처

Tinker Board S : PWM(서보모터) 제어

wiringPi라이브러리의 설치

$ git clone https://github.com/TinkerBoard/gpio_lib_c.git
$ cd gpio_lib_c/
$ chmod a+x build
$ sudo ./build
 
... 생략 ...
 
[Install Dynamic Lib]
 
GPIO Utility
[Compile] gpio.c
[Compile] readall.c
[Compile] pins.c
[Link]
[Install]
 
All Done.
 
NOTE: To compile programs with wiringPi, you need to add:
    -lwiringPi
  to your compile line(s) To use the Gertboard, MaxDetect, etc.
  code (the devLib), you need to also add:
    -lwiringPiDev
  to your compile line(s).

gpio readall

$ gpio readall
wiringPi: wiringPiSetup called
piGpioLayout: Hardware: Hardware        : Rockchip (Device Tree)
 
piGpioLayout: Revision string: Revision : 0000
piGpioLayout: last4Chars are: "0000"
piGpioLayoutOops: Returning revision: 2
piboardId: Revision string: Revision    : 0000
piBoardId: Old Way: revision is: 0000
piBoardId: 2: revision is: 0000
piboardId: Revision string: Revision    : 0000
piBoardId: Old Way: revision is: 0000
piBoardId: 2: revision is: 0000
 +-----+-----+---------+------+---+--Tinker--+---+------+---------+-----+-----+
 | CPU | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | CPU |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 | 252 |   8 |   SDA.1 |  I2C | 1 |  3 || 4  |   |      | 5v      |     |     |
 | 253 |   9 |   SCL.1 |  I2C | 1 |  5 || 6  |   |      | 0v      |     |     |
 |  17 |   7 | GPIO0C1 |   IN | 1 |  7 || 8  | 1 | SERL | TxD.1   | 15  | 161 |
 |     |     |      0v |      |   |  9 || 10 | 1 | SERL | RxD.1   | 16  | 160 |
 | 164 |   0 |  CTSN.4 | SERL | 1 | 11 || 12 | 0 | I2S  | I2S_CLK | 1   | 184 |
 | 166 |   2 |   TxD.4 | SERL | 1 | 13 || 14 |   |      | 0v      |     |     |
 | 167 |   3 |   RxD.4 | SERL | 1 | 15 || 16 | 1 | SERL | CTSN.1  | 4   | 162 |
 |     |     |    3.3v |      |   | 17 || 18 | 1 | SERL | RTSN.1  | 5   | 163 |
 | 257 |  12 |  MOSI.2 |  SPI | 0 | 19 || 20 |   |      | 0v      |     |     |
 | 256 |  13 |  MISO.2 |  SPI | 1 | 21 || 22 | 0 | IN   | GPIO5C3 | 6   | 171 |
 | 254 |  14 |  SCLK.2 |  SPI | 0 | 23 || 24 | 1 | SPI  | CE0.2   | 10  | 255 |
 |     |     |      0v |      |   | 25 || 26 | 1 | SPI  | CE1.2   | 11  | 251 |
 | 233 |  30 |   SDA.4 |  I2C | 1 | 27 || 28 | 1 | I2C  | SCL.4   | 31  | 234 |
 | 165 |  21 |  RTSN.4 | SERL | 1 | 29 || 30 |   |      | 0v      |     |     |
 | 168 |  22 | GPIO5C0 |   IN | 1 | 31 || 32 | 0 | OUT  | GPIO7C7 | 26  | 239 |
 | 238 |  23 |   PWM.2 |  PWM | 0 | 33 || 34 |   |      | 0v      |     |     |
 | 185 |  24 |  I2S_FS |  I2S | 0 | 35 || 36 | 1 | SERL | RxD.3   | 27  | 223 |
 | 224 |  25 |   TxD.3 | SERL | 1 | 37 || 38 | 1 | I2S  | I2S_SDI | 28  | 187 |
 |     |     |      0v |      |   | 39 || 40 | 0 | I2S  | I2S_SDO | 29  | 188 |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | CPU | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | CPU |
 +-----+-----+---------+------+---+--Tinker--+---+------+---------+-----+-----+

팅커 보드 용 Python GPIO 라이브러리 설치

$ wget http://github.com/TinkerBoard/gpio_lib_python/archive/sbc/tinkerboard/python.zip
$ sudo apt-get install python-dev
$ unzip python.zip
$ cd gpio_lib_python-sbc-tinkerboard-python/
$ sudo python setup.py install

py_gpio.c 소스 일부

PyMethodDef asuspi_gpio_methods[] = {
   {"setup", (PyCFunction)py_setup_channel, METH_VARARGS | METH_KEYWORDS, "Set up a GPIO channel or list of channels with a direction and (optional) pull/up down control\nchannel        - either board pin number ,RK number or ASUS number depending on which mode is set.\ndirection      - IN or OUT\n[pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN\n[initial]      - Initial value for an output channel"},
   {"cleanup", (PyCFunction)py_cleanup, METH_VARARGS | METH_KEYWORDS, "Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection\n[channel] - individual channel or list/tuple of channels to clean up.  Default - clean every channel that has been used."},
   {"output", py_output_gpio, METH_VARARGS, "Output to a GPIO channel or list of channels\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set.\nvalue   - 0/1 or False/True or LOW/HIGH"},
   {"input", py_input_gpio, METH_VARARGS, "Input from a GPIO channel.  Returns HIGH=1=True or LOW=0=False\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set."},
   {"setmode", py_setmode, METH_VARARGS, "Set up numbering mode to use for channels.\nBOARD - Use ASUS Pi board numbers\nRK   - Use Broadcom GPIO 00..nn numbers"},
   {"getmode", py_getmode, METH_VARARGS, "Get numbering mode used for channel numbers.\nReturns BOARD, RK, ASUS or UNKNOWN"},
   {"add_event_detect", (PyCFunction)py_add_event_detect, METH_VARARGS | METH_KEYWORDS, "Enable edge detection events for a particular GPIO channel.\nchannel      - either board pin number ,RK number or ASUS number depending on which mode is set.\nedge         - RISING, FALLING or BOTH\n[callback]   - A callback function for the event (optional)\n[bouncetime] - Switch bounce timeout in ms for callback"},
   {"remove_event_detect", py_remove_event_detect, METH_VARARGS, "Remove edge detection for a particular GPIO channel\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set."},
   {"event_detected", py_event_detected, METH_VARARGS, "Returns True if an edge has occured on a given GPIO.  You need to enable edge detection using add_event_detect() first.\nchannel - either board pin number ,RK number and ASUS number depending on which mode is set."},
   {"add_event_callback", (PyCFunction)py_add_event_callback, METH_VARARGS | METH_KEYWORDS, "Add a callback for an event already defined using add_event_detect()\nchannel      - either board pin number ,RK number or ASUS number depending on which mode is set.\ncallback     - a callback function"},
   {"wait_for_edge", (PyCFunction)py_wait_for_edge, METH_VARARGS | METH_KEYWORDS, "Wait for an edge.\nchannel      - either board pin number ,RK number or ASUS number depending on which mode is set.\nedge         - RISING, FALLING or BOTH\n[bouncetime] - time allowed between calls to allow for switchbounce"},
   {"gpio_function", py_gpio_function, METH_VARARGS, "Return the current GPIO function (IN, OUT, PWM, SERIAL, I2C, SPI)\nchannel - either board pin number ,RK number or ASUS number depending on which mode is set."},
   {"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"},
   {"pwmWrite", py_pwmWrite, METH_VARARGS, "Writes the duty cycle to the PWM register for the given GPIO"},
   {"pwmToneWrite", py_pwmToneWrite, METH_VARARGS, "Creates a square wave with given frequency for the given GPIO"},
   {"pwmSetFrequency", py_pwmSetFrequency, METH_VARARGS, "Set up the frequency of PWM clock source."},
   {"pwmSetPeriod", py_pwmSetPeriod, METH_VARARGS, "Writes the period to the PWM register for the given GPIO."},
   {"setGpioDrive", py_setGpioDrive, METH_VARARGS, "Set up the drive strength for the given GPIO."},
   {"getGpioDrive", py_getGpioDrive, METH_VARARGS, "Return the current drive strength."},
   {NULL, NULL, 0, NULL}
};

PWM(서보모터) 제어 파이썬 예제

import ASUS.GPIO as GPIO
import time

GPIO.setmode(GPIO.ASUS)
GPIO.setwarnings(False)

myservo = 239

GPIO.setup(myservo,GPIO.OUT)
pwm = GPIO.PWM(myservo,50) # 50hz yani 20mslik periyod
pwm.start(2.5) # 0 derece

try:
        while True:
                print "0 derece"
                pwm.ChangeDutyCycle(2.5) #0 derece
                time.sleep(1) # wait 1sec
                print "90 derece"
                pwm.ChangeDutyCycle(7.5) #90 derece
                time.sleep(1)
                print "180 derece"
                pwm.ChangeDutyCycle(12.5) #180 derece
                time.sleep(1)
                print "90 derece"
                pwm.ChangeDutyCycle(7.5)
                time.sleep(1)
except KeyboardInterrupt:
        print "Hoscakal canim"
        GPIO.cleanup()

PWM(서보모터) 제어 Java 예제

import com.pi4j.wiringpi.Gpio;

public class ServoTest3 {
	
	private static int PIN_NUMBER = 239;
	
	public static void main(String[] args) throws Exception {
		//
		//GpioFactory.setDefaultProvider(new TinkerBoardGpioProvider());
		
		Gpio.wiringPiSetupGpio();

		Gpio.pinMode(PIN_NUMBER, Gpio.PWM_OUTPUT);
		Gpio.pwmSetMode(Gpio.PWM_MODE_MS);
		// 445 : 200 ~ 1000
		Gpio.pwmSetClock(445); // Gpio.pwmSetClock(400);
		Gpio.pwmSetRange(1024);
		
		int[] arr = {205, 570, 1000};

		while (true) {
			for (int i=0; i≪arr.length; i++) {
				Gpio.pwmWrite(PIN_NUMBER, arr[i]);
				Thread.sleep(300);
			}
		}
	}
}

NanoPi NEO2-LTS NAS

OS/NanoPi 2018.08.30 23:22 Posted by 파란크리스마스

출처

Debian8 Jessie for NanoPi NEO2 설치

nanopi-neo2_debian-nas-jessie_4.14.0_20171208.img.zip 파일 이미지 복원

NAS에 접속

브라우져에서 FriendlyELEC 호스트 이름으로 접속

사용자이름 : admin
암호 : openmediavault

HDD Format

[저장소 - 파일시스템] 왼쪽 메뉴에서 선택하고, Format 할 파일 시스템을 목록에서 선택한 다음, [삭제] 버튼 선택

삭제 확인 메시지 [예] 버튼 선택

[생성] 버튼 선택해서 삭제한 파일 시스템을 추가

[장치] 에서 HDD를 선택하고, 파일 시스템은 [EXT4]로 선택하고, [예] 버튼 선택

추가된 파일 시스템 확인

Swift4 tip

Programming/Swift 2018.08.27 10:14 Posted by 파란크리스마스

출처

Dictionary to JSON

출처 : Convert Dictionary to JSON in Swift - Stack Overflow

        let jsonData = try! JSONSerialization.data(withJSONObject: parameters, options: JSONSerialization.WritingOptions.prettyPrinted)
        let jsonString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue)! as String
        print(jsonString)

화면전환, 파라미터 전달

출처 : Swift 화면 전환 기법: 뷰 컨트롤러, 내비게이션 컨트롤러, 세그웨이 : 네이버 블로그

    func native_video_recording(_ data : NSDictionary) { 
        let vcRecord = self.storyboard!.instantiateViewController(withIdentifier: "vcRecord") as! RecordController // 1
        vcRecord.setParamData(data) // 파라미터 전달
        vcRecord.modalTransitionStyle = UIModalTransitionStyle.crossDissolve // 2
        self.present(vcRecord, animated: true) // 3
    }

카메라 리소스 구하기

출처 : GitHub - parthibanios/custom-Video-Recording-Swift-3.0: Record video using AVCapture AVFoundation framework

    //MARK:- Setup Camera
    func setupSession() -> Bool {
        
        //captureSession.sessionPreset = AVCaptureSessionPresetHigh
        //1080
        captureSession.sessionPreset = AVCaptureSession.Preset.hd1920x1080
        
        // Setup Camera
        let camera = AVCaptureDevice.default(for: .video)
        do {
            let input = try AVCaptureDeviceInput(device: camera!)
            if captureSession.canAddInput(input) {
                captureSession.addInput(input)
                activeInput = input
            }
        } catch {
            print("Error setting device video input: \(error)")
            return false
        }
        
        // Setup Microphone
        let microphone = AVCaptureDevice.default(for: .audio)
        do {
            let micInput = try AVCaptureDeviceInput(device: microphone!)
            if captureSession.canAddInput(micInput) {
                captureSession.addInput(micInput)//addInput(micInput)
            }
        } catch {
            print("Error setting device audio input: \(error)")
            return false
        }
        movieOutput.maxRecordedDuration = CMTimeMake(9, 1)
        
        // Movie output
        if captureSession.canAddOutput(movieOutput) {
            captureSession.addOutput(movieOutput)
        }
        
        return true
    }

도큐먼트 디렉토리 구하기 - UIFileSharingEnabled 설정의 Root 경로

출처 : Swift로 파일 다루기 :

Eth Developer's Lab

    //EDIT 1: I FORGOT THIS AT FIRST
    func getMp4PathURL() -> URL? {
        /*
        let directory = NSTemporaryDirectory() as NSString
        
        if directory != "" {
            let path = directory.appendingPathComponent(NSUUID().uuidString + ".mp4")
            return URL(fileURLWithPath: path)
        }
        return nil
        */
        
        // 도큐먼트 디렉토리 구하기 - UIFileSharingEnabled의 Root 경로
        guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil }
        let fileName = NSUUID().uuidString + ".mp4"
        let fileURL = documentsDirectory.appendingPathComponent(fileName)
        
        /*
        print(imageURL)
        do {
            let imageData = try Data(contentsOf: imageURL)
            return UIImage(data: imageData)
        } catch let err as NSError {
            print("이미지 로딩 에러 : \(err)")
        }
        */
        
        return fileURL
    }

Swift4 : Alamofire 프로젝트에 추가하기

출처 : [iOS / Swift4] Alamofire 사용하기 | ry4nkim

Podfile 파일 편집

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'project' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  project 'project.xcodeproj'

  # Pods for project
  pod 'Firebase/Core'
  pod 'Firebase/Messaging'
  pod 'Alamofire', '~> 4.7'

end

pod install

$ pod install
Analyzing dependencies
Downloading dependencies
Installing Alamofire (4.7.3)
Installing Firebase 5.4.0
Installing FirebaseAnalytics (5.0.1)
Using FirebaseCore (5.0.5)
Using FirebaseInstanceID (3.1.1)
Using FirebaseMessaging (3.0.3)
Using GoogleToolboxForMac (2.1.4)
Using Protobuf (3.6.0)
Installing nanopb (0.3.8)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There are 3 dependencies from the Podfile and 9 total pods installed.
 
[!] Automatically assigning platform `ios` with version `9.3` on target `project` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.

Alamofire 파일 업로드, 결과 JSON 파싱

출력 : swift3 - upload image to server using Alamofire - Stack Overflow, ios - How to parse JSON response from Alamofire API in Swift? - Stack Overflow

        Alamofire.upload(multipartFormData: { (multipartFormData) in
            /*
            for (key, value) in parameters {
                multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
            }
            */
            multipartFormData.append("\(jsonString)".data(using: String.Encoding.utf8)!, withName: "json_str")
            
            /*
            if let data = imageData{
                multipartFormData.append(data, withName: "image", fileName: "image.png", mimeType: "image/png")
            }
            */
            multipartFormData.append(mp4FileUrl, withName: "test.mp4")
            
        }, usingThreshold: UInt64.init(), to: self.upload_url, method: .post, headers: headers) { (result) in
            switch result{
            case .success(let upload, _, _):
                upload.responseJSON { response in
                    print("Succesfully uploaded")
                    if let err = response.error {
                        print(err)
                        onCompletion?(nil, err)
                        return
                    }
                    if let result = response.result.value {
                        let JSON = result as! NSDictionary
                        print(JSON)
                        onCompletion?(JSON, nil)
                    }
                }
            case .failure(let error):
                print("Error in upload: \(error.localizedDescription)")
                onCompletion?(nil, error)
            }
        }

Timer, String format

출처 : ios - Swift - Update/Refresh Label that Displays Time - Stack Overflow

    let movieOutput = AVCaptureMovieFileOutput()
    var durationTimer: Timer?

    //MARK:- Setup Camera
    func setupSession() -> Bool {
        
        //captureSession.sessionPreset = AVCaptureSessionPresetHigh
        //1080
        captureSession.sessionPreset = AVCaptureSession.Preset.hd1920x1080
        
        // Setup Camera
        // 생략
        // Setup Microphone
        // 생략
 
        // 녹화 시간 제한
        movieOutput.maxRecordedDuration = CMTimeMake(300, 1)
        
        return true
    }

    @IBAction func startRecording() {

        if movieOutput.isRecording == false {
        
// ... 생략 ...
            
            self.seconds = 0
            self.durationTimer = Timer(timeInterval: 1.0, target: self, selector: #selector(self.refreshDurationLabel), userInfo: nil, repeats: true)
            RunLoop.current.add(self.durationTimer!, forMode: RunLoopMode.commonModes)
            self.durationTimer?.fire()
        } else {
            self.durationTimer?.invalidate()
            self.durationTimer = nil
            self.seconds = 0
            //self.durationTxt.text = secondsToFormatTimeFull(second: 0)
            stopRecording()
        }
    }

    func secondsToFormatTimeFull(second: Int)->String {
        let sec : Int = second % 60
        let min : Int = second / 60
        return String(format : "%02d:%02d", min, sec)
    }

    @objc func refreshDurationLabel() {
        self.durationTxt.text = secondsToFormatTimeFull(second: self.seconds)
        seconds = seconds + 1
    }

연락처 조회, 선택, WebView 자바스크립트 호출(evaluateJavaScript)

출처 : ContactsUISample/ViewController.swift at master · koogawa/ContactsUISample · GitHub
[SWIFT] 주소록에 저장된 데이터 불러오기 - Things take time - 티스토리

import Contacts
import ContactsUI

class WebViewBase : UIViewController, CNContactPickerDelegate {

    func native_show_contacts() {
        let pickerViewController = CNContactPickerViewController()
        pickerViewController.delegate = self
        
        // Display only a person's phone, email, and postal address
        let displayedItems = [CNContactPhoneNumbersKey, CNContactEmailAddressesKey, CNContactPostalAddressesKey]
        pickerViewController.displayedPropertyKeys = displayedItems
        
        // Show the picker
        self.present(pickerViewController, animated: true, completion: nil)
    }

    // MARK: CNContactPickerDelegate methods
    // Called when a property of the contact has been selected by the user.
    func contactPicker(picker: CNContactPickerViewController, didSelectContactProperty contactProperty: CNContactProperty) {
        //
    }
    
    func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
        // You can fetch selected name and number in the following way
        
        // user name
        let userName:String = contact.givenName
        
        let name = contact.familyName + contact.givenName
        //print(name)
        
        var primaryPhoneNumberStr:String = ""
        
        if (!contact.phoneNumbers.isEmpty) {
            // user phone number
            let userPhoneNumbers:[CNLabeledValue<cnphonenumber>] = contact.phoneNumbers
            let firstPhoneNumber:CNPhoneNumber = userPhoneNumbers[0].value
            
            
            // user phone number string
            primaryPhoneNumberStr = firstPhoneNumber.stringValue
        }
        
        //print("phonenum = \(primaryPhoneNumberStr)")
        
        webView.evaluateJavaScript("setContract('\(name)', '\(primaryPhoneNumberStr)')")
    }
    
    // Called when the user taps Cancel.
    func contactPickerDidCancel(picker: CNContactPickerViewController) {
        //
    }
}

jni

Programming/Java 2018.08.25 23:07 Posted by 파란크리스마스

출처

py_pwm.h

typedef struct
{
    //PyObject_HEAD
    unsigned int gpio;
    float freq;
    float dutycycle;
} PWMObject;

int PWM_init(PWMObject *self, int channel, float frequency);
void PWM_start(PWMObject *self, float dutycycle);
int PWM_ChangeDutyCycle(PWMObject *self, float dutycycle);

PWMObject.java

package com.pi4j.wiringpi;

public class PWMObject {

	public int gpio;
	public float freq;
	public float dutycycle;

	public PWMObject() {

	}

	public int getGpio() {
		return gpio;
	}

	public void setGpio(int gpio) {
		this.gpio = gpio;
	}

	public float getFreq() {
		return freq;
	}

	public void setFreq(float freq) {
		this.freq = freq;
	}

	public float getDutycycle() {
		return dutycycle;
	}

	public void setDutycycle(float dutycycle) {
		this.dutycycle = dutycycle;
	}

}

com_pi4j_wiringpi_ASUSGpio.h

#include <jni.h>
/* Header for class com_pi4j_wiringpi_ASUSGpio */

#ifndef _Included_com_pi4j_wiringpi_ASUSGpio
#define _Included_com_pi4j_wiringpi_ASUSGpio
#ifdef __cplusplus
extern "C" {
#endif

#undef com_pi4j_wiringpi_ASUSGpio_ASUS
#define com_pi4j_wiringpi_ASUSGpio_ASUS 13L
#undef com_pi4j_wiringpi_ASUSGpio_OUTPUT
#define com_pi4j_wiringpi_ASUSGpio_OUTPUT 1L

JNIEXPORT jint JNICALL Java_com_pi4j_wiringpi_ASUSGpio_pySetmode
  (JNIEnv *, jclass, jint);

JNIEXPORT jint JNICALL Java_com_pi4j_wiringpi_ASUSGpio_pySetupChannel
  (JNIEnv *, jclass, jint, jint);

JNIEXPORT jobject JNICALL Java_com_pi4j_wiringpi_ASUSGpio_pwmInit
  (JNIEnv *, jclass, jint, jfloat);

JNIEXPORT void JNICALL Java_com_pi4j_wiringpi_ASUSGpio_pwmStart
  (JNIEnv *, jclass, jobject, jfloat);

JNIEXPORT jint JNICALL Java_com_pi4j_wiringpi_ASUSGpio_pwmChangeDutyCycle
  (JNIEnv *, jclass, jobject, jfloat);

#ifdef __cplusplus
}
#endif
#endif

com_pi4j_wiringpi_ASUSGpio.c

#include <stdio.h>
#include <jni.h>
#include <wiringPi.h>
#include <RKIO.h>
#include <wiringTB.h>
#include <constants.h>
#include <common.h>
#include <c_gpio.h>
#include <py_gpio.h>
#include <py_pwm.h>
#include "com_pi4j_wiringpi_ASUSGpio.h"

void setPwmObject(JNIEnv *env, jclass targetClass, jobject newObject, PWMObject pwm) {
	
	jfieldID fid;
	
	// JniObject 객체의 intField 필드값 설정
	fid = (*env)->GetFieldID(env, targetClass, "gpio", "I");
	(*env)->SetIntField(env, newObject, fid, pwm.gpio);
	
	// JniObject 객체의 intField 필드값 설정
	fid = (*env)->GetFieldID(env, targetClass, "freq", "F");
	(*env)->SetFloatField(env, newObject, fid, pwm.freq);
	
	// JniObject 객체의 intField 필드값 설정
	fid = (*env)->GetFieldID(env, targetClass, "dutycycle", "F");
	(*env)->SetFloatField(env, newObject, fid, pwm.dutycycle);
}

void getPwmObject(JNIEnv *env, jclass targetClass, jobject newObject, PWMObject *pwm) {
	
	jfieldID fid;
	
	// JniObject 객체의 intField 필드값 설정
	fid = (*env)->GetFieldID(env, targetClass, "gpio", "I");
	pwm->gpio = (*env)->GetIntField(env, newObject, fid);
	
	// JniObject 객체의 intField 필드값 설정
	fid = (*env)->GetFieldID(env, targetClass, "freq", "F");
	pwm->freq = (*env)->GetFloatField(env, newObject, fid);
	
	// JniObject 객체의 intField 필드값 설정
	fid = (*env)->GetFieldID(env, targetClass, "dutycycle", "F");
	pwm->dutycycle = (*env)->GetFloatField(env, newObject, fid);
}

JNIEXPORT jint JNICALL Java_com_pi4j_wiringpi_ASUSGpio_pySetmode
(JNIEnv *env, jclass obj, jint new_mode)
{
	return py_setmode(new_mode);
}

JNIEXPORT jint JNICALL Java_com_pi4j_wiringpi_ASUSGpio_pySetupChannel
(JNIEnv *env, jclass obj, jint channel, jint direction)
{
	return py_setup_channel(channel, direction);
}

JNIEXPORT jobject JNICALL Java_com_pi4j_wiringpi_ASUSGpio_pwmInit
(JNIEnv *env, jclass obj, jint channel, jfloat frequency)
{
	//pwm = GPIO.PWM(myservo,50) # 50hz yani 20mslik periyod
	PWMObject pwm;
	PWM_init(&pwm, channel, frequency);
	//printf("pwm.gpio = %d\n", pwm.gpio);
	
	//
	jclass targetClass = (*env)->FindClass(env, "com/pi4j/wiringpi/PWMObject");
	
	// 생성자 찾기
	jmethodID mid = (*env)->GetMethodID(env, targetClass, "<init>", "()V");

	// 객체 생성(객체 레퍼런스 반환)
	jobject newObject = (*env)->NewObject(env, targetClass, mid, "()V");
	
	setPwmObject(env, targetClass, newObject, pwm);
	
	return newObject;
}

JNIEXPORT void JNICALL Java_com_pi4j_wiringpi_ASUSGpio_pwmStart
(JNIEnv *env, jclass obj, jobject thiz, jfloat dutycycle)
{
	PWMObject pwm;
	
	//
	jclass targetClass = (*env)->FindClass(env, "com/pi4j/wiringpi/PWMObject");
	getPwmObject(env, targetClass, thiz, &pwm);
	
	PWM_start(&pwm, dutycycle);
	setPwmObject(env, targetClass, thiz, pwm);
}

JNIEXPORT jint JNICALL Java_com_pi4j_wiringpi_ASUSGpio_pwmChangeDutyCycle
(JNIEnv *env, jclass obj, jobject thiz, jfloat dutycycle)
{
	PWMObject pwm;
	
	//
	jclass targetClass = (*env)->FindClass(env, "com/pi4j/wiringpi/PWMObject");
	getPwmObject(env, targetClass, thiz, &pwm);
	
	int result = PWM_ChangeDutyCycle(&pwm, dutycycle);
	setPwmObject(env, targetClass, thiz, pwm);
	
	return result;
}

ASUSGpio.java

package com.pi4j.wiringpi;

import com.pi4j.util.NativeLibraryLoader;

public class ASUSGpio {

  // private constructor
  private ASUSGpio()  {
    // forbid object construction
  }

  public static final int ASUS = 13;

  public static final int OUTPUT = 1;

  static {
    // Load the platform library
    NativeLibraryLoader.load("libpi4j.so");
  }

  public static native int pySetmode(int new_mode);

  public static native int pySetupChannel(int channel, int direction);

  public static native PWMObject pwmInit(int channel, float frequency);

  public static native void pwmStart(PWMObject self, float dutycycle);

  public static native int pwmChangeDutyCycle(PWMObject self, float dutycycle);
}

빌드

$ export SimulatedPlatform="TinkerBoard GPIO Provider"
$ mvn clean install

-----------------

hml-equation-parser 패키지를 설치

$ sudo apt-get install pandoc
$ sudo pip3 install typing
$ sudo pip3 install hml_equation_parser

jpserve 패키지를 설치

$ sudo pip install jpserve

jython 설치

$ java -jar jython-installer-2.7.0.jar

Tinker Board S : Pi Camera 2.1 적용 Python 얼굴인식

OS/Tinker Board S 2018.08.24 00:45 Posted by 파란크리스마스

출처

Pi카메라 2.1로 영상을 받을 경우 녹색빛으로 보이는데, 네이버카페에서 aciddust님이 올려주신 white_balance.py 소스를 가지고, 파이썬 예제의 얼굴인식 소스에서 카메라로 받은 이미지를 white_balance 작업 후 진행되도록 수정했습니다. 완벽하게 원하는 수준의 영상을 얻을 수는 없었지만, 이전 보다는 좋은 영상을 얻을 수 있었습니다.

다만 S/W로 보정하다보니 조금 느려진 기분이 들고, USB 카메라보다 화질은 아직 떨어 지고, 전용 카메라가 도착하며 다시 시도 해보겠습니다. 지금은 USB 카메라로 하는것이 좋은 결과를 얻을 수 있습니다.

소스 복사

$ mkdir facedetect
$ cd facedetect
$ cp /usr/local/share/OpenCV/samples/python/facedetect.py .
$ cp /usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml .
$ cp /usr/local/share/OpenCV/haarcascades/haarcascade_eye_tree_eyeglasses.xml .

facedetect.py 소스

white_balance 참조

# bluexmas
import white_balance as wb

카메라로 받은 이미지 정보를 white_balance 적용

        # bluexmas
        img = wb.retinex_adjust(img)
        img = wb.gray_world(img)
        img = wb.gimp(img,0.05)

facedetect.py 전체 소스

#!/usr/bin/env python

'''
face detection using haar cascades

USAGE:
    facedetect.py [--cascade ] [--nested-cascade ] []
'''

# Python 2/3 compatibility
from __future__ import print_function

import numpy as np
import cv2

# local modules
from video import create_capture
from common import clock, draw_str

# bluexmas
import white_balance as wb


def detect(img, cascade):
    rects = cascade.detectMultiScale(img, scaleFactor=1.3, minNeighbors=4, minSize=(30, 30),
                                     flags=cv2.CASCADE_SCALE_IMAGE)
    if len(rects) == 0:
        return []
    rects[:,2:] += rects[:,:2]
    return rects

def draw_rects(img, rects, color):
    for x1, y1, x2, y2 in rects:
        cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)

if __name__ == '__main__':
    import sys, getopt
    print(__doc__)

    args, video_src = getopt.getopt(sys.argv[1:], '', ['cascade=', 'nested-cascade='])
    try:
        video_src = video_src[0]
    except:
        video_src = 0
    args = dict(args)
    cascade_fn = args.get('--cascade', "../../data/haarcascades/haarcascade_frontalface_alt.xml")
    nested_fn  = args.get('--nested-cascade', "../../data/haarcascades/haarcascade_eye.xml")

    cascade = cv2.CascadeClassifier(cascade_fn)
    nested = cv2.CascadeClassifier(nested_fn)

    cam = create_capture(video_src, fallback='synth:bg=../data/lena.jpg:noise=0.05')

    while True:
        ret, img = cam.read()
        
        # bluexmas
        img = wb.retinex_adjust(img)
        img = wb.gray_world(img)
        img = wb.gimp(img,0.05)
        
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        gray = cv2.equalizeHist(gray)

        t = clock()
        rects = detect(gray, cascade)
        vis = img.copy()
        draw_rects(vis, rects, (0, 255, 0))
        if not nested.empty():
            for x1, y1, x2, y2 in rects:
                roi = gray[y1:y2, x1:x2]
                vis_roi = vis[y1:y2, x1:x2]
                subrects = detect(roi.copy(), nested)
                draw_rects(vis_roi, subrects, (255, 0, 0))
        dt = clock() - t

        draw_str(vis, (20, 20), 'time: %.1f ms' % (dt*1000))
        
        cv2.imshow('facedetect', vis)

        if cv2.waitKey(5) == 27:
            break
    cv2.destroyAllWindows()

소스 파일

facedetect.tar

실행

$ python3 facedetect.py --cascade haarcascade_frontalface_alt.xml --nested-cascade haarcascade_eye_tree_eyeglasses.xml /dev/video0

실행 결과

Linux에 Maven 설치하기

OS/Linux 2018.08.19 11:51 Posted by 파란크리스마스

출처

설치 : 다운로드, 압축해제, 디렉토리이동

$ wget http://mirror.apache-kr.org/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz
$ tar xvf apache-maven-3.5.4-bin.tar.gz
$ sudo mv apache-maven-3.5.4 /opt/
$ sudo ln -s /opt/apache-maven-3.5.4/ /opt/maven

환경설정 : /etc/profile 내용 추가

$ sudo vi /etc/profile

내용추가

export M2_HOME=/opt/maven
export PATH=$PATH:$M2_HOME/bin

profile 실행

$ source /etc/profile

Tinker Board S : 자바를 이용한 GPIO LED 제어

OS/Tinker Board S 2018.08.19 00:59 Posted by 파란크리스마스

출처

Tinker Board S : 자바를 이용한 GPIO LED 제어

저의 경우 자바로 GPIO 제어하는 것이 좋은 점은 서버 구성하기 편하기 때문인데, 라즈베리파이의 경우 pi4j가 잘 되어 있지만, 아직 팅커보드는 pi4j가 지원하지 않아, 다른 라이브러리를 찾아보니 diozero 라이브러리가 gifhub에 있었고, 몇가지 설치 방법이 pi4j 보다 어려움이 있어서 정리 해보았습니다. 

우선 Device I/O library 소스를 다운 받아서 설치하고, GPIO 번호 설정도 pi4j와 달라서 고생을 했는데, GPIO 표에서 GPIO.ASUS를 사용하니 잘 되었습니다.

Tinker Board : GPIO

이미지 출처 : GPIO - Tinker Board Wiki

jdk 설치

$ sudo apt-get install default-jdk

Device I/O library 설치

$ sudo apt-get install mercurial
$ hg clone http://hg.openjdk.java.net/dio/dev
$ cd dev/
$ export PI_TOOLS=/usr
$ export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-armhf
$ export CROSS_TOOL=/usr/bin/
$ make
$ cd ..
$ sudo mv ~/dev /opt/dio
$ sudo chown -R root.root /opt/dio
$ sudo cp -r /opt/dio/build/deviceio/lib/* $JAVA_HOME/jre/lib

diozero 다운로드

Diozero JAR 라이브러리가 압축된 ZIP파일을 Google 드라이브에서 다운로드

diozero 압축해제

$ unzip diozero-distribution-0.11-SNAPSHOT-bin.zip
$ cd diozero-distribution-0.11-SNAPSHOT/

배선

LED+ : 3번핀 (GPIO.ASUS : 252)
LED- : 9번핀 (GND)

TestLEDMain.java

import org.pmw.tinylog.Logger;

import com.diozero.devices.LED;
import com.diozero.util.BoardInfo;
import com.diozero.util.DeviceFactoryHelper;
import com.diozero.util.RuntimeIOException;
import com.diozero.util.SleepUtil;
import com.diozero.util.SystemInfo;

public class TestLEDMain {

	public static void main(String[] args) throws Exception {
		String hardware = "Rockchip (Device Tree)";
		String revision = "0000";
		BoardInfo board_info = SystemInfo.lookupLocalBoardInfo(hardware, revision, null);
		System.out.println(hardware + "/" + revision + ": " + board_info);

		if (args.length < 1) {
			Logger.error("Usage: {} <gpio>", TestLEDMain.class.getName());
			System.exit(1);
		}
		test(board_info, Integer.parseInt(args[0]));
	}
	
	public static void test(BoardInfo board_info, int pin) {
		
		try (LED led = new LED(pin)) {
			Logger.info("On");
			led.on();
			SleepUtil.sleepSeconds(1);
			Logger.info("Off");
			led.off();
			SleepUtil.sleepSeconds(1);
			Logger.info("Toggle");
			led.toggle();
			SleepUtil.sleepSeconds(1);
			Logger.info("Toggle");
			led.toggle();
			SleepUtil.sleepSeconds(1);
			
			Logger.info("Blink 10 times");
			led.blink(0.5f, 0.5f, 10, false);
			
			Logger.info("Done");
		} catch (RuntimeIOException e) {
			Logger.error(e, "Error: {}", e);
		} finally {
			// Required if there are non-daemon threads that will prevent the
			// built-in clean-up routines from running
			DeviceFactoryHelper.getNativeDeviceFactory().close();
		}
	}
}

TestLEDMain 실행

실행시 LED+ 연결된 3번핀의 GPIO.ASUS 번호 252를 인자로 전달

TestLEDMain.java

$ sudo java -cp .:tinylog-1.3.5.jar:commons-math3-3.6.1.jar:dio.jar:pigpioj-java-2.2.jar TestLEDMain 252
Rockchip (Device Tree)/0000: BoardInfo [make=Asus, model=Tinker Board, memory=2048, libraryPath=tinkerboard, adcVRef=1.8]
03:40:41.377 [main] DEBUG com.diozero.util.DeviceFactoryHelper.init - Using native device factory class JdkDeviceIoDeviceFactory
03:40:41.443 [main] INFO TestLEDMain.test - On
03:40:41.482 [main] DEBUG com.diozero.util.LibraryLoader.loadLibrary - Loaded library 'diozero-system-utils' from classpath
03:40:42.485 [main] INFO TestLEDMain.test - Off
03:40:43.486 [main] INFO TestLEDMain.test - Toggle
03:40:44.488 [main] INFO TestLEDMain.test - Toggle
03:40:45.489 [main] INFO TestLEDMain.test - Blink 10 times
03:40:55.495 [main] INFO TestLEDMain.test - Done
03:40:55.495 [main] DEBUG com.diozero.api.DigitalOutputDevice.close - close()
03:40:55.496 [main] DEBUG com.diozero.internal.provider.AbstractDevice.close - close(), key=Native-GPIO-252
03:40:55.497 [main] DEBUG com.diozero.internal.provider.jdkdio11.JdkDeviceIoGpioOutputDevice.closeDevice - closeDevice()
03:40:55.498 [main] DEBUG com.diozero.internal.DeviceStates.closed - closed(Native-GPIO-252)
03:40:55.502 [main] DEBUG com.diozero.internal.provider.AbstractDeviceFactory.close - close()
03:40:55.503 [main] DEBUG com.diozero.internal.DeviceStates.closeAll - closeAll()
03:40:55.531 [DIO-Zero Shutdown Handler] DEBUG com.diozero.util.ShutdownHandlerThread.run - Shutdown handler running
03:40:55.532 [DIO-Zero Shutdown Handler] DEBUG com.diozero.internal.provider.AbstractDeviceFactory.close - close()
03:40:55.533 [DIO-Zero Shutdown Handler] DEBUG com.diozero.internal.DeviceStates.closeAll - closeAll()
03:40:55.533 [DIO-Zero Shutdown Handler] DEBUG com.diozero.util.ShutdownHandlerThread.run - Shutdown handler finished

실행결과

Tinker Board S : mjpg-streamer (동영상 스트리밍)

OS/Tinker Board S 2018.08.18 22:40 Posted by 파란크리스마스

출처

MJPG streamer 컴파일 관련 라이브러리 설치

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install cmake libjpeg-dev imagemagick libv4l-dev
$ sudo apt-get install subversion libjpeg62-turbo-dev imagemagick

MJPG streamer 소스 다운로드, 컴파일, 설치

$ svn co https://svn.code.sf.net/p/mjpg-streamer/code/
$ cd code/mjpg-streamer
$ make
$ sudo make install
install --mode=755 mjpg_streamer /usr/local/bin
install --mode=644 input_uvc.so output_file.so output_udp.so output_http.so input_testpicture.so input_file.so /usr/local/lib/
install --mode=755 -d /usr/local/www
install --mode=644 -D www/* /usr/local/www

MJPG Streamer 실행

$ cd ~/code/mjpg-streamer
$ ./mjpg_streamer -i "./input_uvc.so -y" -o "./output_http.so -w ./www"
MJPG Streamer Version: svn rev: 3:172
 i: Using V4L2 device.: /dev/video0
 i: Desired Resolution: 640 x 480
 i: Frames Per Second.: 5
 i: Format............: YUV
 i: JPEG Quality......: 80
Adding control for Pan (relative)
UVCIOC_CTRL_ADD - Error: Inappropriate ioctl for device
Adding control for Tilt (relative)
UVCIOC_CTRL_ADD - Error: Inappropriate ioctl for device
Adding control for Pan Reset
UVCIOC_CTRL_ADD - Error: Inappropriate ioctl for device
Adding control for Tilt Reset
UVCIOC_CTRL_ADD - Error: Inappropriate ioctl for device
Adding control for Pan/tilt Reset
UVCIOC_CTRL_ADD - Error: Inappropriate ioctl for device
Adding control for Focus (absolute)
UVCIOC_CTRL_ADD - Error: Inappropriate ioctl for device
mapping control for Pan (relative)
UVCIOC_CTRL_MAP - Error: Inappropriate ioctl for device
mapping control for Tilt (relative)
UVCIOC_CTRL_MAP - Error: Inappropriate ioctl for device
mapping control for Pan Reset
UVCIOC_CTRL_MAP - Error: Inappropriate ioctl for device
mapping control for Tilt Reset
UVCIOC_CTRL_MAP - Error: Inappropriate ioctl for device
mapping control for Pan/tilt Reset
UVCIOC_CTRL_MAP - Error: Inappropriate ioctl for device
mapping control for Focus (absolute)
UVCIOC_CTRL_MAP - Error: Inappropriate ioctl for device
mapping control for LED1 Mode
UVCIOC_CTRL_MAP - Error: Inappropriate ioctl for device
mapping control for LED1 Frequency
UVCIOC_CTRL_MAP - Error: Inappropriate ioctl for device
mapping control for Disable video processing
UVCIOC_CTRL_MAP - Error: Inappropriate ioctl for device
mapping control for Raw bits per pixel
UVCIOC_CTRL_MAP - Error: Inappropriate ioctl for device
 o: www-folder-path...: ./www/
 o: HTTP TCP port.....: 8080
 o: username:password.: disabled
 o: commands..........: enabled

확인



 

티스토리 툴바