아트로봇에서 tmp36을 구매해서 아래 링크를 참조로 해서 회로도를 구성했다.

http://artrobot.co.kr/front/php/product.php?product_no=529&main_cate_no=&display_group=
http://www.ladyada.net/learn/sensors/tmp36.html
http://printk.tistory.com/42
http://www.ladyada.net/learn/sensors/tmp36.html




(이미지 참조 : http://www.ladyada.net/learn/sensors/tmp36.html)

내가 원하는 정보는 섭씨 온도인데, 잘 나온다.

int sensorPin = 0;

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

void loop() {
int reading = analogRead(sensorPin); 
float voltage = reading * 5.0 / 1024.0;

float temperatureC = (voltage - 0.5) * 100 ;
Serial.println(temperatureC);
delay(1000);   
  
}

float getVoltage(int pin){
  return (analogRead(pin) * .004882814);
}

 

다만, 이 수식이 전류의 흐름이 불확실해지면 정보는 정확하지 않게 나오는 단점이 있다.

Posted by '김용환'
,

 

<서론>

이클립스에서 아두이노 코딩을 위한 컴파일 작업을 했고, (http://knight76.tistory.com/entry/이클립스eclipse에서-avr-코딩해서-아두이노arduino-로-이미지-업로드하기-1)
이번에는 avrdude를 이용해서 이미지 업로드하는 방법을 소개한다.

 

<본론>

1. AVRDude 설정

프로퍼티 설정으로 가서, c/c++ build / Settings의 Addtiontal Tool in ToolChain을 선택한다.

“AVRDude” 설정에 대해서 check on 한다.

 

AVRDude item을 선택하고, Command 라인에 대한 설정 내용은 다음과 같이 수정한다.

“${COMMAND} -F -V  -P com3  -b 115200  -p m328p -c arduino -C G:\Arduino-package\arduino-1.0\hardware\tools\avr\etc\avrdude.conf  -U flash:w:arduino-test.hex”

 

망치 버튼을 눌러 동작을 시켜본다.

avrdude 툴을 써서 잘 이미지(hex)를 업로드하는 것을 확인할 수 있다.


**** Build of configuration 328P_16MHz for project arduino-test ****

make all
Building target: arduino-test.elf
Invoking: AVR C++ Linker
avr-g++ -s -Os -o"arduino-test.elf"  ./src/main.o  ./ref/CDC.o ./ref/HID.o ./ref/HardwareSerial.o
./ref/IPAddress.o ./ref/Print.o ./ref/Stream.o ./ref/Tone.o ./ref/USBCore.o
./ref/WInterrupts.o ./ref/WMath.o ./ref/WString.o ./ref/new.o ./ref/wiring.o
./ref/wiring_analog.o ./ref/wiring_digital.o ./ref/wiring_pulse.o ./ref/wiring_shift.o    -lm -Wl,-Map,arduino-test.map,--cref -mmcu=atmega328p
Finished building target: arduino-test.elf
 
Create Flash image (ihex format)
avr-objcopy -R .eeprom -O ihex arduino-test.elf  "arduino-test.hex"
Finished building: arduino-test.hex
 
Invoking: Print Size
avr-size --format=avr --mcu=atmega328p arduino-test.elf
AVR Memory Usage
----------------
Device: atmega328p

Program:   20130 bytes (61.4% Full)
(.text + .data + .bootloader)

Data:        544 bytes (26.6% Full)
(.data + .bss + .noinit)


Finished building: sizedummy
 
Invoking: AVRDude
G:\Arduino-package\arduino-1.0\hardware\tools\avr\bin\avrdude -F -V  -P com3  -b 115200  -p m328p -c arduino -C G:\Arduino-package\arduino-1.0\hardware\tools\avr\etc\avrdude.conf  -U flash:w:arduino-test.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e950f
avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
         To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "arduino-test.hex"
avrdude: input file arduino-test.hex auto detected as Intel Hex
avrdude: writing flash (20130 bytes):

Writing | ################################################## | 100% 3.23s

avrdude: 20130 bytes of flash written

avrdude done.  Thank you.

Finished building: avrdudedummy
 

**** Build Finished ****

 

이렇게 이클립스에서 사용하거나 따로 컴맨드 창에서 동작시켜도 된다.

>avrdude -P com3  -b 115200 -p m328p -c arduino -C../etc/avrdude.conf -F -e -U flash:w:test.hex

 

이런 설정은 하나하나 확인하면서 테스트했었는데. 그럴 필요가 없다. (소스 분석할 때는 없었는데/ ^^;; 완전 나의 삽질~ ㅎ)

hardware/arduino/boards.txt 파일을 보면 아래 arduino uno에 대한 설정 내용이 있다. 이 것만 잘 참조해도  avrdude 바로 쓸 수 있다.

 

uno.name=Arduino Uno
uno.upload.protocol=arduino
uno.upload.maximum_size=32256
uno.upload.speed=115200
uno.bootloader.low_fuses=0xff
uno.bootloader.high_fuses=0xde
uno.bootloader.extended_fuses=0x05
uno.bootloader.path=optiboot
uno.bootloader.file=optiboot_atmega328.hex
uno.bootloader.unlock_bits=0x3F
uno.bootloader.lock_bits=0x0F
uno.build.mcu=atmega328p
uno.build.f_cpu=16000000L
uno.build.core=arduino
uno.build.variant=standar






<예제 파일 돌려보기>

1. 아두이노 스타일 코딩로 코딩하는 것은 어렵지 않다. 잘 동작된다.

main.cpp


#include <Arduino.h>


void setup() {
   pinMode(13, OUTPUT);
}

void loop() {
   digitalWrite(13, HIGH);   // set the LED on
   delay(1000);              // wait for a second
   digitalWrite(13, LOW);    // set the LED off
   delay(1000);              // wait for a second
}

int main(void) {
 init();

#if defined(USBCON)
 USB.attach();
#endif
 
 setup();
   
 for (;;) {
  loop();
  if (serialEventRun) serialEventRun();
 }
       
 return 0;
}





2. 그냥 코딩도 잘 돌아간다.
(http://www.javiervalcarce.eu/wiki/Program_Arduino_with_AVR-GCC에 있는 예제)

main.cpp


#include <avr/io.h>
#include <util/delay.h>

int main (void)
{
  unsigned char counter;
  DDRB = 0xFF;

  while (1)
    {
      PORTB = 0xFF;

      /* wait (10 * 120000) cycles = wait 1200000 cycles */
      counter = 0;
      while (counter != 50)
 {
   /* wait (30000 x 4) cycles = wait 120000 cycles */
   _delay_loop_2(30000);
   counter++;
 }

      /* set PORTB.2 low */
      PORTB = 0x00;

      /* wait (10 * 120000) cycles = wait 1200000 cycles */
      counter = 0;
      while (counter != 50)
 {
   /* wait (30000 x 4) cycles = wait 120000 cycles */
   _delay_loop_2(30000);
   counter++;
 }
    }

  return 1;
}




<project source>




마치며..

이클립스 환경설정하면서 많은 감을 잡은 것 같다. 조금씩 avr도 공부하면서 펌웨어의 즐거움을 즐겨봐야지..
Posted by '김용환'
,

 

<서론>

아두이노 1.0을 바탕으로 윈도우 OS 이클립스에서 아두이노 (AVR) 코딩할 수 있는 환경을 구축하는 방법을 알아보고자 한다.

 

<본론>

1. 가장 먼저 “아두이노 개발툴(pde)”를 설치한다.

나는 1.0 버전으로 설치했다.

 

2. make

mingw 에서 나온 윈도우용 make 유틸리티를 설치한다.

나는 5.1.5 버전을 사용중이다.

http://sourceforge.net/projects/mingw/files/OldFiles/MinGW%205.1.4/MinGW-5.1.4.exe/download 

custom 지정을 잘한다. make을 반드시 설치 목록에 넣어줘야 한다.

 

설치된 mingw/bin 디렉토리를 path에 추가한다.

mingw32-make.exe 파일을 make.exe 파일로 하나 복사해서 사용한다.

 

정상적으로 동작하는지 확인한다.

 

make 유틸리티가 윈도우 path에 등록되어 있지 않으면 이클립스상에서 컴파일은 되지 않는다.

 

**** Build of configuration 328P_16MHz for project arduino-test ****

make all

Error: Cannot run program "make" (in directory "G:\android\workspace\arduino-test\328P_16MHz"): CreateProcess error=2, ??d?? Æ???; ?; ¼? ¾ø

**** Build Finished ****


3. avr Eclipse 플러그인을 설치한다.

http://avr-eclipse.sourceforge.net/wiki/index.php/Plugin_Download 를 참조한다.
플러그인 update 주소는 다음과 같다.

http://avr-eclipse.sourceforge.net/updatesite

AVREclipseInstallUpdatesiteScreenshot.png

(출처 : http://avr-eclipse.sourceforge.net/wiki/index.php/Plugin_Download)

 

4. Preferneces 설정의 AVR Path를 변경

체인툴의 path를 설정해야 한다.

 

path source는 custom으로 하고 설치된 아두이노의 디렉토리를 지정한다.

 

위치 지정은 다음과 같다.

AVG-GCC : hardware\tools\avr\bin
GNU make : hardware\tools\avr\utils\bin
AVR Header Files : hardware\tools\avr\avr\include
AVRDude : hardware\tools\avr\bin

c/c++ / build item에서 Build all configuration in each project를 check on 한다.

 

5. 프로젝트 환경

먼저  c++ 프로젝트를 생성한다.

 

소스 디렉토리를 생성한다.

 

프로젝트의 properties를 설정한다.  내 꺼는 arduino uno이다. MCU type은 Atmgega328P , clock은 16000000로 지정한다.

 

Properties 중 c/c++ build 설정의 “Manage Configuration” 설정을 선택한다.

 

아래와 같은 팝업창에서 “New”버튼을 선택한다.

 

328P_16MHz 라는 이름으로 새로운 설정을 추가한다.

 

OK 버튼을 누르면, 아까 봤던 팝업창이 뜨는데 Set Avice 버튼을 선택한다. 나머지 설정은 다 지운다.

 

AVR tab를 선택하고, 항목에서 Enable시킨다.

 

C/C++ Build –> Settings 설정에서 Configuration 설정에서 328P_16MHz를 선택한다.

 

Settings 아이템의 Additional Tools in Toolchain에서 아래 두 옵션만 check on 한다. (우선은 컴파일하고 바이너리 이미지까지만 만드는 것까지이다.)
”Generate HEX file for flash memroy”, “Print Size”,

 

Tool Settings 밑의 AVR Compiler /Debugging을 선택하고, 정보를 확인한다.

 

AVR Compiler의 Optimization 설정을 다음과 같이 수정한다. 

-Os, 체크박스를 모두 off, "-ffunction-sections -fdata-sections”을 optimization flag로 설정한다.

 

C/C++ Build/Settings 탭의 Tool Settings/AVR Compiler/Language Standard 화면의 옵션을 모두 check off 한다.

 

AVR Compiler의 Directories 설정의 플러스 아이콘을 선택한다.

 


AVR Compiler 의 Directories에 아래 디렉토리를 추가한다. header 파일과 구현 파일들이다.

"G:\Arduino-package\arduino-1.0\hardware\arduino\cores\arduino" : 아두이노 h 및 cpp

"G:\Arduino-package\arduino-1.0\hardware\arduino\variants\standard" : pins_arduino.h

 

AVR Compiler 처럼 AVR C++ Compiler 부분도 똑같이 수정해야 한다. (사실 cpp로 동작하기 때문에 c++ compiler 설정을 더 잘해야 한다.)

 

AVR C++ Compiler/Debugging 설정을 잘 되었는지 확인한다.

 

Optimization 설정도 똑같이 한다.

 

Language Standard도 똑같이 설정한다.

 

Directories도 동일하게 설정한다.

 

 

6. 링커 설정

AVR C++ Linker에서 다음과 같이 설정한다.

Command는 avr-gcc,

Command line pattern은 “ ${COMMAND} -s -Os ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS} -lm ${FLAGS}”으로 지정한다. (복사하면서 유니코드가 들어갈 수 있어 빌드 실패가 일어날 수 있음)

 

그리고, Library 설정은 특별히 하지 않는다.

 

7. 아두이노 디렉토리를 import한다.

Import/Filesystem 을 이용해서 Include된 디렉토리를 참조하게 한다. 이 파일들로 인해서 컴파일 시 참조가 되게 한다.

 

 

8. 컴파일

 

main.cpp 파일에 있는 setup(), loop()를 주석을 제거하거나 exmple 소스 하나를 구현해본다.

 

#include <Arduino.h>


void setup() {
      pinMode(13, OUTPUT);
}

void loop() {
      digitalWrite(13, HIGH);   // set the LED on
      delay(1000);              // wait for a second
      digitalWrite(13, LOW);    // set the LED off
      delay(1000);              // wait for a second
}

int main(void)
{
    init();

#if defined(USBCON)
    USB.attach();
#endif
   
    setup();
   
    for (;;) {
        loop();
        if (serialEventRun) serialEventRun();
    }
       
    return 0;
}

 

잘 생각해보면, 아두이노  개발 툴 에서 setup(), loop()를 구현한 코드에서 main.cpp 와 링킹하면서 바이너리가 만들어지는 모델이라는 점을 쉽게 이해할 수 있다.

 

컴파일을 하려면 툴바에 있는 망치를 선택한다.

 

컴파일하면, 다음과 같이 잘 되는지 확인가능 하다. 빌드 과정을 보면서 지금까지 셋팅한 정보로 컴파일되는지 확인한다.


**** Build of configuration 328P_16MHz for project arduino-test ****

make all
Building file: ../src/main.cpp
Invoking: AVR C++ Compiler
avr-g++  -I"G:\Arduino-package\arduino-1.0\hardware\arduino\cores\arduino" -I"G:\Arduino-package\arduino-1.0\hardware\arduino\variants\standard" -Wall -g2 -gstabs -Os -ffunction-sections -fdata-sections -fno-exceptions -mmcu=atmega328p -DF_CPU=1600000UL -MMD -MP -MF"src/main.d" -MT"src/main.d" -c -o "src/main.o" "../src/main.cpp"
Finished building: ../src/main.cpp
 
Building target: arduino-test.elf
Invoking: AVR C++ Linker
avr-g++ -s -Os -o"arduino-test.elf"  ./src/main.o  ./ref/CDC.o ./ref/HID.o ./ref/HardwareSerial.o
./ref/IPAddress.o ./ref/Print.o ./ref/Stream.o ./ref/Tone.o
./ref/USBCore.o ./ref/WInterrupts.o ./ref/WMath.o ./ref/WString.o
./ref/new.o ./ref/wiring.o ./ref/wiring_analog.o ./ref/wiring_digital.o
./ref/wiring_pulse.o ./ref/wiring_shift.o    -lm -Wl,-Map,arduino-test.map,--cref -mmcu=atmega328p
Finished building target: arduino-test.elf
 
Create Flash image (ihex format)
avr-objcopy -R .eeprom -O ihex arduino-test.elf  "arduino-test.hex"
Finished building: arduino-test.hex
 
Invoking: Print Size
avr-size --format=avr --mcu=atmega328p arduino-test.elf
AVR Memory Usage
----------------
Device: atmega328p

Program:   20130 bytes (61.4% Full)
(.text + .data + .bootloader)

Data:        544 bytes (26.6% Full)
(.data + .bss + .noinit)


Finished building: sizedummy
 

**** Build Finished ****

 

Navigator 또는 Project Explorer로 보면, 아래와 같이 make 파일과 hex, elf 파일이 생성되는지 확인할 수 있다.

 

이제는 이미지 업로드하는 작업을 한다.

Posted by '김용환'
,

 

C 소스를 가지고 윈도우에 설치된 체인툴을 가지고 크로스 컴파일을 해보려고 시도했다.

 

소스에 가장 먼저 #define 되어야 하는 부분은 AVR 타입에 대한 정보이다. 만약 이 부분을 넣지 않으면 warning과 함께 컴파일이 되지 않는다. avr/include/avr 디렉토리의 io.h 파일에 정의되어 있다.

….

#elif defined (__AVR_ATmega328P__)
#  include <avr/iom328p.h

….

#  if !defined(__COMPILING_AVR_LIBC__)
#    warning "device type not defined"
#  endif
#endi

 

아두이노 우노(arduino uno) 라면 ATmega328 프로세스를 사용하고 있으므로, 다음과 같이 정의해야 한다.
#define __AVR_ATmega328P__

또는 avr-gcc 실행시 –mmcpu 파라미터값에 atmega328p를 추가해야 한다.

 

아주 간단한 소스를 컴파일하고 업로드하는 것을 해본다.

<test.c>

#define __AVR_ATmega328P__
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

int main() {
  // 셋업
  DDRB = 0xFF;

  while (1) {
    PORTB = 0xFF;
    _delay_loop_2(1000;
    PORTB = 0x00;
    _delay_loop_2(1000);
  }
}

 

avr 칩에서 동작하는 바이너리 파일을 만든다.

> avr-gcc -O test.c -o test.bin

 

.text와 .data 파일이 포함하는 .hex 파일을 만든다.

>avr-objcopy -j .text -j .data -O ihex test.bin test.hex

 

.hex 파일을 가지고 아두이노 uno에 업로드를 하면 된다.  [속도(b옵션) : 115200, 보드이름(p옵션) arduino 가 반드시 맞아야 한다.] 보드이름에 대한 자세한 정보는 avrdude.conf에 기록 되어 있음

>avrdude -P com3  -b 115200 -p m328p -c arduino -C../etc/avrdude.conf -F -e -U flash:w:test.hex


Posted by '김용환'
,

 

아두이노 개발 툴 1.0에 대한 소스 분석 글이다.

http://knight76.tistory.com/entry/아두이노-개발-툴-소스-10-분석을-위한-환경-셋팅 에 이어 소스 분석을 시작한다.  프로세싱 개발 툴과 너무 흡사한 UI를 가졌기 때문에 소스 분석이 조금 더 쉬운 것 같다.

먼저 빌드 순서를 파악하고, 소스를 파악한다. (짜잘한 것은 제외) 그리고 주석이 약간 틀린 부분이 있었다.ㅠ

1. 빌드 순서


(1) build/build.xml

운영체제(플랫폼)에 맞는 빌드 콜을 호출한다. 윈도우의 경우 windows-build target이 가장 먼저 실행이 된다.

    1) todo.txt 파일의 revistion 숫자, processing/app/Base.java 파일의 revision 정보와 비교해서 revision 번호를 맞춘다.

    2) 윈도우 운영체제인지 확인한다.

    3) core 디렉토리와 app 디렉토리에 ant 컴파일을 시킨다.

       -  core/build.xml
           core 디렉토리를 컴파일하고 bin/core.jar 파일을 만든다.

       -  app/build.xml
           app 디렉토리를 컴파일하고, bin/pde.jar 파일을 만든다.

4) windows/work 디렉토리를 생성 후, 실행에 필요한 libraray (jar, dll)과 driver 파일들을 복사한다. 그리고, window/work/hardware 디렉토리에 윈도우에서 동작할 수 있는 avr 툴(avr 체인) 압축 파일을 풀어둔다.

5) windows/work 디렉토리의 여러 디렉토리에 셋팅을 한다.

    1) windows/work/tools 디렉토리에 Mangler.java 소스를 복사한다.

    2) window/work/library 디렉토리에 아두이노 library 파일을 복사한다.

    3) window/work/hardware 디렉토리에  아두이노 부트로더, 펌웨어등을 복사한다.

    3) window/work/example 디렉토리에는 간단히 예제들을 복사해둔다.

6) launch관련 파일들을 모은다. launch4j와 설정파일, 관련 클래스들을 모아둔다.

7) launch4j를 실행하고, 컴파일하고 링킁하고 실행파일(build\windows\work\arduino.exe)을 생성한다.

launch4j를 이용하여 exe 파일을 만드는 config.xml 파일이다.

<launch4jConfig>
  <dontWrapJar>true</dontWrapJar>
  <headerType>gui</headerType>
  <jar>lib</jar>
  <outfile>arduino.exe</outfile>
  <errTitle></errTitle>
  <cmdLine></cmdLine>
  <chdir>.</chdir>
  <priority>normal</priority>
  <downloadUrl>http://java.sun.com/javase/downloads/</downloadUrl>
  <supportUrl></supportUrl>
  <customProcName>false</customProcName>
  <stayAlive>false</stayAlive>
  <manifest></manifest>
  <icon>application.ico</icon>
  <classPath>
   <mainClass>processing.app.Base</mainClass>
    <cp>lib/pde.jar</cp>
    <cp>lib/core.jar</cp>
    <cp>lib/jna.jar</cp>
    <cp>lib/ecj.jar</cp>
    <cp>lib/RXTXcomm.jar</cp>

  </classPath>
  <jre>
    <path>java</path>
    <minVersion>1.5.0</minVersion>
    <maxVersion></maxVersion>
    <jdkPreference>preferJre</jdkPreference>
    <opt>-Xms128m -Xmx128m</opt>
  </jre>
  <splash>
    <file>about.bmp</file>
    <waitForWindow>true</waitForWindow>
    <timeout>60</timeout>
    <timeoutErr>true</timeoutErr>

  </splash>
  <messages>
    <startupErr>An error occurred while starting the application.</startupErr>
    <bundledJreErr>This application was configured to use a bundled Java Runtime Environment but the runtime is missing or corrupted.</bundledJreErr>
    <jreVersionErr>This application requires at least Java Development Kit</jreVersionErr>
    <launcherErr>The registry refers to a nonexistent Java Development Kit  installation or the runtime is corrupted.</launcherErr>
    <instanceAlreadyExistsMsg>An application instance is already running.</instanceAlreadyExistsMsg>
  </messages>
</launch4jConfig>

 

2. UI (Editor)

processing.app.Base.java 소스에 main 메서드를 따라가 본다.

OS(플랫폼)을 확인하고, preferences.txt 프로퍼티 화일(크기..)을 읽는다. theme/theme.txt 프로퍼티 설정을 읽어 editor에 대한 프로퍼티를 확인한다. look&feel 을 설정후, 임시폴더를 만들고 Base 객체를 생성한다.

Base 생성자 코드를 따라가면, examples, libraries, tools 디렉토리 패스와 프로젝트 파일로 저장할 path (sketchbook path) 를 지정해둔다. hardware 디렉토리를 잘 기억한다. Editor 클래스를 초기화하여 UI를 실행한다. 이전에 아두이노 개발 툴을 종료했을 때 사용했던 스케치 파일이 있었으면 툴 실행시 스케치 파일을 열어둔다.

UI에 관련된 대부분의 특징은 프로세싱 개발 툴과 흡사하다. processing.app 패키지 밑에 잘 들어가 있다.

운영체제에 맞는 특징에 대해서는 운영체제별로 Platform.java 소스에 dependant한 코드들이 들어가 있다. 재미있는 것은 아두이노 오픈 소스 개발자가 macosx 쪽에 Think Different 클래스를 추가했다. 오픈소스의 센스라고 해야 하나 ㅎㅎ 먼가 대단하다고 생각한 코드는 아니지만 웃음코드에 박수~

public class Platform extends processing.app.Platform {

….

public void init(Base base) {
  System.setProperty("apple.laf.useScreenMenuBar", "true");
ThinkDifferent.init(base);
  ..

}

 

public class ThinkDifferent implements ApplicationListener {

… OS X application 이벤트 (open, about 등등)에 대해서 처리하려고 만들었다.

}

아두이노 개발 툴을 UI 초기화하고 menu를 생성하고 editor를 만들면서.. serial port 정보와 타겟 보드가 나와있는데, 이는 processing.app.EditorLineStatus.java 클래스에서 설정 파일을 읽어오는 코드로 동작하게 되어 있다.

맨 처음 읽을 때는 preference.txt 파일에 있는 설정 정보를 읽는다. 이전에 Serial 포트 변경이 있을 때마다 설정값을 변경시키도록 되어 있따.

# ARDUINO PREFERENCES
board = uno
target = arduino

serial.port=COM1

 

3. 아두이노 개발 툴의 스케치 파일 읽고 쓰기

파일을 읽는 시퀀스는 그냥 평범하다.

EditorHeader.rebuildMenu() –> SkechCode.load() –> Base.loadFile() –> PApplet.loadStrings() –>PApplet.createInput() 로 이어져 있다. 파일을 line을 seperator로 String[](내부적으로는 BufferedReader(FileInputStream)클래스를 사용)타입으로 간단하게 파일을 일고, PApplet.join() 메서드에서 String[]에 line separator를 넣어서 String 객체로 리턴한다.

파일을 쓰는 구조는 추측할 수 있도록 파일을 읽는 반대로 구성되어 있다.

 

4. Sketch 파일

아두이노 개발 툴에서 저장하는 파일들을 스케치(Sketch) 라고 한다. 무엇인가를 그리고 거기에 맞게 그린다는 차원에서는 좋아 보이는 개념인 것 같다. processing.app.Sketch.java 클래스는 pde, java 확장자를 지원하고 cpp를 지원하지 않는다. 또한 여러 버그로 인한 많은 땜질 코드들이 보인다. 

processing.app.SketchCode.java 클래스는 코드 자체를 의미하는 클래스로서, 코드가 읽고, 쓰고, 변경될 때 사용되는 클래스이다.

 

 

5. Compile

빌드 Call stack은 다음과 같다.

에디터에서 빌드메뉴를 선택하면, Editor.buildSketchMenu() –>Editor.handleRun()->Editor.presentHandler()
->Thread인 headerListFromIncludePath.run() –> Sketch.build() 로 진행한다.

 

   (1) 전처리 (preprocessor)

컴파일을 하기 전에 전처리(preprocess) 과정을 거친다. Sketch.preprocess() , PdePreprocessor.preprocess()을 참조한다. 소스에 맨 끝에는 \n과 멀티 라인으로 된 주석은 정리되도록 했다. OOME 나 NPE가 발생한 적이 있는 듯 하다. unicode 설정에 되어 있으면 소스를 unicode로 바꾼다.

pde 나 ino 확장자는 가진 파일들은 include 헤더 파일 스트링을 찾아서 저장해 둔다. 소스에서 컴파일과 관련없이 주석, 전처리 지시자, 싱글/더블 따옴표를 모두 스페이스로 만들어버리고 함수 이외 지역에 사용했던 top level brace를 뺀다.  include header 와 정리된 prototype의 line수를 저장해서 나중에 소스를 만들 때 이용한다.

C++ 클래스를 하나 만들어 pde/ino파일에서 사용했던 include 헤더 파일과 #include “Arduino.h”를 추가하고, 잘 정리한 prototype을 넣은 후 cpp 파일로 만들고 컴파일 한다.

 

  (2) 컴파일

Compiler.compile() 메서드에서 정의하고 있는 컴파일러는 avr-gcc (호스트환경은 윈도우이지만, 타겟보드에서 실행할 수 있도록 cross 컴파일을 지원하는 컴파일러) 를 사용하고 있다.  avr base path는 hardware/tools/avr/bin/ 디렉토리를 기준으로 한다.

보드(아두이노 우노)에 맞는 core 라이브러리들이 참조될 수 있도록 라이브러리(hardware\arduino\cores\arduino 디렉토리 밑에 있는 h, cpp 파일들) 들을 잘 정리해둔다.  sketch 파일을 찾아 리스트에 추가하고 컴파일한다.   variants도 필요하면 path에 추가해준다.

    1) 스케치 파일 컴파일

    --- path 디렉토리에 s 확장자로 끝나는 파일을 컴파일

command 창에서 동작할 수 있도록 명령어를 조합하고 object 파일을 만들기 위해서 gcc 컴파일을 실행한다.

    avr-gcc –c –g -assembler-with-cpp -mmcu={$mcu} -DF_CPU={$cpu} -DARDUINO={$number}  –I{IncludePath} {$source file} –o {$object name}

    --- path 디렉토리에 c 확장자로 끝나는 파일을 컴파일

avr-gcc –c –g –Os –Wall –ffunction-section –fdata-section -mmcu={$mcu} -DF_CPU={$cpu} –MMD -DARDUINO={$number}  –I{IncludePath} {$source file} –o {$object name}

    --- path 디렉토리에 cpp 확장자로 끝나는 파일을 컴파일

avr-gcc –c –g –Os –Wall -fno-exceptions –ffunction-section –fdata-section -mmcu={$mcu} -DF_CPU={$cpu} –MMD -DARDUINO={$number}  –I{IncludePath} {$source file} –o {$object name}

 

     2) 라이브러리 컴파일

아두이노 개발 툴에서 짠 소스에서의 include 헤더에 대한 정보들을 모아 관련 디렉토리에서 컴파일한다. 컴파일 하는 방법은 s, c, cpp 확장자로 끝나는 파일로 위의 컴파일 방법과 같다.

    3) 코어 파일 컴파일

cores 디렉토리 밑에 있는 파일들을 찾아 컴파일하고 core.a 파일로 만든다.

avr-ar rcs core.a  파일들

     4) 링킹

avr-gcc –Os -Wl,--gc-sections -mmcu=atmega328p –o  {$primaryclass}.elf  {$objectfile} core.a –L{$buildpath} –lm

     5) EEPROM data 를 만들기

avr-objcopy –O –R  ihex  -j .eeprom --set-section-flags=.eeprom=alloc,load  --no-change-warnings  --change-section-lma .eeprom=0 {$primaryclass}.elf  {$primaryclass}.eep

     6) .hex 파일 만들기

avr-objcopy –O –R  ihex  .eeprom {$primaryclass}.elf  {$primaryclass}.eep

 

 

(3)  보드에 이미지 업로드

EEPROM data를 잘 구워 아두이노 보드에 넣는(upload) 작업을 할 때, processing.app.Upload 클래스, AvrdudeUploader 클래스를 사용한다. 부트 로더를 굽거나 (burn bootlaoder) 할 떄도 사용된다.

Sketch.upload() –> AvrdudeUploader.uploadUsingPreferences() –>AvrdudeUploader.avrdude() 를 호출하는 구조로 되어 있으며, avrdude 라는 명령어를 이용해서 플래쉬에 hex 파일을 굽는다. (-Uflash:w:파일.hex:i’ )

 아두이노의 부트로더를 굽는 방법은 avrdude 명령어에 -Uefuse:w:~~~ 옵션을 넣는다. 

통신방법은 여러가지가 있다. 아마도 운영체제 때문으로 생각된다. 만약 -Pusb 파라미터를 주어서 usb로 통신할 수 있으며, -P {serial port 번호 } 파라미터를 주어서 serial port로 통신할수도 있다.

-b 파라미터로 굽는 속도를 조절할 수 있다. 
 


그리고, Serial 객체를 생성해서 통신하도록 되어 있다.
Serial 클래스는 내부적으로 gnu.io 패키지의 포트 정보를 확인하는 CommPortIdentifier 클래스를 사용하고 있으며, MessageConsumer에 대한 리스너 등록, 이벤트 발생, 데이터를 읽는 형태를 가지고 있다.

 

(4) 윈도우 사용시 레지스트리 이용 - jna

처음 시작할 때, 윈도우에서 ino, pde 파일을 더블 클릭했을 때 아두이노.exe 파일을 실행시키기 위해서, 윈도우 레지스트리에 추가된다. 관련 파일은 Platform.checkAssociations(), Registry 클래스, Advapi32 클래스이다. 여기서도 processing처럼 jna를 아주 잘 쓰고 있다.

public interface Advapi32  extends StdCallLibrary  {

Advapi32 INSTANCE = (Advapi32) Native.loadLibrary("Advapi32", Advapi32.class, Options.UNICODE_OPTIONS);
..
}

 

이상 끝.. 자바로 만들어져서 소스가 어렵지 않다.


참고...
아두이노 개발 툴 없이 소스와 툴만 가지고 컴파일할 때 사용하는 방법은 다음과 같다. 소스에서 사용하는 컴파일 방법과 동일하다.

http://andrew-j-norman.blogspot.com/2011/12/bypassing-ide.html

Posted by '김용환'
,

 

프로세싱(Processing) 개발 툴을 분석하고 나면,  아두이노 개발 툴 소스 분석은 더 쉽다. 
아두이노 개발 툴은 프로세싱 개발 툴 소스 depedency가 있거나 복사된 소스들이 많다.  (정확히 역사는 어떻게 되었는지는 모르지만..^^;)

1. 소스를 다운받는다.

http://www.arduino.cc/en/Main/software  페이지에서 소스를 다운받는다.

 

2. 이클립스 프로젝트 환경 구축

이클립스 프로젝트를 하나 생성하고 다운받은 소스를 복사한다. 아두이노 개발 툴 안에 이클립스 설정이 파일이 있다.

 

아두이노 개발 툴의 build path를 살펴보면, processing-core를 참조하고 있다. (processing.core 패키지를 참조하고 있다.)

 

프로세싱 소스는 아래 위치에서 git로 다운받는다.

http://code.google.com/p/processing/source/checkout

 

프로세싱 코드는 2.0으로 다운받으면, processing.app.RunnerListener 인터페이스를 모두 상속해서 구현하지 않았다고 아두이노 개발 툴 소스의 Editor 클래스 컴파일 에러가 난다. API 구현해주면 깨끗하게 컴파일 완료된다.

public class Editor extends JFrame implements RunnerListener {

…..


@Override
public void startIndeterminate() {
    // TODO Auto-generated method stub
   
}


@Override
public void stopIndeterminate() {
    // TODO Auto-generated method stub
   
}


@Override
public void statusHalt() {
    // TODO Auto-generated method stub
   
}


@Override
public boolean isHalted() {
    // TODO Auto-generated method stub
    return false;
}

 

컴파일 완료된 상태

<아두이노 소스>

 

빌드 연동

 

프로세싱 소스 (core/src 디렉토리의 소스만 잘 빌드되면 됨)

 

3. 소스 디렉토리 확인

UI 부분은 프로세싱과 거의 동일하다.

 

디버그 관련 패키지가 들어가 있다.  컴파일도 하고 실행했을 때 output 처리하는 것들. arduino 보드에 올리는 클래스들이 담겨 있다.

 

프로세싱 개발 툴은 java 기반이지만, 아두이노 개발 툴은 자바 기반 언어대신 C 언어의 특성을 가지고 있다.  (그래서 antlr는 사용할 필요가 없다.)
그러나 화면에 출력되는 문법에 맞는 색상을 칠해주는 패키지이다.

 

이 외. 운영체제(플랫폼)에 맞는 다양한 작업 패키지들이 있다. 여기도 프로세싱 개발 툴처럼  jna가 쓰이고 있다.

processing.app.linux, processing.app.windows, processing.app.macosx


4. 빌드

빌드는 build 디렉토리에 있는 build.xml를 가지고 ant 컴파일 하면 된다.

Buildfile: G:\workspace\arduino-1.0\build\build.xml
build:
revision-check:
windows-checkos:
subprojects-build:
compile:
....
 [launch4j] Compiling resources
 [launch4j] Linking
 [launch4j] Successfully created G:\workspace\arduino-1.0\build\windows\work\arduino.exe
BUILD SUCCESSFUL
Total time: 44 seconds


 

Posted by '김용환'
,

 

첫번째 정리 : http://knight76.tistory.com/entry/프로세싱-언어와-PDE-코드-살펴보기-1

 

2번째 내용 시작

process/app/src 소스를 보면서 접근했다. JDI 코드 부분을 제외한 전반적인 코드를 분석한다.

 

1. Base, Editor 클래스

main 클래스는 processing.app.Base.java 이다.

Base 클래스의 createAndShowGUI() 메서드는 간단하게 버전 정도를 확인하고 swing component를 생성하고 나서 jdk 의 버전을 확인한다. 그리고, 설정 정보(윈도우 크기 등)을 읽는다. OS에 맞는 환경(platform)을 잘 생성하여 어디에서도 문제없이 동작하게 한다. 임시 디렉토리도 확인한 후, Base 클래스의 생성자를 호출한다.

 

* Base 클래스의 main 함수와 관련 메서드

public class Base {


  static public void main(final String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
          createAndShowGUI(args);
        }
    });
  }

  static private void createAndShowGUI(String[] args) {
    try {
      File versionFile = getContentFile("lib/version.txt");
      if (versionFile.exists()) {
        String version = PApplet.loadStrings(versionFile)[0];
        if (!version.equals(VERSION_NAME)) {
          VERSION_NAME = version;
          RELEASE = true;
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
    }

    initPlatform();

    // Use native popups so they don't look so crappy on osx
    JPopupMenu.setDefaultLightWeightPopupEnabled(false);

    // Don't put anything above this line that might make GUI,
    // because the platform has to be inited properly first.

    // Make sure a full JDK is installed
    initRequirements();

    // run static initialization that grabs all the prefs
    Preferences.init(null);

//    String filename = args.length > 1 ? args[0] : null;
    if (!SingleInstance.exists(args)) {
      SingleInstance.createServer(platform);

      // Set the look and feel before opening the window
      try {
        platform.setLookAndFeel();
      } catch (Exception e) {
        String mess = e.getMessage();
        if (mess.indexOf("ch.randelshofer.quaqua.QuaquaLookAndFeel") == -1) {
          System.err.println("Non-fatal error while setting the Look & Feel.");
          System.err.println("The error message follows, however Processing should run fine.");
          System.err.println(mess);
        }
      }

      // Create a location for untitled sketches
      try {
        untitledFolder = Base.createTempFolder("untitled", "sketches");
        untitledFolder.deleteOnExit();
      } catch (IOException e) {
        //e.printStackTrace();
        Base.showError("Trouble without a name",
                       "Could not create a place to store untitled sketches.\n" +
                       "That's gonna prevent us from continuing.", e);
      }

//  System.out.println("about to create base...");
      new Base(args);
//  System.out.println("done creating base...");
    }
  }

 

Base 클래스의 생성자에서는 스케치 북 (프로세싱 디렉토리) 폴더를 확인한다. mode 디렉토리 안에 있는  jar나 zip으로 끝나는 파일들을 모아서 classpath에 넣어서 컴파일시 유용하게 사용할 수 있도록 한다. java/android/javascript를 지원하고 있다.

OS에 맞는 UI (look & Feel)에 맞게 Editor 클래스(JFrame)을 초기화한다. 프로세싱 pde 툴을 작업하고 종료했으면, 기존에 저장된 소스를 불러온다. 만약 그런 경우가 없다면 빈 화면만 보이게 한다.

만약  PDE 개발툴의 업데이트가 존재하면 알려준다.

public Base(String[] args) {
    // Get the sketchbook path, and make sure it's set properly
    determineSketchbookFolder();

    // Delete all modes and tools that have been flagged for deletion before
    // they are initialized by an editor.
    ArrayList<InstalledContribution> contribs = new ArrayList<InstalledContribution>();
    contribs.addAll(ModeContribution.list(this, getSketchbookModesFolder()));
    contribs.addAll(ToolContribution.list(getSketchbookToolsFolder(), false));
    for (InstalledContribution contrib : contribs) {
      if (ContributionManager.isFlaggedForDeletion(contrib)) {
        removeDir(contrib.getFolder());
      }
    }

    buildCoreModes();
    rebuildContribModes();

    libraryManagerFrame = new ContributionManagerDialog("Library Manager",
                                                        new ContributionListing.Filter() {
      public boolean matches(Contribution contrib) {
        return contrib.getType() == Contribution.Type.LIBRARY
            || contrib.getType() == Contribution.Type.LIBRARY_COMPILATION;
      }
    });
    toolManagerFrame = new ContributionManagerDialog("Tool Manager",
                                                     new ContributionListing.Filter() {
      public boolean matches(Contribution contrib) {
        return contrib.getType() == Contribution.Type.TOOL;
      }
    });
    modeManagerFrame = new ContributionManagerDialog("Mode Manager",
                                                     new ContributionListing.Filter() {
      public boolean matches(Contribution contrib) {
        return contrib.getType() == Contribution.Type.MODE;
      }
    });
    updateManagerFrame = new ContributionManagerDialog("Update Manager",
                                                       new ContributionListing.Filter() {
      public boolean matches(Contribution contrib) {
        if (contrib instanceof InstalledContribution) {
          return ContributionListing.getInstance().hasUpdates(contrib);
        }

        return false;
      }
    });

    // Make sure ThinkDifferent has library examples too
    defaultMode.rebuildLibraryList();

    // Put this after loading the examples, so that building the default file
    // menu works on Mac OS X (since it needs examplesFolder to be set).
    platform.init(this);

    toolsFolder = getContentFile("tools");

//    // Get the sketchbook path, and make sure it's set properly
//    determineSketchbookFolder();

//    // Check if there were previously opened sketches to be restored
//    boolean opened = restoreSketches();
    boolean opened = false;

    // Check if any files were passed in on the command line
    for (int i = 0; i < args.length; i++) {
      String path = args[i];
      // Fix a problem with systems that use a non-ASCII languages. Paths are
      // being passed in with 8.3 syntax, which makes the sketch loader code
      // unhappy, since the sketch folder naming doesn't match up correctly.
      // http://dev.processing.org/bugs/show_bug.cgi?id=1089
      if (isWindows()) {
        try {
          File file = new File(args[i]);
          path = file.getCanonicalPath();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      if (handleOpen(path) != null) {
        opened = true;
      }
    }

    // Create a new empty window (will be replaced with any files to be opened)
    if (!opened) {
//      System.out.println("opening a new window");
      handleNew();
//    } else {
//      System.out.println("something else was opened");
    }

    // check for updates
    if (Preferences.getBoolean("update.check")) {
      new UpdateCheck(this);
    }
  }

 

Editor 클래스는 JFrame을 상속했으며, 화면 UI를 담당한다.

public abstract class Editor extends JFrame implements RunnerListener

에디터의 기본 내용들은 processing.app 패키지에 담겨져 있다.

 

2. Contribution

여기에 기존 library외에 특정 폴더에 lib 또는 zip파일을 복사하면 프로세싱 pde 툴이 시작하면서 그 파일들을 모두 읽는다. 이런 파일들을 processing 툴에서는 contribution이라는 단어를 써서 하고 있다. 파일을 다운받고 설치할 수 있기도 하고, 메뉴에서 refresh 해서 다시 library 정보를 취합할 수 있다. 관련 내용은 processing.app.contrib.ContributionManager.java 과 processing.app.contrib.Contribution.java 에 담겨있다.

 

3. Process

안드로이드환경에서 avd를 생성하거나 출력, adb, keytool, mv 명령을 내릴 때 필요한 정보들은 processing.app.exec 패키지에 담겨 있다.

 

4. Platform

linux, mac, window 에 맞는 UI를 실행시키거나 OS-dependent한 코드들을 실행할 때 필요한 내용들이 담겨 있다. 예를 들어 윈도우의 경우 폴더를 실행시킬 때, explorer를 실행시켜야 한다. 또한 msvcrt.dll(printf와 같은 stdio/stdout에 해당되는 c 런타임 라이브러리로서 sta)를 jna로 연결한다. 그리고, 마우스 오른쪽 버튼 연동을 하여 자바 Swing 어플에서 폴더를 열 때, 윈도우에서 폴더 열어서 이것 저것(예, 폴더 생성)을 할 수 있게 처리하는 코드가 담겨 있다.

관련 패키지는 processing.app.windows, processing.app.linux, processing.app.macosx  이다.

 

5. Syntax

processing.app.DefaultInputHander 클래스 소스에서는 Editor를 사용하기 때문에 키보드로부터 다양한 입력이 들어오는데. 미리 저장해둔 키보드 액션 값(Ctrl + C와 같은 복사)인지 코드(Code)인지를 분간한다. 또한, 예전 JEdit Syntax (syntax.jedit.org) 의 Code highlight 형식을 적용하여 예쁘게 색칠해 준다. 키워드일 때는 색깔을 입혀 코드 작성자가 깜박하지 않도록 도와준다.

코드를 토큰을 줄 단위로 나눈 후 토큰을 토큰 리스트(linked list)로 연결했다.

 

관련 코드는 processing.app.syntax에 있다.

 

6. tools

소스를 압축하고, 색깔을 선택하거나, 인코딩, 폰트 설정과 같은 Tool 성격의 클래스가 담겨져 있다.

 

7, mode

프로세싱은 android, javascript, java 중 세가지 모드로 export할 수 있는 코드로 구성되어 있다.

이 중 특별하게 javascript mode는 javascript 코드를 작성하면, 이를 processing.js 파일로 만든 후, 소스는 그냥 PApplet 클래스로 해서  웹 브라우져로 보여주도록 코드 작성이 되어 있다. processing.mode.javascript 패키지에 내용이 담겨 있다.

그리고, android mode는 avd도 연동할 수 있도록 편리한 클래스를 제공하고 있다. processing.mode.android 패키지에 잘 설명이 되어 있다. 완전히 안드로이드 향에서 동작되어 있는 코드로 되어 있다. 자세한 것은 안보고 패쓰.. 중요한 것은 java에 있으니 그곳으로 집중.

마지막으로 남은  java mode를 살펴본다. java mode에서는 antlr과 java debug interface를 사용하고 있었다. (사실 이 것 때문에 소스 분석한 것이긴 하다.)

 

먼저 빌드(app/build.xml) 소스를 확인해 본다.

가정 먼저 antlr 문법에 맞게 전처리 작업을 전행한다. processing/mode/java/preporc/java15.g 파일을 읽어서 소스 generate 한다. 그 다음 같은 디렉토리에 있는 pde.g 파일을 읽고 소스를 generate 한다.

 

 

  <property name="generated"
        value="${basedir}/generated/processing/mode/java/preproc" />
  <mkdir dir="${generated}" />

  <property name="grammars"
        value="${basedir}/src/processing/mode/java/preproc" />

 

……………..

<target name="preproc" description="Compile ANTLR grammar">
    <antlr target="${grammars}/java15.g" outputdirectory="${generated}">
      <classpath path="${antlrjar}" />
    </antlr>
    <antlr target="${grammars}/pde.g"
       outputdirectory="${generated}"
       glib="${grammars}/java15.g">
      <classpath path="${antlrjar}" />
    </antlr>
  </target>

  <target name="compile" depends="preproc" description="Compile sources">
    <condition property="core-built">
      <available file="../core/core.jar" />
    </condition>
    <fail unless="core-built"
      message="Please build the core library first and make sure it sits in ../core/core.jar" />

    <mkdir dir="bin" />

 

java15.g는 antlr이 이해할 수 있는 java1.5 언어 문법 파일이다. 이 파일이 antlr에 의해서 생성되는 클래스는 파서(class JavaRecognizer extends Parser) 과 스캐너 (class JavaLexer extends Lexer) 이다. 그리고, pde.g 은 antlr에 의해서 파서(class PdeRecognizer extends JavaRecognizer)와 스캐너 (class PdeLexer extends JavaLexer)와 토큰에 대한 정의 정보 (interface PdeTokenTypes)가 생성된다.

컴파일된 클래스는 아래 위치에서 확인해 볼 수 있었다.

G:\android\workspace\processing\app\bin\processing\mode\java\preproc

 

프로세싱 PDE에서 application 또는 applet으로 export 할 때, 빌드가 일어나고 실행할 수 있게 되어 있다. processing.mode.java.JavaBuild.java가 중요 핵심 클래스가 된다. 

processing.mode.java.JavaBuild 클래스의 exportApplication() 메서드에서 application빌드하고  exportApplication(File destFolder, int exportPlatform,int exportBits) 메서드에서 실행을 한다.

만약 윈도우라면 아래와 같이 자바가 실행이 된다.


if (exportPlatform == PConstants.WINDOWS) {
      if (exportBits == 64) {
        // We don't yet have a 64-bit launcher, so this is a workaround for now.
        File batFile = new File(destFolder, sketch.getName() + ".bat");
        PrintWriter writer = PApplet.createWriter(batFile);
        writer.println("@echo off");
        writer.println("java -Djava.ext.dirs=lib -Djava.library.path=lib " + sketch.getName());
        writer.flush();
        writer.close();
      } else {
        Base.copyFile(mode.getContentFile("application/template.exe"),
                      new File(destFolder, sketch.getName() + ".exe"));
      }
    }

 

빌드과정을 조금 따라가 본다.

processing.mode.java.JavaBuild.java 파일의 build 파일이 실행되는 시점부터 코드를 따라간다. 먼저 전처리 과정을 한 후, 컴파일을 한다.

  public String build(File srcFolder, File binFolder) throws SketchException {
    this.srcFolder = srcFolder;
    this.binFolder = binFolder;

//    Base.openFolder(srcFolder);
//    Base.openFolder(binFolder);
   
    // run the preprocessor
    String classNameFound = preprocess(srcFolder);

    // compile the program. errors will happen as a RunnerException
    // that will bubble up to whomever called build().
//    Compiler compiler = new Compiler(this);
//    String bootClasses = System.getProperty("sun.boot.class.path");
//    if (compiler.compile(this, srcFolder, binFolder, primaryClassName, getClassPath(), bootClasses)) {
    if (Compiler.compile(this)) {
      sketchClassName = classNameFound;
      return classNameFound;
    }
    return null;
  }

 

processing.mode.java.preproc.PdePreprocessor.preprocess() 메서드가 호출되면, 파서가 가장 먼저 동작한다. 파서가 만든 AST tree를 traverse할 수 있는 pdeEmitter를 사용한다. PrintWriter 객체에 java로 컴파일가능한 소스를 생성한다. 그리고 classpath 에 library를 추가하고, 임시 파일을 생성(Base.saveFile()호출)한다. 그리고, 원래대로 돌아가 컴파일 하는 구조이다.


8. JDI (java debugger interface)
JPDA의 하이 레벨의 인터페이스인 JDI를 정의하는 코드가 processing.mode.java.runner 패키지에 담겨있다.

어플리케이션에서 run 또는 present를 실행시 JavaMode클래스의 handleRun메서드를 실행하고,
Runner  클래스의   launchVirtualMachine()메소드 실행으로 이어진다.
실제 어플리케이션에서 어플리케이션을 실행시키면서 jpda로 연결해서 테스트가 가능할 수 있도록 한다.


 Runner 클래스의 launch 메서드는 다음처럼 먼저 vm을 실행시키고, trace 를 생성한다.

public void launch(boolean presenting) {
    this.presenting = presenting;
   
    // all params have to be stored as separate items,
    // so a growable array needs to be used. i.e. -Xms128m -Xmx1024m
    // will throw an error if it's shoved into a single array element
    //Vector params = new Vector();

    // get around Apple's Java 1.5 bugs
    //params.add("/System/Library/Frameworks/JavaVM.framework/Versions/1.4.2/Commands/java");
    //params.add("java");
    //System.out.println("0");

    String[] machineParamList = getMachineParams();
    String[] sketchParamList = getSketchParams();

    vm = launchVirtualMachine(machineParamList, sketchParamList);
    if (vm != null) {
      generateTrace(null);
//      try {
//        generateTrace(new PrintWriter("/Users/fry/Desktop/output.txt"));
//      } catch (Exception e) {
//        e.printStackTrace();
//      }
    }
  }




VM 실행에 대한 코드이다.  debug에 대한 정보가 보인다.


  protected VirtualMachine launchVirtualMachine(String[] vmParams,
                                                String[] classParams) {
    //vm = launchTarget(sb.toString());
    LaunchingConnector connector = (LaunchingConnector)
      findConnector("com.sun.jdi.RawCommandLineLaunch");
    //PApplet.println(connector);  // gets the defaults

    //Map arguments = connectorArguments(connector, mainArgs);
    Map arguments = connector.defaultArguments();

    Connector.Argument commandArg =
      (Connector.Argument)arguments.get("command");
    // Using localhost instead of 127.0.0.1 sometimes causes a
    // "Transport Error 202" error message when trying to run.
    // http://dev.processing.org/bugs/show_bug.cgi?id=895
    String addr = "127.0.0.1:" + (8000 + (int) (Math.random() * 1000));
    //String addr = "localhost:" + (8000 + (int) (Math.random() * 1000));
    //String addr = "" + (8000 + (int) (Math.random() * 1000));

    String commandArgs =
      "java -Xrunjdwp:transport=dt_socket,address=" + addr + ",suspend=y ";
    if (Base.isWindows()) {
      commandArgs =
        "java -Xrunjdwp:transport=dt_shmem,address=" + addr + ",suspend=y ";
    } else if (Base.isMacOS()) {
      commandArgs =
        "java -d" + Base.getNativeBits() + //Preferences.get("run.options.bits") + 
        " -Xrunjdwp:transport=dt_socket,address=" + addr + ",suspend=y ";
    }

    for (int i = 0; i < vmParams.length; i++) {
      commandArgs = addArgument(commandArgs, vmParams[i], ' ');
    }
    if (classParams != null) {
      for (int i = 0; i < classParams.length; i++) {
        commandArgs = addArgument(commandArgs, classParams[i], ' ');
      }
    }
    commandArg.setValue(commandArgs);

    Connector.Argument addressArg =
      (Connector.Argument)arguments.get("address");
    addressArg.setValue(addr);

    //PApplet.println(connector);  // prints the current
    //com.sun.tools.jdi.AbstractLauncher al;
    //com.sun.tools.jdi.RawCommandLineLauncher rcll;

    //System.out.println(PApplet.javaVersion);
    // http://java.sun.com/j2se/1.5.0/docs/guide/jpda/conninv.html#sunlaunch

      return connector.launch(arguments);






trace를 생성하는 메서드이다. VM에 대해서 debug trace를 걸고, event thread 를 생성한다.
VM을 띄운 후, 어플리케이션 출력코드를 다 받아와 editor에 화면에 보여줄 수 있도록 한다.

  /**
   * Generate the trace.
   * Enable events, start thread to display events,
   * start threads to forward remote error and output streams,
   * resume the remote VM, wait for the final event, and shutdown.
   */
  protected void generateTrace(PrintWriter writer) {
    vm.setDebugTraceMode(debugTraceMode);

    EventThread eventThread = null;
    //if (writer != null) {
    eventThread = new EventThread(this, vm, excludes, writer);
    eventThread.setEventRequests(watchFields);
    eventThread.start();
    //}

    //redirectOutput();

    Process process = vm.process();

//  processInput = new SystemOutSiphon(process.getInputStream());
//  processError = new MessageSiphon(process.getErrorStream(), this);

    // Copy target's output and error to our output and error.
//    errThread = new StreamRedirectThread("error reader",
//        process.getErrorStream(),
//        System.err);
    MessageSiphon ms = new MessageSiphon(process.getErrorStream(), this);
    errThread = ms.getThread();

    outThread = new StreamRedirectThread("output reader",
        process.getInputStream(),
        System.out);

    errThread.start();
    outThread.start();

    vm.resume();
    //System.out.println("done with resume");

    // Shutdown begins when event thread terminates
    try {
      if (eventThread != null) eventThread.join();
//      System.out.println("in here");
      // Bug #852 tracked to this next line in the code.
      // http://dev.processing.org/bugs/show_bug.cgi?id=852
      errThread.join(); // Make sure output is forwarded
//      System.out.println("and then");
      outThread.join(); // before we exit
//      System.out.println("out of it");

      // At this point, disable the run button.
      // This happens when the sketch is exited by hitting ESC,
      // or the user manually closes the sketch window.
      // TODO this should be handled better, should it not?
      if (editor != null) {
        editor.deactivateRun();
      }
    } catch (InterruptedException exc) {
      // we don't interrupt
    }
    //System.out.println("and leaving");
    if (writer != null) writer.close();
  }




전형적인 JPDA FE 쓰레드를 사용하고 있으며, 어플리케이션에서 어플리케이션을 띄우고 관련 로그를 부모 어플리케이션으로 보내거나 할 때 많이 유용하다. eclipse 의 어플리케이션 디버그도 이와 비슷하다.



(출처 : http://openjdk.java.net/groups/serviceability/jpdaFEThreads.jpg)
                                               

Posted by '김용환'
,

아주 심플하지만, 정말 해보고 싶었던 기능이었다..

중요한 웹 서버가 장애가 났을 때, 모니터링을 SMS로 받지만 모든 사람이 다 받기에는 고역이다.
그래서, 관리자도 알게 하고 주위로부터 일종의 경고를 알림으로서, 지금 우리는 장애를 처리하고 있다는 것을 알려주고 싶었다.


(자세한 내용은 아래 레퍼런스 참조)

http://knight76.tistory.com/entry/아두이노-프로세싱-연동-어플에서-버튼을-누르면-불-깜빡거리게-하기

http://knight76.tistory.com/entry/프로세싱-언어가-자바-언어로-변환

http://knight76.tistory.com/entry/프로세싱processing-이클립스연동

http://knight76.tistory.com/entry/me2day-의-특정-글에-리플을-달면-램프-깜박이게-하기-아두이노-이클립스-연동




이클립스 자바 소스

localhost로 떠있는 웹서버가 죽으면, 바로 깜박거리게 한다.

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;

import processing.core.PApplet;
import processing.serial.Serial;

public class PingTest extends PApplet {
 static int replyNumber = 0;
 Serial port;

 /**
  * 초기화
  */
 public void setup() {
  System.out.println("setup - start");
  System.out.println("Available serial ports:" + Serial.list().length);
  for (String comport : Serial.list()) {
   System.out.println(comport);
  }

  if (Serial.list().length == 0) {
   System.out.println("## NO DETECT ##:");
   System.out.println("end programe");
   System.exit(0);
  }

  // list[1]에 com3로 arduino가 붙어 있다.
  port = new Serial(this, Serial.list()[1], 9600);
  ScheduleJob job = new ScheduleJob();
  Timer jobScheduler = new Timer();
  jobScheduler.schedule(job, 0, 3000);
  System.out.println("setup - end");
 }

 // draw 메소드를 override 해줘야 JApplet을 이용해서 serial 을 사용하는 코드에서 문제가 나지 않는다.
 public void draw() {
 }

 static public void main(String args[]) {
  PApplet.main(new String[] { "--bgcolor=#F0F0F0", "PingTest" });
 }

 /**
  * Timer Task를 상속함
  *
  */
 class ScheduleJob extends TimerTask {
  @Override
  public void run() {
   if (!isok()) {
    blink();
   }
  }
 }

 public boolean isok() {
  String url = "http://localhost/";
  HttpURLConnection.setFollowRedirects(false);
  HttpURLConnection con;
  try {
   con = (HttpURLConnection) new URL(url).openConnection();
   con.setRequestMethod("GET");
   con.setConnectTimeout(5000);
   con.connect();
  } catch (MalformedURLException e) {
   e.printStackTrace();
   return false;
  } catch (IOException e) {
   e.printStackTrace();
   return false;
  }
  return true;
 }
 
 
 /**
  * 깜빡, 깜빡~
  */
 public void blink() {
  for (int i = 0; i < 3; i++) {
   // turn on led
   port.write(255);
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   port.write(0);
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }

 }
}




접속이 안되면,  Exception이 생기고, LED가 깜박거리게 된다.

java.net.ConnectException: Connection refused: connect
 at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
 at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:75)
 at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:337)
 at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:198)
 at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:180)
 at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:157)
 at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:391)
 at java.net.Socket.connect(Socket.java:579)


여기서 좀 더 응용을 하면, http response가 200, 304가 아닌 것에 대한 모든 것에 대해서 에러로 처리할 수도 있을 것이다.



Posted by '김용환'
,

 

이클립스-아두이노를 연동하여 특정 글에 리플이 추가되거나 삭제될 때마다 램프를 깜박이게 하려는 데모를 작성했다. 하다 보니. me2day api 연동 글이 되어 버렸다.

 

1. api 사용자키를 확인

미투 웹의 설정화면에 접속하여 api 사용자 키를 확인한다.

http://me2day.net/knight111111/setting

 

 

2. 애플리케이션 키 발급 및 사용

m2api 를 사용하기 위해서 애플리케이션 키를 발급해야 한다.

http://me2day.net/api/front/appkey

 

http://me2day.net/me2/app/edit_appkey 에 접속하고, 애플리케이션 키 (appkey) 값을 확인한다.

미투 개발서버에서 메일로 웹에서 보았던 애플리케이션 키(appkey) 값을 전달해준다.

미투 Open API(http://dev.naver.com/openapi/apis/me2day/me2api_intro#metwo2)에 따르면, 헤더에 ‘me2_application_key’을 이용하거나, GET/POST 파라미터에 'akey'를 넣으면 된다고 하며 모든 m2api 호출시 반드시 넣어야 한다.

 

나는 웹 파라미터를 이용한 방식을 사용해 본다. 웹으로 동작되는지 확인한다.

http://me2day.net/api/get_posts/$계정명$.xml?akey=발급받은애플리케이션키
(발급 받은 애플리케이션 키(appkey)가 없어도 볼 수는 있다.)

http://me2day.net/api/get_posts/knight111111.xml?akey=7f4e6364d7f4dd8bf7072c11f20b3be0

 

3. 인증

글쓰기, 친구신청, 쪽지 쓰기 등 사용자 본인만 할 수 있는 것을 하려면, 인증을 해야 한다.

미투 API 인증 절차(http://dev.naver.com/openapi/apis/me2day/me2api_intro#metwo3)가 있다. 나는 이미 있는 라이브러리를 쓰기로 했다.

미투 API 참고자료(http://dev.naver.com/openapi/apis/me2day/me2api_intro#metwo4)에 보면 외부 개발자가 다양한 언어별로 클라이언트 라이브러리 개발한 것이 있다. 자바의 경우는 예전에 많든 소스와 구글 프로젝트 코드(http://code.google.com/p/me2day-api/) 가 있는데, 나는 간단히 테스트만 할 것이라 me2api-java14-src.tar.gz 만 다운받았다.

 

코드는 아래와 같이 사용하면 포스트가 된다.  (실제 인증에 대해서 궁금한 사람은 Me2API 클래스의 request()메소드를 참조한다.)

        Me2API me2api = new Me2API();
        me2api.setUsername("knight111111");
        me2api.setApplicationKey("7f4e6364d7f4dd8bf7072c11f20b3be0");
        me2api.setUserKey("67000463");
        me2api.post("test");

 

4. 댓글자 확인

http://me2day.net/api/get_posts/knight111111.xml  URL을 통해서 body 글을 확인하고 포스트의 id가 “pyhja7h-665uq”인지 확인한다.

http://me2day.net/api/get_comments/xml?post_id=pyhja7h-665uq URL은 댓글 정보를 알 수 있다.  이 정보를 파싱하는 방법이 있지만, 이미 있는 api가 있으므로 그것을 활용한다.

 

me2api-java14 클라이언트 라이브러리를 이용해서 reply-test 댓글을 단다.

Me2API me2api = new Me2API();
me2api.setUsername("knight111111");
me2api.setApplicationKey("7f4e6364d7f4dd8bf7072c11f20b3be0");
me2api.setUserKey("67000463");
me2api.createComment("pyhja7h-665uq", "reply-test");

 

4. 아두이노 연동

특정 글이 리플이 달릴 때마다 아두이노에서 램프를 깜박이게 하는 것이다. 이 데모를 따라하기 위해서는 “http://knight76.tistory.com/entry/프로세싱processing-이클립스연동” , “http://knight76.tistory.com/entry/아두이노-프로세싱-연동-어플에서-버튼을-누르면-불-깜빡거리게-하기” 정보를 참조하면 좋다.

 

이클립스 프로젝트의 Referered Libraries 정보이다.

이클립스의 자바 코드

import java.io.IOException;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.xml.parsers.ParserConfigurationException;

import net.me2day.java.Comment;
import net.me2day.java.Me2API;
import processing.core.PApplet;
import processing.serial.Serial;

public class Me2dayReplyTest extends PApplet {
    static int replyNumber = 0;
    Serial port;

    /**
     * 초기화
     */
    public void setup() {
        System.out.println("setup - start");
        System.out.println("Available serial ports:" + Serial.list().length);
        for (String comport : Serial.list()) {
            System.out.println(comport);   
        }
       
        if (Serial.list().length == 0) {
            System.out.println("## NO DETECT ##:");
            System.out.println("end programe");
            System.exit(0);
        }
       
        // comment 개수
        replyNumber = getCommentNumber();
       
        // list[1]에 com3로 arduino가 붙어 있다.
        port = new Serial(this, Serial.list()[1], 9600);
        ScheduleJob job = new ScheduleJob();
        Timer jobScheduler = new Timer();
        jobScheduler.schedule(job, 0, 3000);
        System.out.println("setup - end");
    }
   
    // draw 메소드를 override 해줘야 JApplet을 이용해서 serial 을 사용하는 코드에서 문제가 나지 않는다.
    public void draw() {
    }

    static public void main(String args[]) {
        PApplet.main(new String[] { "--bgcolor=#F0F0F0", "Me2dayReplyTest" });
    }

    /**
     * Timer Task를 상속함
     *
     */
    class ScheduleJob extends TimerTask {
        @Override
        public void run() {
            int commentNumber = getCommentNumber() ;
            if (commentNumber != replyNumber) {
                blink();
                replyNumber = commentNumber;
            }
        }
    }

    /**
     * 특정 글에 대한 Comment 개수 구하기
     * @return
     */
    public int getCommentNumber() {
        Me2API me2api = null;
        try {
            me2api = new Me2API();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        me2api.setApplicationKey("7f4e6364d7f4dd8bf7072c11f20b3be0");
        me2api.setUserKey("67000463");
        List<Comment> list = null;
        try {
            list = me2api.getComments("pyhja7h-665uq");
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("list number : " + list.size());
        return list.size();
    }
   
    /**
     * 깜빡, 깜빡~
     */
    public void blink() {
        for (int i = 0; i < 3 ; i++) {
            // turn on led
            port.write(255);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            port.write(0);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

아두이노 소스는 기존과 동일하게 Serial로 전달된 정보를 받고 LED에 값을 변경한다.

 

 

const int ledPin = 8;      // the pin that the LED is attached to

void setup()

{

  // initialize the serial communication:

  Serial.begin(9600);

  // initialize the ledPin as an output:

  pinMode(ledPin, OUTPUT);

}

void loop() {

  byte brightness;

  // check if data has been sent from the computer:

  if (Serial.available()) {

    // read the most recent byte (which will be from 0 to 255):

    brightness = Serial.read();

    // set the brightness of the LED:

    analogWrite(ledPin, brightness);

  }

}

 

특정 글에 comment를 넣어주는 클라이언트 코드는 아래와 같이 하거나.. 직접 글에 댓글을 달아주면 된다.

public class Me2Test2 {
    public static void main(String[] args) throws Exception {
        Me2API me2api = new Me2API();
        me2api.setUsername("knight111111");
        me2api.setApplicationKey("7f4e6364d7f4dd8bf7072c11f20b3be0");
        me2api.setUserKey("67000463");
        me2api.createComment("pyhja7h-665uq", "reply-test");
    }
}

 

테스트하니 정상적으로 잘 동작한다.

 

 

 

참고) java.lang.RuntimeException: Error inside Serial.write() 발생시에 대한 대처 방법

아래와 같은 에러가 난다면, draw() 메소드를 반드시 override 해야 한다. draw() 메소드를  override 하면 아래 에러는 더 이상 발생하지 않는다.


java.lang.NullPointerException
    at processing.serial.Serial.write(Unknown Source)
    at Me2dayReplyTest.blink(Me2dayReplyTest.java:98)
    at Me2dayReplyTest$ScheduleJob.run(Me2dayReplyTest.java:63)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)
Exception in thread "Timer-0" java.lang.RuntimeException: Error inside Serial.write()
    at processing.serial.Serial.errorMessage(Unknown Source)
    at processing.serial.Serial.write(Unknown Source)
    at Me2dayReplyTest.blink(Me2dayReplyTest.java:98)
    at Me2dayReplyTest$ScheduleJob.run(Me2dayReplyTest.java:63)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)


 //   public void draw() {
//    }
->

    public void draw() {
    }

Posted by '김용환'
,


<시작>
아두이노와 프로세싱을 가지고 이것 저것 해보면서, 굳이 프로세싱 (processing) 언어의 경우는 굳이 processing ide를 쓰지 않아도 되겠다 하는 생각이 들었다. 그래서 윈도우에서 이클립스환경에서 쉽게 개발할 수 있도록 셋팅을 해보았다. 이렇게 한다면, 이클립스 + 아두이노로만 개발이 가능해 지고 쉽게 개발할 것이다.

기존에 했던 작업
http://knight76.tistory.com/entry/아두이노-프로세싱-연동-어플에서-버튼을-누르면-불-깜빡거리게-하기
http://knight76.tistory.com/entry/프로세싱-언어가-자바-언어로-변환


<본론>
프로세싱과 아두이노와 연동했던 소스를 참조해서 만들어본다.
"http://knight76.tistory.com/entry/아두이노-프로세싱-연동-어플에서-버튼을-누르면-불-깜빡거리게-하기"

아두이노 소스는 그대로 사용한다.

이제 프로세싱에 해당되는 것만 이클립스 환경에서 쓸 수 있게 한다.
다운받은 프로세싱 (processing) 패키지의 리소스를 잘 이용하여 Referenced Libraries 에 추가한다.

1. 프로젝트 생성
자. 이제 이클립스 프로젝트를 새로 생성한다.
그리고, 속성-Java Build Path를 지정한다.
UI만 쓸꺼면, 프로세싱 설치 디렉토리의 serial.jar만 추가하면 된다. 그러나 나는 serial 통신까지 하는 예제이기 때문에 조금 신경써야 한다. ^^

2. Build Path 추가
프로세싱 디렉토리의 lib 디렉토리의 core.jar (ui 담당), jna.jar를 build path에 추가한다.
그 다음 modes\java\libraries\serial\library 디렉토리의 RXTXcomm.jar와 serial.jar 을 build path에 추가한다.

3. Serial.dll 복사
제일 중요한 것은 serial 통신을 위한 dll 파일이다. 이 파일은 아주 다행히 프로세싱 설치 디렉토리에 있다.

설치 디렉토리의 modes\java\libraries\serial\library\windows32 디렉토리에 있는 rxtxSerial.dll 파일을
c:\windows\system32에 복사한다.

만약 rxtxSerial.dll 파일이 존재하지만 않으면, 다음의 에러가 발생한다.

java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path thrown while loading gnu.io.RXTXCommDriver
java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path
     at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1682)
     at java.lang.Runtime.loadLibrary0(Runtime.java:822)
     at java.lang.System.loadLibrary(System.java:993)
     at gnu.io.CommPortIdentifier.<clinit>(CommPortIdentifier.java:83)
     at processing.serial.Serial.list(Serial.java:549)
     at Springer.setup(Springer.java:33)
     at processing.core.PApplet.handleDisplay(PApplet.java:1390)
     at processing.core.PGraphics.requestDisplay(PGraphics.java:690)
     at processing.core.PApplet.run(PApplet.java:1562)
     at java.lang.Thread.run(Thread.java:613)
Error while running applet.
java.lang.RuntimeException: Error inside Serial.ports()
     at processing.serial.Serial.errorMessage(Serial.java:583)
     at processing.serial.Serial.list(Serial.java:564)
     at Springer.setup(Springer.java:33)
     at processing.core.PApplet.handleDisplay(PApplet.java:1390)
     at processing.core.PGraphics.requestDisplay(PGraphics.java:690)
     at processing.core.PApplet.run(PApplet.java:1562)
     at java.lang.Thread.run(Thread.java:613)







4. 클래스 생성
마지막으로 클래스를 생성한다.

import processing.core.PApplet;
import processing.serial.Serial;

public class SketchTest extends PApplet {
 Serial port;
 boolean button = false;
 int x = 150;
 int y = 150;
 int w = 100;
 int h = 75;

 public void setup() {
  size(400, 400);
  println("Available serial ports:");
  println(Serial.list());
  port = new Serial(this, Serial.list()[1], 9600);
 }

 public void draw() {
  if (button) {
   background(255);
   stroke(0);
  } else {
   background(0);
   stroke(255);
  }

  fill(175);
  rect(x, y, w, h);
 }

 public void mousePressed() {
  if (mouseX > x && mouseX < x + w && mouseY > y && mouseY < y + h) {
   button = !button;
  }

  if (button == true) {
   // turn on led
   port.write(255);
  } else {
   // turn off led
   port.write(0);
  }
 }

 static public void main(String args[]) {
  PApplet.main(new String[] { "--bgcolor=#F0F0F0", "SketchTest" });
 }
}






5. 클래스를 실행한다.
Run Application, Run Applet 다 되니 상관없다.


6. 애플리케이션 테스트를 한다.



<결론>
동작 아주 잘된다. 깜빡~ 깜빡~









USB 씨리얼 통신을 이클립스에서 자바 언어로 연동을 쉽게 할 수 있다는 점은 상당히 앞으로 창의력을 키워줄 것이다.


<참고>
관련된 라이브러리 추가 (win 32 기준)

Posted by '김용환'
,