첫번째 정리 : 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 김용환 '김용환'

arduino와 processing을 연동 하면서, processing 언어가 어떻게 자바로 바뀌는지 궁금했다.

export application 하니 win32, win64 에서 동작할 수 있도록 코드가 생성된다. windows32 디렉토리와 window64 디렉토리가 생기고, 각각 lib, source 디렉토리와 serial 통신이 가능한 dll파일과 exe 파일이 생긴다. 

자바소스는 source디렉토리에 보니 processing언어로 된 원래 코드와 변환된 자바 코드가 있다. 

기존 코드는 다음과 같다. 

 import processing.serial.*;
 Serial port;


boolean button = false;

int x = 150;
int y = 150;
int w = 100;
int h = 75;

void setup() {
  size(400,400); 
  
  // 디버그 
 println("Available serial ports:");
 println(Serial.list());
 // 내 pc 에는 Serial 내부 구조의 1번에 com3로 연결된 아두이노가 있다. 
  port = new Serial(this, Serial.list()[1], 9600);  
}

void draw() {
  if (button) {
    background(255);
    stroke(0);
  } else {
    background(0);
    stroke(255);
  }
  
  fill(175);
  rect(x,y,w,h);
}


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

// 버튼의 값이 true이면 led을 끼고, false이면 led를 끈다.
  if (button == true) {
    // turn on led
     port.write(255);
  } else {
    // turn off led
    port.write(0);
  }
}
 


자동으로 변환된 자바 코드이다. 


import processing.core.*; 
import processing.xml.*; 

import processing.serial.*; 

import java.applet.*; 
import java.awt.Dimension; 
import java.awt.Frame; 
import java.awt.event.MouseEvent; 
import java.awt.event.KeyEvent; 
import java.awt.event.FocusEvent; 
import java.awt.Image; 
import java.io.*; 
import java.net.*; 
import java.text.*; 
import java.util.*; 
import java.util.zip.*; 
import java.util.regex.*; 

public class sketch_dec08a 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); 
  
  // \ub514\ubc84\uadf8 
 println("Available serial ports:");
 println(Serial.list());
 // \ub0b4 pc \uc5d0\ub294 Serial \ub0b4\ubd80 \uad6c\uc870\uc758 1\ubc88\uc5d0 com3\ub85c \uc5f0\uacb0\ub41c \uc544\ub450\uc774\ub178\uac00 \uc788\ub2e4. 
  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", "sketch_dec08a" });
  }
}




PApplet을 상속받은 클래스를 하나 만들고, PApplet의 method를 override 하도록 되어 있다. 
이렇게 만들어진 PApplet 을 바로 쓰면 애플릿으로 바로 쓸 수 있고,
main 메서드만 추가하면 어플리케이션처럼 쓸 수 있도록 짜 있다. 전형적인 어플 개방 방식을 쓰고 있다.  


lib/core.jar 파일에 processing.core.JApplet 클래스가 존재한다.  JApplet 클래스는 java.awt.Applet 을 상속하고, java.awt의 이벤트 계열 리스너와 쓰레드를 상속해서 쓰고 있다. 

public class PApplet extends Applet  implements PConstants, Runnable, MouseListener, MouseMotionListener, KeyListener, FocusListener {
...
}

lib/args.txt 파일을 보니, 클래스이름과 jar 파일 classpath가 적힌 것 같다. 

lib/RXTXcomm.jar 파일을 살펴보니. gnu.io 패키지를 가지고 있다. serial 통신을 지원하는 library인데 정체가 무엇일까 하는 생각이 들었다. http://users.frii.com/jarvi/rxtx/ 웹 페이지에 자세한 설명이 있다. 이 라이브러리는 LGPL 라이선스 이고 java에서 사용할 수 있도록 만들어진 serial, parallel 통신 library이다. 
이 페이지는 old 해졌고, http://rxtx.qbang.org/wiki/index.php/Main_Page 페이지가 최신 소개 페이지이다. 
serial port 통신에 대한 얘기들과 예제들이 있다. java로 쉽게 개발할 수 있도록 고생하셨다. 짝짝~


생각보다 processing의 원리가 무척 간단하다는 생각이 들었다. 단순히 java 언어로 변환하고, library만 지원하는 구조가 아닌가 생각이 든다. 그래서 예술가들이 processing 언어를 쓰는 것 같다. 

Posted by 김용환 '김용환'



아두이노 보드에 이렇게 구성한다. 
8번 포트를 아웃푹으로 지정





아두이노 소스 




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);
  }
}




프로세싱 소스

(원 소스는 http://www.learningprocessing.com 에서 있으며, 그림 예제에서 일부를 수정해서 만들었음)

 import processing.serial.*;
 Serial port;


boolean button = false;

int x = 150;
int y = 150;
int w = 100;
int h = 75;

void setup() {
  size(400,400); 
  
  // 디버그 
 println("Available serial ports:");
 println(Serial.list());
 // 내 pc 에는 Serial 내부 구조의 1번에 com3로 연결된 아두이노가 있다. 
  port = new Serial(this, Serial.list()[1], 9600);  
}

void draw() {
  if (button) {
    background(255);
    stroke(0);
  } else {
    background(0);
    stroke(255);
  }
  
  fill(175);
  rect(x,y,w,h);
}


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

// 버튼의 값이 true이면 led을 끼고, false이면 led를 끈다.
  if (button == true) {
    // turn on led
     port.write(255);
  } else {
    // turn off led
    port.write(0);
  }
}





여기서 약간 나는 머리를 썼다.
LED를 재미있게 만들었다. 원래 선물받은 제품인대, 꼬마 전구가 문제가 생겨서 못쓰고 있었다.
(사실 나는 "손에 잡히는 아두이노" 책에서 영감받아 나만의 재미있는 것을 만들려던 참이었다.)









꼬마 전구 대신 간단한 LED를 이용했다. 그리고 간단하게 테이프를 붙였다.
(.  원리는 무척 간단한데, 이런 제품을 구하기 가 어렵다는 게 있다. )

그리고 아두이노에 연결했다

처음에는 검은 바탕으로 있다. 꺼져있다. 





가운데 버튼을 눌러주면 환하게 켜진다. 




그렇게 복잡하지는 않지만, pc에서 아두이노를 다룬다는 것은 재미있다. 복잡한 프레임워크나 어려운 코드를 쓰지 않아도 내가 원하는 것을 할 수 있다니 매력이 있다. 

흐흐.. 이제 점점 장난감으로 갈 것 같다. 


Posted by 김용환 '김용환'

아두이노를 다룰 때, 아두이노 자체에서만 동작하는 "Arduino software(아두이노 소프트웨어)"만 써왔다.
pc에서 아두이노 기기를 다룰려면, 드라이버를 이용해서 코딩해야 한다. 
찾아보니 Visial Studio에서 연동하는 게 있기는 한데..
간단하게 동작되는 것만 하고 싶었는데. Processing(프로세싱) 이라는 툴 및 언어를 이용하면 될 것 같다. 
(프로세싱 언어가 자바랑 비슷한 문법을 하고 있다. 자바 개발자에게는 어쩌면 딱이다.)

프로세싱은 UI 및 아두이노와 serial 통신을 책임져준다. 


"손에 잡히는 아두이노" 책에서 간단히 소개할 때는 그런가 보다 했는데..
조금씩 이해하면서 접근해야지. 


설치 
http://processing.org/download/ 에 접속해서 1.5.1 를 다운받는다. 
 

 


UI Loo& Feel 은 꼭 아두이노 소프트웨어처럼 생겼다. 하지만 거의 자바와 비슷한 문법을 취하고 있다. (사실 내부는 jvm을 사용하고 있다.)


실제 돌아가는지 테스트해본다. 

http://arduino.cc/en/Tutorial/Dimmer




다음과 같이 설정한다. 



아두이노 소프트웨어에 다음의 코드를 넣는다.  


const int ledPin = 9;      // 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);
  }
}




프로세싱 코드


SERIAL 포트 중에 연결되어 있는 녀석으로 수정해야 한다. 
내 pc에는 1번 값에 com3로 arduino로 연결되어 있어서 1로 수정했다.  


 import processing.serial.*;
 Serial port;
 
 void setup() {
 size(256, 150);
 
 println("Available serial ports:");
 println(Serial.list());
 
 // Uses the first port in this list (number 0).  Change this to
 // select the port corresponding to your Arduino board.  The last
 // parameter (e.g. 9600) is the speed of the communication.  It
 // has to correspond to the value passed to Serial.begin() in your
 // Arduino sketch.
 port = new Serial(this, Serial.list()[1], 9600);  
 
 }
 
 void draw() {
 // draw a gradient from black to white
   for (int i = 0; i < 256; i++) {
   stroke(i);
   line(i, 0, i, 150);
   }
 
 // write the current X-position of the mouse to the serial port as
 // a single byte
 port.write(mouseX);
 }
 



그리고, processing 코드를 돌려보면 검은색 부분으로 마우스를 이동하면 LED가 꺼지고,
밝은 색 부분으로 마우스를 이동하면 LED가 켜진다. 




좋은 Reference 

http://www.arduino.cc/en/Tutorial/HomePage
http://processing.org/learning/
http://www.learningprocessing.com
http://www.cre8ive.kr/blog/2009/02/27/arduino-processing-%EC%97%B0%EB%8F%99/
책 - "손에 잡히는 아두이노"



Posted by 김용환 '김용환'