2016年3月2日 星期三

Raspberry Pi: Connected Arduino Using I2C

since: 2016/02/25
update: 2016/03/03

reference:
1.Raspberry Pi and Arduino Connected Using I2C - OscarLiang.net
2. [I2C] onRequest and onReceive as slave with Raspberry Pi Master

A. 檢查 Raspberry Pi:
   
1. Linux 版本

    $ uname -a
Linux raspberrypi 4.1.17-v7+ #843 SMP Mon Feb 15 23:35:33 GMT 2016 armv7l GNU/Linux

    2. python 版本
    $ python -V
Python 2.7.9

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

B. 安裝 I2C 與 python相關套件:
    $ sudo apt-get install python-smbus
    $ sudo apt-get install python3-smbus // for python3
    $ sudo apt-get install i2c-tools

    // check
    $ sudo aptitude search smbus
p   pypy-smbus-cffi        - This Python module allows SMBus access through the I2C /dev              
i   python-smbus            - Python bindings for Linux SMBus access through i2c-dev                   
v   python2.7-smbus      -                                                                          
i   python3-smbus          - Python 3 bindings for Linux SMBus access through i2c-dev


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

C. 安裝 I2C 的 Kernel Support:
     $ sudo raspi-config
        > 9 Advanced Options

        > A7 I2C

        > Yes
       ....
        > Yes

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

D. 檢查設定(選擇性)
     $ cat /etc/modules
....
i2c-dev
    
     $ cat /etc/modprobe.d/raspi-blacklist.conf
# ...
# ...


    $ cat /boot/config.txt
....
dtparam=i2c_arm=on

    $ cat /etc/group | grep i2c
i2c:x:998:pi
      // $ sudo adduser pi i2c

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

E. I2C 測試:
    $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- -- 


    $ ls /dev/i2c*
/dev/i2c-1
-----------------------------------------------------------------------------------------------

F. Arduino Code:
#include <Wire.h>

#define SLAVE_ADDRESS 0x04
int number = 0;
int state = 0;

void setup() {
    pinMode(13, OUTPUT);
    Serial.begin(9600); // start serial for output
    // initialize i2c as slave
    Wire.begin(SLAVE_ADDRESS);

    // define callbacks for i2c communication
    Wire.onReceive(receiveData);
    Wire.onRequest(sendData);
    //Serial.println(“Ready!”);
}

void loop() {
    delay(100);
}

// callback for received data
void receiveData(int byteCount){

    while(Wire.available()) {
        number = Wire.read();
        //Serial.print(“data received: “);
        //Serial.println(number);


        if (number == 1){

            if (state == 0){
                digitalWrite(13, HIGH); // set the LED on
                state = 1;
            }
            else{
                digitalWrite(13, LOW); // set the LED off
                state = 0;
            }
        }
    }
}

// callback for sending data
void sendData(){
    Wire.write(number);
}


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

G. Raspberry Pi's  Python Code:
#!/usr/bin/python
#encoding: utf-8

import smbus
import time

# for RPI version 1, use "bus = smbus.SMBus(0)"
bus = smbus.SMBus(1)

# This is the address we setup in the Arduino Program
address = 0x04

def writeNumber(value):
    bus.write_byte(address, value)
    # bus.write_byte_data(address, 0, value)
    return -1

def readNumber():
    number = bus.read_byte(address)
    # number = bus.read_byte_data(address, 1)
    return number

while True:
    var = input("Enter 1 – 9:")
    if not var:
        continue

    writeNumber(var)
    print "RPI: Hi Arduino, I sent you ", var
    # sleep one second
    time.sleep(1)

    number = readNumber()
    print "Arduino: Hey RPI, I received a digit ", number
    print


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

H. 備註:
When we use read_i2c_block_data(), It was too fast to write a command byte and read the data.

In that time, if we use Serial.println() to print log to serial. Arduino will can not follow the speed. and it missing the i2c read flag.

So, the dataReceive() funtion will not be run at all.

The solution is simple: just do not use Serial library until the i2c is free.

2016年2月19日 星期五

Raspberry Pi: Setting Up The Watchdog

since: 2016/02/19
update: 2016/02/19

reference:
1. 樹莓派硬體看門狗(Watchdog):當機時自動重新開機 - G. T. Wang
2. ssmtp to send emails – Raspberry Pi Projects


A. Sending Email From Your System with sSMTP
    1. 安裝套件:
        $ sudo apt-get install ssmtp
        $ sudo apt-get install mailutils

    2. 編輯設定檔:
        $ sudo nano /etc/ssmtp/ssmtp.conf
#
# Config file for sSMTP sendmail
#
# The person who gets all mail for userids < 1000
# Make this empty to disable rewriting.
#root=postmaster
root=lanlixxxx@gmail.com

# The place where the mail goes. The actual machine name is required no
# MX records are consulted. Commonly mailhosts are named mail.domain.com
#mailhub=mail
mailhub=smtp.gmail.com:587

# Where will the mail seem to come from?
#rewriteDomain=

# The full hostname
hostname=raspberrypi

# Auth
AuthUser=pythonicxxxx@gmail.com
AuthPass=pythonxxxx


# Are users allowed to set their own From: address?
# YES - Allow the user to specify their own From: address
# NO - Use the system generated From: address
FromLineOverride=YES
UseSTARTTLS=YES


    3. 降低寄發郵件的安全性設定: (AuthUser)
        > GMail 低安全性應用程式 - 帳戶設定

    4. 寄發測試郵件:
        $ echo "Hello world email body" | mail -s "Test Subject" lanlixxxx@gmail.com

    5. 寄發 "附加檔案" 測試郵件:
        $ sudo apt-get install mpack
        $ mpack -s "Test" somefile.txt lanlixxxx@gmail.com

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

B. 安裝 watchdog

    1. 啟用 bcm2708_wdog 核心模組
        $ sudo nano /etc/modules
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

i2c-dev

bcm2708_wdog

    2. 立即啟用:
        $ sudo modprobe bcm2708_wdog

    3. 安裝 watchdog 監控 Daemon
        $ sudo apt-get install watchdog

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

C. 編輯 watchdog 設定檔
    $ sudo nano /etc/watchdog.conf
#ping                   = 172.31.14.1
#ping                   = 172.26.1.255
#interface              = eth0
#interface              = wlan0
# 監控檔案是否可以正常存取

#file                   = /var/log/messages
#change                 = 1407

# Uncomment to enable test. Setting one of these values to '0' disables it.
# These values will hopefully never reboot your machine during normal use
# (if your machine is really hung, the loadavg will go much higher than 25)
max-load-1              = 24
max-load-5              = 18
max-load-15             = 12


# Note that this is the number of pages!
# To get the real size, check how large the pagesize is on your machine.
# 查看自己系統的 page size
# getconf PAGESIZE (4096)

#
#min-memory             = 1 (一張 page 的大小就是 4096 bytes)
#allocatable-memory     = 1

#repair-binary          = /usr/sbin/repair
#repair-timeout         =
#test-binary            =
#test-timeout           =

watchdog-device = /dev/watchdog

# Defaults compiled into the binary

// 檢查 CPU 溫度  (單位: 攝氏千分之一度)
// cat /sys/class/thermal/thermal_zone0/temp     (35780)
#temperature-device     =  /sys/class/thermal/thermal_zone0/temp
#max-temperature        = 120

#max-temperature        = 80000
# Defaults compiled into the binary
#admin                  = root
admin                   = lanlixxxx@gmail.com
#interval               = 1
#logtick                = 1
#log-dir                = /var/log/watchdog

# This greatly decreases the chance that watchdog won't be scheduled before
# your machine is really loaded
realtime                = yes
priority                = 1

# Check if rsyslogd is still running by enabling the following line
#pidfile                = /var/run/rsyslogd.pid

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

D. 調整: (for 新版 Pi OS: 2016-02-09-raspbian-jessie; still may not work)
     $ sudo nano /lib/systemd/system/watchdog.service
[Unit]
Description=watchdog daemon
Conflicts=wd_keepalive.service
After=multi-user.target
OnFailure=wd_keepalive.service

[Service]
Type=forking
EnvironmentFile=/etc/default/watchdog
ExecStartPre=/bin/sh -c '[ -z "${watchdog_module}" ] || [ "${watchdog_module}" = "none" ] || /sbin/modprobe $watchdog_module
ExecStart=/bin/sh -c '[ $run_watchdog != 1 ] || exec /usr/sbin/watchdog $watchdog_options'
ExecStopPost=/bin/sh -c '[ $run_wd_keepalive != 1 ] || false'

[Install]

WantedBy=multi-user.target

$ systemctl enable watchdog

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

E. 啟動看門狗
    1. 立即啟動 watchdog 常駐程式
        $ sudo service watchdog start

    2. 開機時自動啟動 watchdog
        $ sudo update-rc.d watchdog defaults

    3. 檢查
        $ ps aux | grep watchdog
root       786  0.0  0.3   1888  1760 ?        SLs  14:34   0:00 /usr/sbin/watchdog
pi         822  0.0  0.3   4276  1956 pts/0    S+   14:36   0:00 grep --color=auto watchdog


    4. 測試       
        kill 掉 watchdog 本身, 會重新開機
        $ sudo kill -9 786       

2016年1月22日 星期五

Raspberry Pi: Windows 10 IoT Memo

since: 2016/01/22
update: 2016/01/22

reference:
1. Windows IoT - Downloads
2. Windows IoT - Setup your Raspberry Pi 2
3. Windows IoT - Use SSH to connect to a Windows IoT Core device


A. 說明:
     1. 需要 Windows 10 才可以安裝

     2. 已在 Windows 上安裝過以下軟體:
         Windows 10 IoT Core
         Windows 10 IoT Core Dashboard

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

B. 可使用 ssh 登入
    > Windows 上安裝 putty

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

C. ID / pass:
    administrator / xxxx

Raspberry Pi: Setup For LED Pixel Art

since: 2016/01/22
update: 2016/01/22

reference:
1. Raspberry Pi and IOIO Board | PIXEL: LED ART
2. PIXEL Console App | PIXEL: LED ART
3. Overview | Web Enabled PIXEL on Raspberry Pi | Adafruit Learning System
4. Raspberry Pi and PIXEL | PIXEL: LED ART
5. RPiBlog: Installing Oracle JDK 8 on Raspberry Pi


A. Download the udev rules file.

    1. 到 Downloads · ytai/ioio Wiki , 下載 Linux 版的檔案: 50-ioio.rules (另存新檔)
       其內容為:
ACTION=="add", SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="0008", SYMLINK+="IOIO%n", MODE="666"
ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="0008", ENV{ID_MM_DEVICE_IGNORE}="1"


    2.  將 50-ioio.rules 上傳到 pi 裡:
         $ scp 50-ioio.rules pi@192.168.1.24:/home/pi

    3. copy it to your rules directory (one time step)
       $ sudo cp 50-ioio.rules /etc/udev/rules.d

    4. restart udev
       $ sudo restart udev
       (or $ sudo /etc/init.d/udev restart)

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

B. Check IOIO recognized status
    1. Plug your IOIO into a free USB port on the Raspberry Pi

    2. check if it’s recognized using this command
        $ ls /dev/IOIO*
           /dev/IOIO0

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

C. Install Java on your Pi
    1. for pi 1:
        $ sudo apt-get install openjdk-7-jre

    2. for pi 2:
       $ sudo apt-get install openjdk-8-jre

    3. 備註:
        切換使用不同版本的 java 方式: (如果有安裝不同的版本)
        $ sudo update-alternatives --config java

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

D. 安裝 avahi-daemon
    $ sudo apt-get install avahi-daemon

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

E. Check PIXEL recognized status
    1.Move the toggle switch on the side of PIXEL from the “Bluetooth” position to the “PC” position

    2. Plug PIXEL into a free USB port on your Raspberry Pi using the included USB A-A cable.

    3. Then check if it’s recognized using this command:
        $ ls /dev/ttyACM0*
           /dev/ttyACM0

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

F. 下載 PIXEL Console App
        http://ledpixelart.com/console/
    1. 在此使用 PIXEL: Console V2.0 版本
    2. 上傳到 pi 裡:
        $ scp pixelc_2_0.jar pi@192.168.1.24:/home/pi

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

G. 測試:
     先將
pixelc_2_0.jar  更名成: pixelc.jar
     1. $ java -jar -Dioio.SerialPorts=/dev/IOIO0 pixelc.jar --gif=black.gif
     2. $ java -jar -Dioio.SerialPorts=/dev/IOIO0 pixelc.jar --gif=black.gif --write
     3. $ java -jar -Dioio.SerialPorts=/dev/IOIO0 pixelc.jar -–zip=95050
     4. $ java -jar -Dioio.SerialPorts=/dev/ttyACM0 pixelc.jar --gif=black.gif
     5. $ java -jar pixelc.jar --gif=fire.gif
     6. $ java -jar pixelc.jar -–zip=95050 

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

H. 其他:
     套件更新:
     $ sudo apt-get update
     $ sudo apt-get upgrade
     $ sudo apt-get dist-upgrade
     $ sudo rpi-update

     others:
     $ sudo apt-cache search openjdk
     $ sudo apt-get install openjdk-7-jdk
     $ sudo update-alternatives --config javac

2016年1月16日 星期六

Processing: An error occurred during startup

since: 2016/01/16
update: 2016/01/16


A. 錯誤:
     Processing 2.21 無法開啟

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

B. 解決方式:
    1. 可先開啟 Processing 3, 查看最下方偏好設定檔的位置.
        或看 C. 備註3.

    2. 刪除整個 "偏好設定檔目錄", 在此例為: /Users/Lanli/Library/Processing

    3. 重新開啟 Processing 2

-----------------------------------------------------------------------------------------------
  
C. 備註:
     1. WindowsMac 皆適用

     2. "偏好設定檔目錄" 預設為隱藏
          Windows: 目錄設定顯示所有隱藏檔
          Mac: Finder > 前往 > 前往檔案夾 ...

     3. Windows 與 Mac 預設的 "偏好設定檔目錄" 位置:
         Windows: C:\Users\Lanli\AppData\Roaming\Processing
         Mac: /Users/Lanli/Library/Processing

2016年1月15日 星期五

openFrameworks: Reading From And Writing To Files With ofBuffer Class

since: 2016/01/15
update: 2016/01/15
reference:

A. in header file:
    ....
    /* config file */

    bool debug; // debug mode: to show more message or not
    float checkTime_second;
   
    /* record datetime to file */
    ofBuffer readBuffer;
    ofBuffer checkTimeBuffer;
    string nowDateString;


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

B. in c++ file:
     1. Read File:
   
    ....

    // read config file
    readBuffer = ofBufferFromFile("config.txt");
    //cout << readBuffer.getText(); // let's see what it says
    vector<string> lines = ofSplitString(readBuffer, "\n");
   
    for( int i = 0; i < lines.size(); i++){
        //cout << lines[i] << endl;
       
        if(i == 1) {
            debug = ofToBool(lines[i]);
            if(debug) {
                ofLog(OF_LOG_NOTICE, ">>>>> debug true");
            }
            else {
                ofLog(OF_LOG_NOTICE, ">>>>> debug false");
            }
        }
        else if(i == 4) {
            checkTime_second = ofToFloat(lines[i]);
            ofLogNotice(">>>>>>>>> checkTime_second") << checkTime_second;
        }

   

     2. Write File:
         ....

         // inner some loop
         if(ofGetElapsedTimef() >= checkTime_second) {
             ofResetElapsedTimeCounter();
               
             nowDateString = ofGetTimestampString("%Y%m%d%H%M%S");
             checkTimeBuffer.set(nowDateString.c_str(), nowDateString.size());
             if(ofBufferToFile("dateTime.txt", checkTimeBuffer)) {
                 ofLogNotice(">>>>>>>>> update checking dateTime") << nowDateString;
             }
         }


AppleScript: Repeat Checking App Status

since: 2016/01/15
update: 2016/01/15


A. 新增 AppleScript:
    1. 開啟 Automator:

   
     2. Automator > 檔案 > 新增 > 應用程式 > 選擇:
    
     3. 工具程式 > 執行 AppleScript > 拖拉到右方

    4. 預設程式碼:
on run {input, parameters}
   
    (* Your script goes here *)
   
    return input
end run


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

B. 修改 AppleScript:
on run {input, parameters}
   
    #
    # start: variables defined
    #
   
    # script repeat delay time (second)

    set repeatDelayTime to 180
   
    # dateTimeFile Path
    # /Lanli/RD/project/openFrameworks/of_v0.9.0/apps/myApps/myFirstApp/bin/data/

    set dateTimeFilePath to (("Lanli:RD:project:openFrameworks:of_v0.9.0:apps:myApps:myFirstApp:bin:data:") as text)
   
    # dateTimeFile Name
    set dateTimeFileName to "dateTime.txt"
   
    # completed dateTimeFile
    set dateTimeFile to dateTimeFilePath & dateTimeFileName
   
    # allow time difference to sysDateTime & appUpdateTime (second)

    set allowedSecondDiff to 120


    # allowed min free memory (MB)
    set allowedMinFreeMemory to 0
   
    # my app name
    set myAppName to "myFirstApp"

    # reboot system or not
    set reboot to false   

    #
    # end: variables defined
    #

   
    ##########################################################
   
    #
    # start script repeat
    #

    repeat
       
        # delay 180 second  
        # delay 180 
  
        delay repeatDelayTime
       
        # start: repeat task
       

##########################################################       
        # 
        # check 01:  app update status
        #
        # Read lines from file.

        set fileLines to paragraphs of (read file dateTimeFile as «class utf8»)
       
        # Loop over lines read and copy each to the clipboard.
        repeat with perLine in fileLines
            set the clipboard to perLine
            #display alert (the clipboard)
            set appUpdateTime to (the clipboard) as integer
            exit repeat # we just need read one line here
        end repeat
       
        # get sysDateTime
        set sysDateTime to nowTimeFormat() as integer
       
        # check time diff
        if (appUpdateTime + allowedSecondDiff) ≥ sysDateTime then
            # display dialog "you pass" with title "check app update status" buttons {"OK"} default button 1
        else
            # display dialog "reboot" with title "check app update status" buttons {"OK"} default button 1
            set reboot to true
        end if
       
       
        #
        # check 02:  system memory free
        #
       
        # query memory free (MB)

        set vmStats to (text 12 thru -2 of (do shell script "vm_stat | grep 'Pages free'")) * 4096 / 1024 / 1024
        # show free Memory
        #display dialog vmStats with title "Memory Free (MB)" buttons {"OK"} default button 1

       
        # if vmStats <= 0 MB
        if vmStatsallowedMinFreeMemory then
            set reboot to true
        end if
       
        # for test
        #set reboot to false

       
        #
        # reboot system or not
        #

        if reboot is true then
            #display dialog "reboot" with title "reboot system or not" buttons {"OK"} default button 1
           
            #step 1: kill your app 
            tell application "System Events"
                set ProcessList to name of every process
               
                if myAppName is in ProcessList then
                    set ThePID to unix id of process myAppName
                    do shell script "kill -KILL " & ThePID
                end if
            end tell
           
            #step 2: reboot system
            tell application "Finder"
                restart
            end tell
           
        else
            #display dialog "pass" with title "reboot system or not" buttons {"OK"} default button 1
        end if
       
       
        # end: repeat task
       

##########################################################       
        # exit script repeat: for only once execute
        #exit repeat
       
        #   
        # end script repeat
        #  
     
    end repeat
   
    return input
end run



# nowTimeFormat
on nowTimeFormat()
   
    set theDate to current date
    set y to text -4 thru -1 of ("0000" & (year of theDate))
    set m to text -2 thru -1 of ("00" & ((month of theDate) as integer))
    set d to text -2 thru -1 of ("00" & (day of theDate))
    set hh to text -2 thru -1 of ("00" & (hours of theDate))
    set mm to text -2 thru -1 of ("00" & (minutes of theDate))
    set ss to text -2 thru -1 of ("00" & (seconds of theDate))
   
    # 2016-01-15-10-56-46
    #return y & "-" & m & "-" & d & "-" & hh & "-" & mm & "-" & ss
    # 20160115105646

    return y & m & d & hh & mm & ss
   
end nowTimeFormat