Tinker Board : 한글 입력기 설치

OS/Tinker Board 2018.09.30 18:00 Posted by 파란크리스마스

출처

ip 확인

$ ip addr | grep inet
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
    inet 192.168.137.101/24 brd 192.168.137.255 scope global dynamic eth0
    inet 192.168.137.145/24 brd 192.168.137.255 scope global secondary eth0
    inet6 fe80::b848:f27d:8127:389/64 scope link

eMMC에 OS 설치

$ sudo dd if=20180622-tinker-board-linaro-stretch-alip-v2.0.7.img of=/dev/mmcblk1 bs=4MB status=progress conv=sync
3096000000 bytes (3.1 GB, 2.9 GiB) copied, 70.0279 s, 44.2 MB/s 
782+1 records in
783+0 records out
3132000000 bytes (3.1 GB, 2.9 GiB) copied, 71.9111 s, 43.6 MB/s

리눅스 정보 확인

$ grep . /etc/*-release
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
NAME="Debian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

OS 업데이트

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

Tinker Board 환경설정

$ sudo tinker-config

용량 확장

locale 변경

재부팅후 폴더 이름 변경 설정 팝업

한글폰트 설치 (나눔폰트 - nanum)

$ sudo apt install fonts-nanum fonts-nanum-coding fonts-nanum-extra

한글 입력기(nabi, imhangul) 설치

$ sudo apt-get install nabi imhangul-gtk2 imhangul-gtk3 im-config zenity

입력기 설정

$ im-config -n hangul

입력기 환경설정

$ im-config

한글입력예

환경설정

$ cat .xinputrc 
## im-config(8) generated on Thu, 11 Oct 2018 06:17:20 +0000
run_im hangul
## im-config signature: ef7d60ee7a0f5fd446ce389716f52467  -
 
export XIM=nabi
export XIM_ARGS=
export XIM_PROGRAM="nabi"
export XMODIFIERS="@im=nabi"
export GTK_IM_MODULE=xim
export QT_IM_MODULE=xim

내용 추가

export XIM=nabi
export XIM_ARGS=
export XIM_PROGRAM="nabi"
export XMODIFIERS="@im=nabi"
export GTK_IM_MODULE=xim

Tinker Board : CodeTyphone

OS/Tinker Board 2018.09.30 03:56 Posted by 파란크리스마스

출처

컴파일하는 동안 ‘out of memory’을 방지하기 위해 스왑 파일을 활성화

$ sudo apt-get install -y dphys-swapfile

dphys-swapfile 서비스 실행

$ sudo /etc/init.d/dphys-swapfile start
Starting dphys-swapfile (via systemctl): dphys-swapfile.service==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to start 'dphys-swapfile.service'.
Authenticating as: linaro,,, (linaro)
==== AUTHENTICATION COMPLETE ===

"sudo" 루트 권한 부여

$ sudo vi /etc/sudoers

linaro ALL=(ALL) NOPASSWD: ALL

CodeTyphon 다운로드

$  wget http://www.pilotlogic.com/codetyphon/zips/CodeTyphonIns.zip

CodeTyphon 압축 해제

$ unzip CodeTyphonIns.zip

CodeTyphon 설치 스크립트 실행

$ cd CodeTyphonIns/
$ ./install.sh 
 
====================================================
             CodeTyphon Studio 
            Version 6.50 (GEN 6)
   Installation for: Linux-Solaris-FreeBSD-MacOS
====================================================
 
   0) Install CodeTyphon Studio
 
   9) Exit
 
>>> Select an action (press 0..9 key): 0

0번 선택 ( 0) Install System Libraries )

====================================================
  CodeTyphon Studio 6.50 Setup for Linux32
   Settings: Platform=gtk2  Multiarch Mode=0
====================================================
   
   0) Install System Libraries
   1) Run CodeTyphon Center (CTC)
   
     11) -- Platform (widget) Setup
     12) -- Multi-Architecture Setup
   
   3) Remove FreePascal
   4) Remove and Build FreePascal
   
   5) Remove Typhon IDE
   6) Remove and Build Typhon IDE
   
   7) Remove ALL
   8) Remove and Build ALL
   
   9) EXIT
   
>>> Select an action (press 0..9 key): 0

8번 선택 ( 8) Remove and Build ALL )

====================================================
  CodeTyphon Studio 6.50 Setup for Linux32
   Settings: Platform=gtk2  Multiarch Mode=0
====================================================
   
   0) Install System Libraries
   1) Run CodeTyphon Center (CTC)
   
     11) -- Platform (widget) Setup
     12) -- Multi-Architecture Setup
   
   3) Remove FreePascal
   4) Remove and Build FreePascal
   
   5) Remove Typhon IDE
   6) Remove and Build Typhon IDE
   
   7) Remove ALL
   8) Remove and Build ALL
   
   9) EXIT
   
>>> Select an action (press 0..9 key): 8

9번 선택 ( 9) EXIT )

====================================================
  CodeTyphon Studio 6.50 Setup for Linux32
   Settings: Platform=gtk2  Multiarch Mode=0
====================================================
   
   0) Install System Libraries
   1) Run CodeTyphon Center (CTC)
   
     11) -- Platform (widget) Setup
     12) -- Multi-Architecture Setup
   
   3) Remove FreePascal
   4) Remove and Build FreePascal
   
   5) Remove Typhon IDE
   6) Remove and Build Typhon IDE
   
   7) Remove ALL
   8) Remove and Build ALL
   
   9) EXIT
   
>>> Select an action (press 0..9 key): 9

실행

출처

omv-extras 설치 (root 계정으로 설치)

$ su - root
# wget -O - http://omv-extras.org/install | bash

OMV-Extras 추가 확인

[플러그인] 목록에서 openmediavault-transmissionbt 선택하고 [설치] 버튼 선택

공유 폴더 추가

공유 폴더는 omv 설치시 생성된 debian-transmission 계정으로 생성된 폴더를 지정

[서비스] > [BitTorrent] > [설정] 화면에서 활성화하고 [저장] 버튼 선택하여 저장

[RPC] 화면에서 활성화하고 [저장] 버튼 선택하여 저장하고, [Show] 버튼을 선택하려 클라이언트 화면 보기 

토렌토 클라이언트 Web 화면

출처

Orange Pi Zero Plus (H5) : Orange Pi NAS Expansion Board

Orange Pi Zero Plus (H5)

Orange Pi NAS Expansion Board

3D 프린터로 출력한 케이스

  

케이스 적용

  

  

one.sh - omv 패키지 리파지스토리에 등록

cat <<EOF >> /etc/apt/sources.list.d/openmediavault.list
deb http://packages.openmediavault.org/public arrakis main
# deb http://downloads.sourceforge.net/project/openmediavault/packages arrakis main
## Uncomment the following line to add software from the proposed repository.
# deb http://packages.openmediavault.org/public arrakis-proposed main
# deb http://downloads.sourceforge.net/project/openmediavault/packages arrakis-proposed main
## This software is not part of OpenMediaVault, but is offered by third-party
## developers as a service to OpenMediaVault users.
# deb http://packages.openmediavault.org/public arrakis partner
# deb http://downloads.sourceforge.net/project/openmediavault/packages arrakis partner
EOF

two.sh - openmediavault 4 (Arrakis) 패키지 설치

export LANG=C
export DEBIAN_FRONTEND=noninteractive
export APT_LISTCHANGES_FRONTEND=none
apt-get update
apt-get --allow-unauthenticated install openmediavault-keyring
apt-get update
apt-get --yes --auto-remove --show-upgraded \
    --allow-downgrades --allow-change-held-packages \
    --no-install-recommends \
    --option Dpkg::Options::="--force-confdef" \
    --option DPkg::Options::="--force-confold" \
    install postfix openmediavault
# Initialize the system and database.
omv-initsystem

설치 스크립트(one.sh, two.sh) 실행가능하도록 모드 변경

$ chmod a+x one.sh two.sh

설치 스크립트(one.sh, two.sh) 실행

$ sudo ./one.sh
$ sudo ./two.sh

관리 페이지 접속

기본계정과 암호 - root/openmediavault

NAS에 장착한 msata ssd 확인

NAS에 장착한 msata ssd 파티션(파일 시스템) 추가

[파일 시스템]메뉴에서 [생성] 버튼을 선택하여 파일 시스템 생성 

파일 시스템 생성

파일 시스템 생성 완료

추가된 파티션 확인

sqlite

Programming/안드로이드 2018.09.29 01:03 Posted by 파란크리스마스

출처

DBManager.java

package com.bluexmas.common;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBManager extends SQLiteOpenHelper {

    private static String TAG = DBManager.class.getName();

    // Database 버전
    public static final int DB_VERSION = 12;
    // Database 이름 (SQLite 파일명)
    public static final String DB_NAME = "bluexmas.db";

    // DBManager 객체 - 한번만 객체가 생성되도록 static 으로 변수 선언 : singleton 패턴
    private static DBManager instance = null;

    private Context context;

    // private 생성자 : singleton 패턴
    private DBManager(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        this.context = context;
    }

    // DBManager 객체 반환 : singleton 패턴
    public static DBManager getInstance(Context context) {
        if (instance == null)
            instance = new DBManager(context);
        return instance;
    }

    public Context getContext() {
        return this.context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // 테이블 생성 관련 SQL 스크립트 실행
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // DB_VERSION 버전이 올라 가면 변경될 SQL 스크립트 실행
    }
}

VideoEntity.java

package com.bluexmas.common;

public class VideoEntity {

    public static final String TABLE_NAME = "video_info";

    public static final String COLUMN_NAME_MEDIA_ID = "v_id";
    public static final String COLUMN_NAME_TYPECODE = "type_code";
    public static final String COLUMN_NAME_FILEPATH = "path";
    public static final String COLUMN_NAME_REGDATE = "regdate";

    public String getTableName() {
        return TABLE_NAME;
    }

    public String genCreateSQL() {
        return "CREATE TABLE "+this.getTableName()+"( "
                + COLUMN_NAME_MEDIA_ID+" INTEGER PRIMARY KEY AUTOINCREMENT, "
                + COLUMN_NAME_TYPECODE+" CHAR(2) NOT NULL, "
                + COLUMN_NAME_FILEPATH+" TEXT NOT NULL, "
                + COLUMN_NAME_REGDATE+" TEXT NOT NULL "
                + ");";
    }
}

DBManager.java

package com.bluexmas.common;

public class DBManager extends SQLiteOpenHelper {

    //
    private static String TAG = DBManager.class.getName();

    // Database 버전
    public static final int DB_VERSION = 12;
    // Database 이름 (SQLite 파일명)
    public static final String DB_NAME = "bluexmas.db";

    // DBManager 객체 - 한번만 객체가 생성되도록 static 으로 변수 선언 : singleton 패턴
    private static DBManager instance = null;

    private Context context;

    private VideoEntity videoEntity = null;

    // private 생성자 : singleton 패턴
    private DBManager(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        this.context = context;

        // VideoEntity 생체 생성
        this.videoEntity = new VideoEntity();
    }

    // DBManager 객체 반환 : singleton 패턴
    public static DBManager getInstance(Context context) {
        if (instance == null)
            instance = new DBManager(context);
        return instance;
    }

    public Context getContext() {
        return context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // 테이블 생성 관련 SQL 스크립트 실행

        // VideoEntity 테이블 생성
        db.execSQL(this.videoEntity.genCreateSQL());
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // DB_VERSION 버전이 올라 가면 변경될 SQL 스크립트 실행
    }

    // 비디오 정보 추가 (레코드 추가)
    public int addVideo(String type_code, String path) {
        if (path == null)
            return;

        // DB 객체 가져오기
        SQLiteDatabase db = this.getWritableDatabase();

        //
        ContentValues values = new ContentValues();
        values.put(this.videoEntity.COLUMN_NAME_TYPECODE, type_code);
        values.put(this.videoEntity.COLUMN_NAME_FILEPATH, path);
        values.put(this.videoEntity.COLUMN_NAME_REGDATE, "-");

        // 데이터 삽입
        long newRowId = db.insert(this.videoEntity.getTableName(), null, values);

        return getLastID(this.videoEntity.getTableName());
    }

    /**
     * 마지막 추가한 ID 구하기
     * @param table_name 테이블 이름
     * @return ID
     */
    public int getLastID(String table_name) {
        // DB 객체 가져오기
        SQLiteDatabase db = this.getWritableDatabase();

        final String query = "SELECT last_insert_rowid() FROM "+ table_name;
        Cursor cur = db.rawQuery(query, null);
        cur.moveToFirst();
        int last_id = cur.getInt(0);
        cur.close();
        return last_id;
    }
}



-

Orange Pi Zero Plus (H5) : 원격데스크탑(RDP) 설치

OS/Orange PI 2018.09.29 01:03 Posted by 파란크리스마스

출처

OS 업데이트

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

linux 정보 확인

$ grep . /etc/*armbian-release
## PLEASE DO NOT EDIT THIS FILE
BOARD=orangepizeroplus
BOARD_NAME="Orange Pi Zero Plus"
BOARDFAMILY=sun50iw2
VERSION=5.60
LINUXFAMILY=sunxi64
BRANCH=next
ARCH=arm64
IMAGE_TYPE=stable
BOARD_TYPE=conf
INITRD_ARCH=arm64
KERNEL_IMAGE_TYPE=Image

디스크 용량 확인

$ sudo fdisk -l | grep Disk  
Disk /dev/mmcblk0: 14.5 GiB, 15523119104 bytes, 30318592 sectors
Disklabel type: dos
Disk identifier: 0xc61d9af9
Disk /dev/zram0: 50 MiB, 52428800 bytes, 12800 sectors
Disk /dev/zram1: 60.3 MiB, 63254528 bytes, 15443 sectors
Disk /dev/zram2: 60.3 MiB, 63254528 bytes, 15443 sectors
Disk /dev/zram3: 60.3 MiB, 63254528 bytes, 15443 sectors
Disk /dev/zram4: 60.3 MiB, 63254528 bytes, 15443 sectors

LightDM 설치

$ sudo apt-get -y install xorg lightdm xfce4 tango-icon-theme gnome-icon-theme
$ sudo apt-get install dbus-x11

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.6-1~bpo9+1 100
        100 http://httpredir.debian.org/debian stretch-backports/main arm64 Packages
 *** 0.9.1-9+deb9u3 500
        500 http://httpredir.debian.org/debian stretch/main arm64 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://httpredir.debian.org/debian stretch/main arm64 Packages
        100 /var/lib/dpkg/status

원격데스크탑 접속

출처

안드로이드 부팅 이벤트 받기

BootReceiver,java - 부팅 이벤트를 받은 BroadcastReceiver를 상속받은 클래스 생성

package com.bluexmas.common;

import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;

public class BootReceiver extends BroadcastReceiver {

    private final static String TAG = BootReceiver.class.getSimpleName();

    // BroadcastReceiver를 상속하여 처리 해줍니다.
    @Override
    public void onReceive(final Context context, Intent intent) {
        // TODO Auto-generated method stub
        // 전달 받은 Broadcast의 값을 가져오기
        // androidmanifest.xml에 정의한 인텐트 필터를 받아 올 수 있습니다.
        String action = intent.getAction();
        // 전달된 값이 '부팅완료' 인 경우에만 동작 하도록 조건문을 설정 해줍니다.
        if (action.equals("android.intent.action.BOOT_COMPLETED")) {
            // TODO
            // 부팅 이후 처리해야 코드 작성
            // Ex.서비스 호출, 특정 액티비티 호출등등
            Log.d(TAG, "action = " + action);

            //
            new Handler().postDelayed(new Runnable() {
                // 3초 후에 실행
                @Override public void run() {
                    //Toast.makeText(context, "-- BootReceiver.onReceive", Toast.LENGTH_LONG).show();

                    // BackgroundService
                    Intent serviceLauncher = new Intent(context, BackgroundService.class);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        context.startForegroundService(serviceLauncher);
                    } else {
                        context.startService(serviceLauncher);
                    }
                }
            }, 3000);
        }
    }

    public static boolean isServiceRunning(Context context, Class serviceClass) {
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (serviceClass.getName().equals(service.service.getClassName())) {
                Log.i (TAG,"ServiceRunning? = "+true);
                return true;
            }
        }
        Log.i(TAG,"ServiceRunning? = "+ false);
        return false;
    }
}

AndroidManifest.xml 내용추가

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.bluexmas.main" >

    <!-- 안드로이드 부팅 이벤트 받기 권한 추가 -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:name="com.bluexmas.main.BluexmasApplication"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:largeHeap="true">

        <!-- 안드로이드 부팅 이벤트 받기 : BroadcastReceiver -->
        <receiver
            android:name="com.bluexmas.common.BootReceiver"
            android:enabled="true"
            android:exported="false"
            android:label="BOOTReceiver">

            <intent-filter >
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

앱이 종료 이후 백그라운드 서비스 실행 유지

서비스 생성

package com.bluexmas.common;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;

public class BackgroundService extends Service {

    private final static String TAG = BackgroundService.class.getSimpleName();

    private Context context = null;
    public int counter=0;

    // 생성자1 : 반듯이 필요
    public BackgroundService() {
    }

    // 생성자2
    public BackgroundService(Context applicationContext) {
        super();
        context = applicationContext;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 서비스에서 가장 먼저 호출됨(최초에 한번만)
        Log.d(TAG, "BackgroundService.onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        // 서비스가 호출될 때마다 실행
        Log.d(TAG, "BackgroundService.onStartCommand");
        //
        startTimer();
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 서비스가 종료될 때 실행
        Log.d(TAG, "BackgroundService.onDestroy");
        //
        Intent broadcastIntent = new Intent("com.bluexmas.common.RestartService");
        sendBroadcast(broadcastIntent);
        stoptimertask();
    }

    private Timer timer;
    private TimerTask timerTask;
    long oldTime=0;
    public void startTimer() {
        //set a new Timer
        timer = new Timer();

        //initialize the TimerTask's job
        initializeTimerTask();

        //schedule the timer, to wake up every 1 second
        timer.schedule(timerTask, 1000, 1000); //
    }

    /**
     * it sets the timer to print the counter every x seconds
     */
    public void initializeTimerTask() {
        timerTask = new TimerTask() {
            public void run() {
                Log.i(TAG, "in timer ++++  "+ (counter++));
            }
        };
    }

    /**
     * not needed
     */
    public void stoptimertask() {
        //stop the timer, if it's not already null
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }
}

AndroidManifest.xml 내용추가 - 서비스와 종료 이벤트를 받은 receiver 등록

        <!-- BackgroundService -->
        <service
            android:name="com.bluexmas.common.BackgroundService"
            android:enabled="true" >
        </service>

        <receiver
            android:name="com.bluexmas.common.RestarterBroadcastReceiver"
            android:enabled="true"
            android:exported="true"
            android:label="RestartServiceWhenStopped">
            <intent-filter>
                <action android:name="com.bluexmas.common.RestartService" />
            </intent-filter>
        </receiver>

    </application>

종료 이벤트를 받은 receiver 클래스 생성

package com.bluexmas.common;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class RestarterBroadcastReceiver extends BroadcastReceiver {

    private final static String TAG = RestarterBroadcastReceiver.class.getSimpleName();

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "RestarterBroadcastReceiver.onReceive");
        context.startService(new Intent(context, BackgroundService.class));
    }
}

MainActivity - 서비스가 실행하고 있지 않는 경우 서비스 실행

    // BackgroundService
    private Intent mBackgroundServiceIntent;
    private BackgroundService mBackgroundService;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ... 생략 ...

        // BackgroundService
        mBackgroundService = new BackgroundService(getApplicationContext());
        mBackgroundServiceIntent = new Intent(getApplicationContext(), mBackgroundService.getClass());
        // 서비스가 실행 중인지 확인
        if (!BootReceiver.isServiceRunning(this, mBackgroundService.getClass())) {
            // 서비스가 실행하고 있지 않는 경우 서비스 실행
            startService(mBackgroundServiceIntent);
        }
    }

사용자가 강제로 서비스를 종료하더라도 자동으로 서비스를 다시 시작하기

AndroidManifest.xml 내용추가 - android:stopWithTask="false"로 설정해야 onTaskRemoved 메소드가 호출됨

        <!-- BackgroundService -->
        <service
            android:name="com.bluexmas.common.BackgroundService"
            android:enabled="true"
            android:stopWithTask="false">
        </service>

기존 BackgroundService 클래스에 onTaskRemoved 오버라이드 메소드 구현

    // 사용자가 강제로 서비스를 종료하더라도 자동으로 서비스를 다시 시작하는 방법은 무엇입니까?
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Log.d(TAG, "BackgroundService.onTaskRemoved");
        //create an intent that you want to start again.
        Intent intent = new Intent(getApplicationContext(), BackgroundService.class);
        PendingIntent pendingIntent = PendingIntent.getService(this, 1, intent, PendingIntent.FLAG_ONE_SHOT);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime() + 5000, pendingIntent);
        super.onTaskRemoved(rootIntent);
    }

BPI-Bit : Arduino 개발환경 구축하기

OS/Banana Pi /BPI-Bit 2018.09.21 21:12 Posted by 파란크리스마스

출처

BPI-Bit : Arduino 개발환경 구축하기

BPI-Bit는 몇가지 개발 언어가 있는데 Webduino 말고도 Arduino IDE로 개발할 수 있어서, Arduino IDE 개발환경을 구축하고 간단예제를 실행해보았습니다.

1. Arduino IDE 설치

Arduino IDE (arduino-1.8.7-windows.zip)를 다운로드받고, 설치

2. arduino-esp32 다운로드

Github 저장소(espressif / arduino-esp32)에서 arduino-esp32-master.zip 파일 다운로드

3. arduino-esp32 설치

다운로드 받은 파일 arduino-esp32-master.zip을 [Arduino IDE 설치경로]/hardware/espressif/esp32에 압축 해제

4. get 명령을 관리자 권한으로 실행

[Arduino IDE 설치경로]/hardware/espressif/esp32/tools 디렉토리에서 get 명령을 관리자 권한으로 실행 실행

5. Arduino IDE를 실행하고, 메뉴[툴] > [보드] > [NodeMCU -32S] 선택

예제 작성

//BIT NEW
//BPI - BIT test code
#include <Arduino.h>
#include <NeoPixelBus.h>

#define LEDC_CHANNEL_0 0
#define LEDC_TIMER_13_BIT 13
#define LEDC_BASE_FREQ 4500

const uint16_t PixelCount = 25;
const uint8_t PixelPin = 4;

#define colorSaturation 128
#define delay_ms 500

NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(PixelCount, PixelPin);

RgbColor red(colorSaturation, 0, 0);
RgbColor green(0, colorSaturation, 0);
RgbColor blue(0, 0, colorSaturation);
RgbColor white(colorSaturation);
RgbColor black(0);
RgbColor num1(0.8 * colorSaturation, 0, 0.2 * colorSaturation);
RgbColor num2(0.5 * colorSaturation, 0, 0.5 * colorSaturation);
RgbColor num3(0.25 * colorSaturation, 0, 0.75 * colorSaturation);

HslColor hslRed(red);
HslColor hslGreen(green);
HslColor hslBlue(blue);
HslColor hslWhite(white);
HslColor hslBlack(black);

#define ledPower 2
#define BottomA 35
#define BottomB 27

int brightness = 0;
int fadeAmount = 5;

void ledcAnalogWrite(uint8_t channel, uint32_t value) {
  // calculate duty, 8191 from 2 ^ 13 - 1 (2 ^ LEDC_TIMER_13_BIT - 1)
  //value_MAX = 255
  uint32_t duty = (8191 / 255) * value;
  // write duty to LEDC
  ledcWrite(channel, duty);
}

void setup() {
  Serial.begin(115200); //Serial Port Config 115200-8-N-1
  
  Serial.println();
  Serial.println("Initializing...");
  Serial.flush();
  
  // this resets all the neopixels to an off state
  strip.Begin();
  strip.Show();
  
  pinMode(ledPower,OUTPUT);
  pinMode(BottomA, INPUT);
  pinMode(BottomB, INPUT);
  digitalWrite(ledPower, HIGH);
  
  // strip.SetPixelColor(10, blue);
  // strip.SetPixelColor(11, blue);
  // strip.SetPixelColor(12, blue);
  // strip.SetPixelColor(13, blue);
  // strip.SetPixelColor(14, red);
  // strip.Show();
  
  // delay(1000);
  
  // int i;
  // for (i = 0; i <= PixelCount - 1; i++)
  // {
  //     strip.SetPixelColor(i, black);
  //     strip.Show();
  // }
}

void loop() {
  //signel map
  if (digitalRead(BottomA) == LOW) {
    delay(10);
    if (digitalRead(BottomA) == LOW) {
      strip.SetPixelColor(16, num1);
      strip.SetPixelColor( 7, num2);
      strip.SetPixelColor(18, num3);
      strip.Show();
    } else {
      int i;
      Serial.println("Turn Off");
      for (i = 0; i <= PixelCount - 1; i++) {
        strip.SetPixelColor(i, hslBlack);
        strip.Show();
      }
    }
  }
}

예제 실행

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

OS/Tinker Board 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 : Lazarus 설치

OS/Tinker Board 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
$ sudo wget https://jaist.dl.sourceforge.net/project/lazarus/Lazarus%20Zip%20_%20GZip/Lazarus%201.8.4/lazarus-1.8.4.tar.gz
$ sudo tar -xvf lazarus-1.8.4.tar.gz 
$ cd lazarus/
$ 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 : Smart-Mirror 설치

OS/Tinker Board 2018.09.16 10:20 Posted by 파란크리스마스

출처

Tinker Board : Smart-Mirror 설치

Raspberry PI에서 사용햇던 Smart-Mirror를 Tinker Board에 적용해보았습니다. Raspberry PI이 보다 실행 속도가 많이 빨라 졌습니다. 모니터는 Raspberry PI 7인치 모니터를 사용했고, 미러용 필름은 붙이지는 않았습니다. 마이크의 입력은 4극 스테레오 Y케이블을 사용해서 특별하게 마이크 설정없이 바로 사용이 가능했습니다.

음성 인식용으로 사용했던 마이크

4극 스테레오 (3.5) Y케이블

Tinker Board용 Audio 단자는 마이크 입력과 오디오 출력이 동시에 가능한 4핀 단자로 아래와 같은 4극 Y케이블을 이용하면 마이크 입력과 오디오 출력을 분리해서 사용 할 수 있습니다.

4극 스테레오 (3.5) Y케이블에 마이크 연결

Node.js 6.x 설치

$ curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
$ sudo apt-get install -y nodejs

Smart-Mirror 소스 다운로드

$ cd ~
$ git clone https://github.com/evancohen/smart-mirror.git

Smart-Mirror 관련 라이브러리 설치

$ sudo apt-get install sox libatlas-base-dev

Smart-Mirror 설치

$ cd ~/smart-mirror
$ npm install

Smart-Mirror 실행

$ npm start

개발자 콘솔로 Smart-Mirror 실행

$ npm start dev

관리 페이지 접속

관리 페이지 오른쪽 상단 톱니바퀴 아이콘을 선택하면 Smart-Mirror 설정 화면으로 이동이 가능합니다.

언어 설정 변경 (한국어 명령이 가능하도록 설정)

Language 항목의 설정을 ko-KR로 수정

자신만의 호출 키워드 생성

이 작업은 마이크를 사용하여 smart-mirror가 대기 모드에서 명령 모드로 변경 됩니다.

키워드 생성은 사이트(https://snowboy.kitt.ai/hotword/47)에서 하시면 되고 저는 팅커보드의 약자로 팅커벨로 했습니다.

Snowboy에서 생성한 Tinkerbell.pmdl 파일을 smart-mirror가 설치된 경로(/home/linaro/smart-mirror)에 복사합니다.

호출 키워드 등록

Google Cloud Speech Keyfile 등록

출처 : Cloud Speech Recognition · Smart Mirror Documentation

keyfile 생성

Google Cloud Speech Keyfile 등록

모니터 세로 모드로 변경

$ vi .xsessionrc

#!/bin/sh
xrandr --output DSI-1 --rotate left

Smart-Mirror 실행 영상

Tinker Board : pi4j

OS/Tinker Board 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

실행 동영상