2015年10月20日 星期二

CUDA: Try To Measuring The Kernel By Timer

since: 2015/10/20
update: 2015/10/20

reference:
1. Professional CUDA C Programming
2. I touchs: Get Started On NVIDIA Jetson TK1
3. I touchs: How to re-flash your Jetson TK1 Development Kit 
4. I touchs: Using the Jetson TK1 as a remote development environment for CUDA


A. Timing With CPU Timer

     1. 在 Nsight Eclipse Edition 撰寫程式如下:
         // 檔名: sumArraysOnGPU-timer.cu
#include <cuda_runtime.h>
#include <stdio.h>
#include <sys/time.h>


// check error

void CHECK(cudaError_t call)
{
    const cudaError_t error = call;
    if (error != cudaSuccess)
    {
        fprintf(stderr, "Error: %s:%d, ", __FILE__, __LINE__);
        fprintf(stderr, "code: %d, reason: %s\n", error,
                cudaGetErrorString(error));
    }
}

 
// the timer on cpu
double seconds()
{
    struct timeval tp;
    struct timezone tzp;
    int i = gettimeofday(&tp, &tzp);
    return ((double)tp.tv_sec + (double)tp.tv_usec * 1.e-6);
}


// verifying your kernel
void checkResult(float *hostRef, float *gpuRef, const int N)
{
    double epsilon = 1.0E-8;
    bool match = 1;

    for (int i = 0; i < N; i++)
    {
        if (abs(hostRef[i] - gpuRef[i]) > epsilon)
        {
            match = 0;
            printf("Arrays do not match!\n");
            printf("host %5.2f gpu %5.2f at current %d\n", hostRef[i],
                   gpuRef[i], i);
            break;
        }
    }

    if (match) printf("Arrays match.\n\n");

    return;
}

 

// initial random data
void initialData(float *ip, int size)
{
    // generate different seed for random number
    time_t t;
    srand((unsigned) time(&t));

    for (int i = 0; i < size; i++)
    {
        ip[i] = (float)( rand() & 0xFF ) / 10.0f;
    }

    return;
}



// sum Arrays On Host

void sumArraysOnHost(float *A, float *B, float *C, const int N)
{
    for (int idx = 0; idx < N; idx++)
    {
        C[idx] = A[idx] + B[idx];
    }
}


// sum Arrays On GPU
__global__ void sumArraysOnGPU(float *A, float *B, float *C, const int N)
{
    int i = blockIdx.x * blockDim.x + threadIdx.x;

    if (i < N) C[i] = A[i] + B[i];
}


// the main function

int main(int argc, char **argv)
{
    printf("\n%s Starting...\n", argv[0]);

    // set up device
    int dev = 0;
    cudaDeviceProp deviceProp;
    CHECK(cudaGetDeviceProperties(&deviceProp, dev));
    printf("Using Device %d: %s\n", dev, deviceProp.name);
    CHECK(cudaSetDevice(dev));

    // set up data size of vectors
    int nElem = 1 << 24;
    printf("Vector size %d\n", nElem);

    // malloc host memory
    size_t nBytes = nElem * sizeof(float);

    float *h_A, *h_B, *hostRef, *gpuRef;
    h_A     = (float *)malloc(nBytes);
    h_B     = (float *)malloc(nBytes);
    hostRef = (float *)malloc(nBytes);
    gpuRef  = (float *)malloc(nBytes);

    double iStart, iElaps;

    // initialize data at host side
    iStart = seconds();
    initialData(h_A, nElem);
    initialData(h_B, nElem);
    iElaps = seconds() - iStart;
    printf("initialData Time elapsed %f sec\n", iElaps);
    memset(hostRef, 0, nBytes);
    memset(gpuRef,  0, nBytes);

    // add vector at host side for result checks
    iStart = seconds();
    sumArraysOnHost(h_A, h_B, hostRef, nElem);
    iElaps = seconds() - iStart;
    printf("sumArraysOnHost Time elapsed %f sec\n", iElaps);

    // malloc device global memory
    float *d_A, *d_B, *d_C;
    CHECK(cudaMalloc((float**)&d_A, nBytes));
    CHECK(cudaMalloc((float**)&d_B, nBytes));
    CHECK(cudaMalloc((float**)&d_C, nBytes));

    // transfer data from host to device
    CHECK(cudaMemcpy(d_A, h_A, nBytes, cudaMemcpyHostToDevice));
    CHECK(cudaMemcpy(d_B, h_B, nBytes, cudaMemcpyHostToDevice));
    CHECK(cudaMemcpy(d_C, gpuRef, nBytes, cudaMemcpyHostToDevice));

    // invoke kernel at host side
    int iLen = 256;
    dim3 block (iLen);
    dim3 grid  ((nElem + block.x - 1) / block.x);


    iStart = seconds();
    sumArraysOnGPU<<<grid, block>>>(d_A, d_B, d_C, nElem);
    CHECK(cudaDeviceSynchronize()); // used just for debugging purpose
    iElaps = seconds() - iStart;
    printf("sumArraysOnGPU <<<  %d, %d  >>>  Time elapsed %f sec\n", grid.x,
           block.x, iElaps);


    // the testing result ....
    //

    // sumArraysOnGPU <<<  16384, 1024  >>>  Time elapsed 0.040817 sec
    // sumArraysOnGPU <<<  32768, 512  >>>  Time elapsed 0.031031 sec
    // sumArraysOnGPU <<<  65536, 256  >>>  Time elapsed 0.029070 sec
    // sumArraysOnGPU <<<  131072, 128  >>>  Time elapsed 0.028804 sec

    // sumArraysOnGPU <<<  262144, 64  >>>  Time elapsed 0.056073 sec
    // sumArraysOnGPU <<<  524288, 32  >>>  Time elapsed 0.098515 sec
    // sumArraysOnGPU <<<  1048576, 16  >>>  Time elapsed 0.190098 sec
    // sumArraysOnGPU <<<  2097152, 8  >>>  Time elapsed 0.375030 sec
    // sumArraysOnGPU <<<  4194304, 4  >>>  Time elapsed 0.803681 sec
    // sumArraysOnGPU <<<  8388608, 2  >>>  Time elapsed 1.835205 sec
    // sumArraysOnGPU <<<  16777216, 1  >>>  Time elapsed 3.515245 sec


    // check kernel error
    CHECK(cudaGetLastError()) ;

    // copy kernel result back to host side
    CHECK(cudaMemcpy(gpuRef, d_C, nBytes, cudaMemcpyDeviceToHost));

    // check device results
    checkResult(hostRef, gpuRef, nElem);

    // free device global memory
    CHECK(cudaFree(d_A));
    CHECK(cudaFree(d_B));
    CHECK(cudaFree(d_C));

    // free host memory
    free(h_A);
    free(h_B);
    free(hostRef);
    free(gpuRef);

    return(0);
}


     2. 執行結果:

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

B. Timing With nvprof(NVIDIA profiling tool)
     1. Before this, Don't forget to Add CUDA bin Environment Variables
         => How to re-flash your Jetson TK1 Development Kit
         => G. Add CUDA bin Environment Variables


     2. Login to TK1:
         $ ssh ubuntu@192.168.0.106

     3. Go to the release directory:
        $ cd /home/ubuntu/RD/projects/cuda/Release

     4. Timing with nvprof:
         $ nvprof ./NSightCUDA

     5. Result:
./NSightCUDA Starting...
==2996== NVPROF is profiling process 2996, command: ./NSightCUDA
Using Device 0: GK20A
Vector size 16777216
initialData Time elapsed 4.632509 sec
sumArraysOnHost Time elapsed 0.060414 sec
sumArraysOnGPU <<<  65536, 256  >>>  Time elapsed 0.023884 sec
Arrays match.

==2996== Profiling application: ./NSightCUDA
==2996== Profiling result:
Time(%)      Time     Calls       Avg       Min       Max  Name
 57.86%  137.14ms         3  45.714ms  44.908ms  46.267ms  [CUDA memcpy HtoD]
 32.42%  76.837ms         1  76.837ms  76.837ms  76.837ms  [CUDA memcpy DtoH]
  9.73%  23.053ms         1  23.053ms  23.053ms  23.053ms  sumArraysOnGPU(float*, float*, float*, int)

==2996== API calls:
Time(%)      Time     Calls       Avg       Min       Max  Name
 54.19%  219.10ms         4  54.774ms  45.602ms  79.567ms  cudaMemcpy
 39.03%  157.79ms         3  52.598ms  1.0795ms  152.74ms  cudaMalloc
  5.87%  23.717ms         1  23.717ms  23.717ms  23.717ms  cudaDeviceSynchronize
  0.64%  2.5713ms         3  857.08us  661.42us  1.0873ms  cudaFree
  0.14%  582.58us        83  7.0190us  1.4160us  302.67us  cuDeviceGetAttribute
  0.08%  331.83us         1  331.83us  331.83us  331.83us  cudaGetDeviceProperties
  0.03%  119.25us         1  119.25us  119.25us  119.25us  cudaLaunch
  0.01%  45.583us         1  45.583us  45.583us  45.583us  cudaSetDevice
  0.00%  17.416us         2  8.7080us  4.5000us  12.916us  cuDeviceGetCount
  0.00%  17.333us         1  17.333us  17.333us  17.333us  cudaGetLastError
  0.00%  10.667us         1  10.667us  10.667us  10.667us  cuDeviceTotalMem
  0.00%  9.0000us         1  9.0000us  9.0000us  9.0000us  cudaConfigureCall
  0.00%  6.2500us         1  6.2500us  6.2500us  6.2500us  cuDeviceGetName
  0.00%  4.8340us         4  1.2080us     667ns  1.8340us  cudaSetupArgument
  0.00%  4.1670us         2  2.0830us  1.8330us  2.3340us  cuDeviceGet


  備註: The nvprof result is more accurate than the host-side timing result

openFrameworks: Serial Read String From Arduino Simulated Sensor

since: 2015/10/20
update: 2015/10/22
reference:
1. Serial read string from Arduino - 【oF】openFrameworks

A. Arduino 程式: 
// arduino_sensor.ino
long randNumber;
float randFloat;

String xAxis = "X: ";
String yAxis = "Y: ";
String zAxis = "Z: ";

String xValue = "";
String yValue = "";
String zValue = "";

void setup(){
  Serial.begin(9600);

  // if analog input pin 0 is unconnected, random analog
  // noise will cause the call to randomSeed() to generate
  // different seed numbers each time the sketch runs.
  // randomSeed() will then shuffle the random function.

  randomSeed(analogRead(0));
}

void loop() {

  // ex: X: 359.81252 Y: 11.81252 Z: 56.00005
  randNumber = random(0, 36000000);
  randFloat = randNumber / 100000.0; //
produce float random value: 0 ~ 360
  xValue = String(randFloat, 5);
 
  randNumber = random(-3600000, 3600000);
  randFloat = randNumber / 100000.0; //
produce float random value: -36 ~ 36
  yValue = String(randFloat, 5); 
 
  randNumber = random(0, 18000000);
  randFloat = randNumber / 100000.0;  //
produce float random value: 0 ~ 180
  zValue = String(randFloat, 5); 

  Serial.println(xAxis + xValue + " " + yAxis + yValue + " " + zAxis + zValue);
  delay(50);
}


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

B. openFrameworks 程式:
    1. main.cpp
#include "ofMain.h"
#include "ofApp.h"

//========================================================================
int main( ){
    ofSetupOpenGL(1024,768,OF_WINDOW);            // <-------- setup the GL context

    // this kicks off the running of my app
    // can be OF_WINDOW or OF_FULLSCREEN
    // pass in width and height too:

    ofRunApp(new ofApp());
}

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

    2. ofApp.h
#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

    public:
        void setup();
        void update();
        void draw();

        void keyPressed(int key);
        void keyReleased(int key);
        void mouseMoved(int x, int y );
        void mouseDragged(int x, int y, int button);
        void mousePressed(int x, int y, int button);
        void mouseReleased(int x, int y, int button);
        void windowResized(int w, int h);
        void dragEvent(ofDragInfo dragInfo);
        void gotMessage(ofMessage msg);
   
        //@add 2015/10/20 ########################################
        string ofxGetSerialString(ofSerial &serial, char until);
        string ofxTrimStringRight(string str);
        string ofxTrimStringLeft(string str);
        string ofxTrimString(string str);
   
        ofTrueTypeFont  font;
        float           readTime;           // when did we last read?
        ofSerial        serial;
        string          serialString;
};


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

    3. ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------

//@add 2015/10/20 ########################################
string ofApp::ofxGetSerialString(ofSerial &serial, char until) {
    static string str;
    stringstream ss;
    char ch;
    int ttl=1000;
    while ((ch=serial.readByte())>0 && ttl-->0 && ch!=until) {
        ss << ch;
    }
    str+=ss.str();
    if (ch==until) {
        string tmp=str;
        str="";
        return ofxTrimString(tmp);
    } else {
        return "";
    }
}


//@add 2015/10/20 ########################################
// trim right trailing spaces

string ofApp::ofxTrimStringRight(string str) {
    size_t endpos = str.find_last_not_of(" \t\r\n");
    return (string::npos != endpos) ? str.substr( 0, endpos+1) : str;
}


//@add 2015/10/20 ########################################
// trim left trailing spaces

string ofApp::ofxTrimStringLeft(string str) {
    size_t startpos = str.find_first_not_of(" \t\r\n");
    return (string::npos != startpos) ? str.substr(startpos) : str;
}


//@add 2015/10/20 ########################################
// trim trailing spaces

string ofApp::ofxTrimString(string str) {
    return ofxTrimStringLeft(ofxTrimStringRight(str));;
}


void ofApp::setup(){
    //@add 2015/10/20 ########################################
    ofSetVerticalSync(true);
   
    ofBackground(255);
    // http://openframeworks.cc/documentation/utils/ofLog.html
    ofSetLogLevel(OF_LOG_VERBOSE);
   
    ofSetColor(0);
    font.loadFont("DIN.otf", 32);
   
    serial.listDevices();
    /*
     [notice ] ofSerial: [0] = tty.usbmodem1441
     [notice ] ofSerial: [1] = cu.usbmodem1441
     [notice ] ofSerial: [2] = tty.Bluetooth-Incoming-Port
     [notice ] ofSerial: [3] = cu.Bluetooth-Incoming-Port
     */
   
    /*
    vector<ofSerialDeviceInfo> deviceList = serial.getDeviceList();
    vector<ofSerialDeviceInfo>::iterator it = deviceList.begin();
   
    while( it != deviceList.end() ){
        ofLogVerbose() << (*it).getDeviceID() << ": " << (*it).getDeviceName();
        ++it;
    }
    */

   
    int baud = 9600;
    // Tells the computer which port to be listening to
    serial.setup(0, baud); //open the first device
   
    readTime = 0;
    serialString = "";
}

//--------------------------------------------------------------
void ofApp::update(){
    //@add 2015/10/20 ########################################
    serialString = "";
    serialString = ofxGetSerialString(serial,'\n'); //read until end of line
    if (serialString.length() > 0) {
        readTime = ofGetElapsedTimef();
        ofLogVerbose() << "serialString = " << serialString << "\n";
    }
}

//--------------------------------------------------------------
void ofApp::draw(){
    string msg;
    msg += "read: " + serialString + "\n";
    msg += "(at time " + ofToString(readTime, 3) + ")";
    font.drawString(msg, 50, 100);
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}

//--------------------------------------------------------------

void ofApp::mousePressed(int x, int y, int button){
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}


       備註:
       記得將 .... /openFrameworks/of_v0.8.4_osx_release/examples/ communication/
       serialExample/bin/data
內的 DIN.otf copy 到相對的位置內.


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

C. 執行結果:

2015年10月16日 星期五

Raspberry Pi: Using a standard USB webcam

since: 2015/10/16
update: 2015/10/16

reference:
1. Using a standard USB webcam
2. Raspberry Pi 安裝 Webcam 和 Motion Webcam Server
3. Raspberry Pi 筆記(十九): Webcam 拍照與瀏覽串流媒體

A. 單張照片拍照功能:
     1. $ lsusb
...
Bus 001 Device 004: ID 1871:0341 Aveo Technology Corp.
...

     2. $ ls /dev/video0
/dev/video0

     3. 安裝 fswebcam
         $ sudo apt-get update
         $ sudo apt-get upgrade
         $ sudo apt-get install fswebcam

     4. 抓圖測試:
         $ fswebcam -d /dev/video0 test.jpg
         (or $ fswebcam image.jpg)

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

B. 移動偵測拍照功能:

     1. 安裝 motion
         $ sudo apt-get install motion
         $ mkdir /tmp/motion
         $ sudo chmod -R 777 /tmp/motion
         $ sudo chmod -R 777 /etc/motion/motion.conf

     2. $ sudo nano /etc/default/motion
# set to 'yes' to enable the motion daemon
#start_motion_daemon=no

start_motion_daemon=yes

     3. $ sudo nano /etc/motion/motion.conf
....

# Start in daemon (background) mode and release terminal (default: off)
#daemon off

daemon on

# Image width (pixels). Valid range: Camera dependent, default: 352
# width 320

width 640

# Image height (pixels). Valid range: Camera dependent, default: 288
# height 240

height 480

# Maximum number of frames to be captured per second.
# Valid range: 2-100. Default: 100 (almost no limit).
#framerate 2

framerate 60

# The mini-http server listens to this port for requests (default: 0 = disabled)
webcam_port 8081

# Quality of the jpeg (in percent) images produced (default: 50)
# webcam_quality 50

webcam_quality 100

# Restrict webcam connections to localhost only (default: on)
webcam_localhost on

# TCP/IP port for the http server to listen on (default: 0 = disabled)
control_port 8080

# Restrict control connections to localhost only (default: on)
control_localhost on

....

     4. $ sudo service motion restart

     5. 在 pi 上, 測試:
         a. $ startx
         b. 開啟瀏覽器輸入: http://127.0.0.1:8081/

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

C. 簡易 Pi 視窗桌面相機:
     1. $ sudo apt-get install camorama

     2. $ startx

     3. 測試: Graphics > Camorama Webcam Viewer

    備註:
    1. 亦可在進入視窗模式後, 利用終端機啟動 ($ camorama --help)

    2. 調整存擋位置:
         Edit > Preferences > Local Capture > Browse... > OK

2015年10月1日 星期四

製作 OS X El Capitan USB 安裝開機碟

since: 2015/10/01
update: 2015/10/01

reference:
1. How to Create a OS X El Capitan Boot Installer USB Flash Drive

A. 準備動作:     

     1. 16 GB 的 USB 隨身碟.(至少需 8 GB)

     2. 從 Mac App Store 下載 OS X El Capitan, 下載完成後, 離開安裝步驟, 先不要安裝.

         備註: 並確認下載的檔案是在 /Applications 下
                  $ cd /Applications
                  $ ls | grep "Install"
                     Install OS X El Capitan.app

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

B. 製作可開機的 USB 碟:
    1. 將 USB 隨身碟連結 Mac, 並開啟 "磁碟工具程式",
        從左邊的磁碟清單點選 USB 隨身碟.

    2. 點選 "清除" 頁籤, 格式選為: Mac OS 擴充格式(日誌式), 按下 "清除" 並確認.

    3. 點選 "分割" 頁籤, 將分割區佈局從旁邊的下拉式選單選取 "1個分割區",
        並將分割區資訊裡的名稱, 改成: Untitled .
 
  4. 點選 "選項...", 點選 "GIUD 磁碟分割區表格" > 套用 > 分割 > 確認

    5. 磁碟工具程式 > 結束磁碟工具程式

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

C. 更改要安裝 OS X El Capitan 的 USB 隨身碟名稱, 以方便識別:
     ---> 將其名稱改成 "ElCapInstaller"


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

D. 製作 OS X El Capitan 安裝碟:
     1. 開啟 "終端機", 鍵入以下的指令:
    $sudo /Applications/Install\ OS\ X\ El\ Capitan.app/Contents/Resources/createinstallmedia --volume /Volumes/ElCapInstaller --applicationpath /Applications/Install\ OS\ X\ El\ Capitan.app --nointeraction

     2. 鍵入 admin 密碼, 等待完成的訊息(約 20 分鐘), 離開終端機.

     3. 完成後, 可以在 Mac Finder 看到剛出爐的 OS X El Capitan 安裝碟.

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

E. 進行安裝:
     重新開機, 按下 "option" 鍵, 就可以選擇 "Install OS X El Capitan" 了.

openFrameworks: Control The Raspberry Pi Camera Module

since: 2015/10/01
update: 2016/04/25
reference:
1. jvcleave/ofxRPiCameraVideoGrabber
2. 在 Raspberry Pi 中擷取螢幕畫面(Snapshot)的工具 - G. T. Wang

A. 說明
     在此處會利用 Mac 的 Xcode 當成程式的編輯工具, 而編譯執行皆需在 Pi 上進行. 

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

B. 啟用 Pi 的相機模組功能
    1. $ sudo raspi-config

    2. 選擇 5. Enable Camera

    3. > Enable

    4. > Yes

C. 安裝附加在 openFrameworks 上的相機模組程式
     分別在 Mac 與 Pi 上的 openFrameworksaddons 目錄下安裝:

     // Pi
     $ cd /home/pi/of_v0.8.4_linuxarmv7l_release/addons
     $ git clone https://github.com/jvcleave/ofxRPiCameraVideoGrabber

     // Mac
     $ cd /Lanli/RD/project/openFrameworks/of_v0.8.4_osx_release/addons
     $ git clone https://github.com/jvcleave/ofxRPiCameraVideoGrabber  

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

D. 在 Xcode 上新增 openFrameworks 的 app 專案
      1. 於所安裝 openFrameworks 版本下的 projectGenerator_osx 目錄內,
          點二下: projectGenerator.app

      2. 設定新專案的資訊:
          Name: RPiCamera
          Addons: ofxRPiCameraVideoGrabber
          > 按下: "GENERATE PROJECT"

      3. 完成後, 可於所安裝 openFrameworks 版本下的 apps > myApps 目錄下看到:
          RPiCamera 專案資料夾, 其資料夾下的 addons.make 檔案內容即是附加的
          程式名稱.

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

E. 用 Xcode 開啟 RPiCamera 專案目錄下的 RPiCamera.xcodeproj     
      1. 參考剛剛下載 addons 的 ofxRPiCameraVideoGrabber 目錄下的 example 程式碼

      2. 修改 main.cpp, ofApp.hofApp.cpp 程式碼如下:
          // main.cpp
#include "ofMain.h"
#include "ofApp.h"
#include "ofGLProgrammableRenderer.h"

int main()
{
    ofSetLogLevel(OF_LOG_VERBOSE);
    ofSetCurrentRenderer(ofGLProgrammableRenderer::TYPE);
   
    //ofSetupOpenGL(1280, 720, OF_WINDOW);
    //@update 2015/10/01

    ofSetupOpenGL(1280, 800, OF_FULLSCREEN);
    ofRunApp( new ofApp());
}


*************************************************************************


          // ofApp.h
#pragma once

#include "ofMain.h"
#include "ofAppEGLWindow.h"
#include "TerminalListener.h"
#include "ImageFilterCollection.h"
#include "ofxRPiCameraVideoGrabber.h"

class ofApp : public ofBaseApp, public KeyListener{
   
public:
   
    void setup();
    void update();
    void draw();
    void keyPressed(int key);
   
    void onCharacterReceived(KeyListenerEventData& e);
    TerminalListener consoleListener;
    ofxRPiCameraVideoGrabber videoGrabber;
   
    ImageFilterCollection filterCollection;
   
    bool doDrawInfo;
};


*************************************************************************


          // ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup()
{
    ofSetLogLevel(OF_LOG_VERBOSE);
    ofSetLogLevel("ofThread", OF_LOG_ERROR);
    //ofSetVerticalSync(false);
   
    doDrawInfo    = true;
   
    consoleListener.setup(this);
   
    OMXCameraSettings omxCameraSettings;
    //omxCameraSettings.width                = 1280;
    //omxCameraSettings.height                = 720;

    omxCameraSettings.width                    = 1280;
    omxCameraSettings.height                = 800;
    omxCameraSettings.isUsingTexture        = false;
   
    omxCameraSettings.doRecording            = false;        //default: false
    if (omxCameraSettings.doRecording)
    {
        omxCameraSettings.doRecordingPreview    = true;
        omxCameraSettings.recordingFilePath        = "";        //will self generate if left blank
        omxCameraSettings.doConvertToMKV        = false;    //converts file to .mkv using mkvmerge(if present)
    }
   
    videoGrabber.setup(omxCameraSettings);
    filterCollection.setup();
}

//--------------------------------------------------------------
void ofApp::update()
{
}

//--------------------------------------------------------------
void ofApp::draw(){
    //Nothing really to do here as the output is rendered directly to full screen
}

//--------------------------------------------------------------
void ofApp::keyPressed  (int key)
{
    ofLog(OF_LOG_VERBOSE, "%c keyPressed", key);
   
    if (key == 'e')
    {
        videoGrabber.applyImageFilter(filterCollection.getNextFilter());
    }
   
    if (key == 'g')
    {
        doDrawInfo = !doDrawInfo;
    }
    if (key == 'q')
    {
        ofLogVerbose(__func__) << "SENDING QUIT";
        videoGrabber.stopRecording();
    }
    if (key == 't')
    {
        videoGrabber.toggleLED();
    }
}

void ofApp::onCharacterReceived(KeyListenerEventData& e)
{
    keyPressed((int)e.character);
}


備註: 在 Xcode 上, 只需用到: Product > Clean , 將在 Mac 上不支援 Pi 的語法清除.

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

F. 編譯與執行
     1. 將 Xcode 建立的整個 RPiCamera 專案資料夾, 拷貝並上傳到 Pi 相對的位置下:
         /home/pi/of_v0.8.4_linuxarmv7l_release/apps/myApps/

     2. 在 Pi 上建立 app 捷徑(symbolic link)
         $ cd
         $ ln -s /home/pi/of_v0.8.4_linuxarmv7l_release/apps/myApps/RPiCamera ./RPiCamera

     3. 編譯
         $ cd
         $ cd RPiCamera
         $ make

     4. 在 Pi 上執行
         $ cd ~/RPiCamera
         $ make run

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

G. 結果

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

H. 加入拍照功能:
     1. 安裝 raspi2png
         a. 先安裝 png 函式庫
             $ sudo apt-get install libpng12-dev

         b. 下載 raspi2png
             $ cd ~
             $ git clone https://github.com/AndrewFromMelbourne/raspi2png.git

         c. 編譯 raspi2png
             $ cd ~/raspi2png
             $ make

     2. 擷取畫面測試
         $ cd ~/raspi2png
         $ ./raspi2png        (預設檔名: snapshot.png)

         備註: ./raspi2png --help
     3. 於程式加上 print screen 功能:
         開啟 ofApp.cpp 檔案, 修改如下:
....
void ofApp::keyPressed  (int key)
{
....
    if (key == 't')
    {
        videoGrabber.toggleLED();
    }

    //@add 2015/10/21: print screen ######################################
    if (key == 'p')
    {
        string mySweetCommand = "/home/pi/raspi2png/raspi2png --pngname ";
       
        // yyyymmddhhmmss
        mySweetCommand += ofToString(ofGetYear()) + ofToString(ofGetMonth())+ ofToString(ofGetDay())+ ofToString(ofGetHours())+ ofToString(ofGetMinutes()) + ofToString(ofGetSeconds());

        mySweetCommand += ".png";
       
        system(mySweetCommand.c_str());
    }
}

....


     4. 於 Pi 上編譯, 並執行. 按下 "p" 即會在 ~/RPiCamera/bin 下產生擷取的影像畫面

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

I. 備註:     
   reference:
   a. Capturing HD Video With The Pi Camera Module 24
   b. Streaming Video Using VLC Player

   c. Raspberry Pi Camera 簡介

   1. 單純拍攝短片或照片
   
         a. raspicam commands
             1. 錄製 10 秒鐘影片:
                 $ raspivid --codec MJPEG -o video.mpg -t 10000
                 在 pi 上播放:
                 $ omxplayer ./video.mpg

         b. Python picamera
             1. install python-picamera
                 $ sudo apt-get install python-picamera
                 $ sudo apt-get install python3-picamera
                 $ sudo apt-get install python-picamera-docs

             2. camera_test.py
#!/usr/bin/python3

import picamera

camera = picamera.PiCamera()

# auto white balance
# off,auto,sun,cloud,shade,tungsten,fluorescent,incandescent,flash,horizon
#camera.awb_mode = 'auto'


camera.start_preview()


#for i in range(100):
#    camera.brightness = i
#    sleep(0.2)


#camera.capture('image.jpg')

camera.start_recording('video.h264')
camera.wait_recording(3)
camera.stop_recording()

camera.stop_preview()


             3. 播放
                 (1). 下載
video.h264 在 Mac 上, 利用 VLC 播放
                 (2). 先將 h264 轉乘 mp4 再播放
                       $ sudo apt-get install gpac
                       $ MP4Box -add video.h264 video.mp4

                       $ omxplayer ./video.mp4                          (亦可下載到 Mac 上播放)     -----------------------------------------------------------------------------------------------
   2. 開機自動執行
RPiCamera 程式
       a. 開機後自動登入
           $ sudo nano /etc/inittab

           ....
           #1:2345:respawn:/sbin/getty --noclear 38400 tty1
           1:2345:respawn:/bin/login -f pi tty1 </dev/tty1 >/dev/tty1 2>&1

       b. 登入後自動執行 RPiCamera 程式
           $ sudo nano ~/.bashrc
....
# auto run RPiCamera after start up 10 second, but not SSH sign in
sleep 10
echo "tty = $(tty)"

if [ $(tty) == "/dev/tty1" ]; then

  echo "We have a match."
  cd ~/RPiCamera
  ./bin/RPiCamera

else
  echo "We dont match."
fi


-----------------------------------------------------------------------------------------------
   3. 排程: 每天下午5點整關機
       $ sudo crontab -e
          # shutdown at 17:00 everyday
          00 17 * * * /sbin/shutdown -h now

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

   4. 當要使用一般的 USB Webcam 時, 記得要再執行: $sudo raspi-config ,  
       將 Pi 的相機模組功能停用.

2015年9月28日 星期一

CUDA: Check Dimension

since: 2015/09/28
update: 2015/09/28

reference:
1. Professional CUDA C Programming
2. I touchs: Get Started On NVIDIA Jetson TK1
3. I touchs: How to re-flash your Jetson TK1 Development Kit 
4. I touchs: Using the Jetson TK1 as a remote development environment for CUDA


A. 在 Nsight Eclipse Edition 撰寫程式如下:
     // 檔名: checkDimension.cu
#include <cuda_runtime.h>
#include <stdio.h>


__global__ void checkIndex(const int N)
{
    int i = blockIdx.x * blockDim.x + threadIdx.x;

    if (i < N)
    printf("threadIdx:(%d, %d, %d), blockIdx:(%d, %d, %d), blockDim:(%d, %d, %d), gridDim:(%d, %d, %d)\n",
               threadIdx.x, threadIdx.y, threadIdx.z,
               blockIdx.x, blockIdx.y, blockIdx.z,
               blockDim.x, blockDim.y, blockDim.z,
               gridDim.x, gridDim.y, gridDim.z);
}

int main(int argc, char **argv)
{
    // define total data element
    int nElem = 5;
    printf("\n");
    printf(">> total data count = %d \n", nElem);

    // define grid and block structure
    dim3 block(3);
    dim3 grid((nElem + block.x - 1) / block.x);
    printf(">> define block dimension = %d \n", block.x);
    printf(">> we get grid dimension = %d \n", grid.x);

    // check grid and block dimension from host side
    printf("\n* check grid and block dimension from host side *\n");
    printf("grid.x = %d , grid.y = %d , grid.z = %d\n", grid.x, grid.y, grid.z);
    printf("block.x = %d , block.y = %d , block.z = %d\n", block.x, block.y, block.z);
    printf("\n");

    // check grid and block dimension from device side
    printf("*check grid and block dimension from device side *\n");
    checkIndex<<<grid, block>>>(nElem);

    // reset device before you leave
    cudaDeviceReset();

    return 0;
}


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

B. 執行結果:

2015年9月24日 星期四

openFrameworks: v0.8.4 with Xcode 7.0

since: 2015/09/24
update: 2015/09/26
reference:
1. Warning : before upgrading to Xcode 7 - x-code - openFrameworks

A. 說明:
     Xcode 7 並沒有包含 OS X SDK 10.10 或更早的版本,
     可能會造成程式編譯上的錯誤:

         a. opensslconf.h file not found

         b. There is no SDK with the name or path

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

B. 解決方式:
    1. 在更新至 Xcode 7 前, 先從以下目錄來備份 MacOSX10.10.sdk:
         應用程式 > Xcode > (滑鼠右鍵)顯示套件內容 >
         Contents > Developer > Platforms > MacOSX.platform >
         Developer > SDKs > MacOSX10.10.sdk

        或者直接從網路下載: MacOSX10.10.sdk.dmg

    2. 更新至 Xcode 7 後, 將剛剛備份或下載的  MacOSX10.10.sdk ,
        複製回 Xcode 7 的相對的 SDKs 目錄內.

    3. 開啟 Xcode 的專案, 選取左邊的 openFrameworksLib.xcodeproj :
        右方 > Build Settings > Architectures > Base SDK: 選取 OS X 10.10

 4. 同樣地, 也需對 Xcode 本身的專案作相同的設定.

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

C. 備註:
     如果只是 openssl 的問題, 可以由以下的方式解決:  

     1. 在 Mac 上安裝 openssl:
          $ brew install openssl

     2. 開啟 Xcode 的專案, 點選左邊的 CoreOF.xcconfig   

     3. 在右方 HEADER 定義的最下方加入:
         ....
         //@add for openssl

         HEADER_OPENSSL = "$(OF_PATH)/libs/openssl/include"
         ....

     4. 在右方 OF_CORE_HEADERS =  的最後面加入:  $(HEADER_OPENSSL)
         ....
         ....