24 янв. 2016 г.

How to use IntelliJ IDEA to develop and upload software for micro controllers like Arduino

Arduino IDE times

Recently i've started to play with Arduino and also different other micro controllers like esp8266.
Originally i've used Arduino IDE to develop and upload sketches to the MCU.
But as a java/javascript software developer i always felt myself unhappy since i could not use my favourite IntelliJ IDEA for this. There is a CLion Arduino plugin present in IntelliJ plugins repository i've tried it but still was unhappy (also i used trial version of CLion since it does not have community version).

But recently i've found such a great project - PlatformIO created by Ivan Kravets from Ukraine which is very great since i'm also from Ukraine.

PlatformIO to the rescue

In short PlatformIO is free and open-source cross-platform code builder and library manager for Arduino with Continuos and IDE integration. It has pre-configured settings for the most Arduino Boards.

The great thing is that it supports not only Arduino but other MCU's as well - you could see list of supported platforms here. Also it does not require installed Arduino IDE - it is completely independent solution: toolchain for specific platform is downloaded and managed by Platformio.

So how to use PlatformIO and how to integrate it with IntelliJ IDEA?

using PlatformIO within IntelliJ IDEA 

Installing PlatformIO

First of all we have to install PlarformIO. It uses python and supports most OS which includes Windows, Linux and OSX. I will describe installation under OSX since i'm using this OS, but you could read the official get started section to see how to install it under other platforms. All installation steps should be performed from command line.

So first of all check whether you have installed python package manager pip:

which pip

if pip is not installed you could install it by running the following command:

sudo easy_install pip

after this lets install PlatformIO by itself:

sudo pip install -U platformio

Creating new project with PlatformIO


Now lets create first project with platformio. Create folder where your test project will be placed, cd to this folder. Then run:

platformio init --board=uno

Here i've created project for the Adruino UNO board. If you wish to use other board - you could find it's name using the following command:

platformio boards

And then just find in the command output name of your board (for Arduino boards see atmelavr platforms section). An example output of this command is the following:

$ platformio boards

Platform: atmelavr
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bluefruitmicro        atmega32u4     8Mhz      28Kb    2.5Kb  Adafruit Bluefruit Micro
feather32u4           atmega32u4     8Mhz      28Kb    2.5Kb  Adafruit Feather
flora8                atmega32u4     8Mhz      28Kb    2.5Kb  Adafruit Flora
gemma                 attiny85       8Mhz      8Kb     512B   Adafruit Gemma
metro                 atmega328p     16Mhz     31Kb    2Kb    Adafruit Metro
protrinket3ftdi       atmega328p     16Mhz     28Kb    2Kb    Adafruit Pro Trinket 3V/12MHz (FTDI)
protrinket3           atmega328p     12Mhz     28Kb    2Kb    Adafruit Pro Trinket 3V/12MHz (USB)
protrinket5           atmega328p     16Mhz     28Kb    2Kb    Adafruit Pro Trinket 5V/16MHz (USB)

Name from type column is what you need to specify in --board parameter.
After initialising your project structure will be the following:

├── .gitignore
├── .travis.yml
├── lib
│   └── readme.txt
├── platformio.ini
└── src

.gitignore - handy if you going to store your project in git cvs.
.travis.yml - for CI integration
lib - place here your libraries
platformio.ini - main configutation file. For now its ok to use defaults here.
src - your sketch should be placed here.

Compiling and uploading sample blink sketch with PlarformIO

lets create sample blink sketch:

  • create file blink.ino in src folder
  • copy blink example into this file:

    void setup() {
      pinMode(13, OUTPUT);
    }
    
    void loop() {
      digitalWrite(13, HIGH);
      delay(1000);           
      digitalWrite(13, LOW); 
      delay(1000);           
    }
    
now we can compile the code by running the following command in the root folder of our sample blink project:

platformio run

The sample output looks like:

Sergeys-MBP:pltest sergey$ platformio run
[Sun Jan 24 12:58:06 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino)
--------------------------------------------------------------------------------------------------------------------------------
avr-ar rcs .pioenvs/uno/libFrameworkArduinoVariant.a
avr-g++ -o .pioenvs/uno/src/tmp_ino_to.o -c -fno-exceptions -fno-threadsafe-statics -std=gnu++11 -g -Os -Wall -.pioenvs/uno/FrameworkArduino/hooks.o .pioenvs/uno/FrameworkArduino/main.o .pioenvs/uno/FrameworkArduino/new.o .pioenvs/uno/FrameworkArduino/wiring.o .pioenvs/uno/FrameworkArduino/wiring_analog.o .pioenvs/uno/FrameworkArduino/wiring_digital.o .pioenvs/uno/FrameworkArduino/wiring_pulse.o .pioenvs/uno/FrameworkArduino/wiring_shift.o
<cut ......>
avr-ranlib .pioenvs/uno/libFrameworkArduino.a
avr-g++ -o .pioenvs/uno/firmware.elf -Os -mmcu=atmega328p -Wl,--gc-sections,--relax .pioenvs/uno/src/tmp_ino_to.o -L/Users/sergey/.platformio/packages/ldscripts -L.pioenvs/uno -Wl,--start-group -lm .pioenvs/uno/libFrameworkArduinoVariant.a .pioenvs/uno/libFrameworkArduino.a -Wl,--end-group
avr-objcopy -O ihex -R .eeprom .pioenvs/uno/firmware.elf .pioenvs/uno/firmware.hex
"avr-size" --mcu=atmega328p -C -d .pioenvs/uno/firmware.elf
AVR Memory Usage
----------------
Device: atmega328p

Program:     998 bytes (3.0% Full)
(.text + .data + .bootloader)

Data:          9 bytes (0.4% Full)
(.data + .bss + .noinit)


================================================= [SUCCESS] Took 1.17 seconds =================================================


Great! Compilation was sucessful!
Lets upload this sketch to the Arduino UNO board. Attach arduino board to your mac or pc and run the following command:

platformio run --target upload

platformio will try to recognize usb port to which arduino is attached and will upload your sketch to the board.
Thats it!

IntelliJ IDEA (and CLion as well as other IntelliJ products) integration

So starting from now you do not need Arduino IDE - you could compile and upload your sketches directly via command line!

But wait... what about IntelliJ IDEA integration?
Well integration of PlatformIO with IDEA is far from excellent - unfortunately there is no IDEA plugin for PlatfomIO yet, so let's see what we could do.

Creating IDEA project from PlatformIO project

Lets create new IDEA project.
Choose File->New->Project from Existing Sources...


Then choose root folder of your PlatformIO project:



Then choose "Create project from existing sources"




Give name to the project or leave default one:



Then just click next:



And then "finish":



Now you could see our project opened:


You could use great IDEA terminal plugin to run PlatformIO commands right from IDEA:


And that's all?
Well there is one more thing we could do - we could use IDEA Ant integration to be able to run basic commands like compile and upload using IDEA build configuration.

Using Ant build file for IDEA build config support

Lets create build.xml file in the project root, and place the following text inside it:



<project default="compile" basedir=".">

    <target name="compile" description="compile the source">
        <exec executable="platformio">
            <arg value="-f"/>
            <arg value="-c"/>
            <arg value="intellij"/>
            <arg value="run"/>
        </exec>
    </target>

    <target name="clean" description="clean the source">
        <exec executable="platformio">
            <arg value="-f"/>
            <arg value="-c"/>
            <arg value="intellij"/>
            <arg value="run"/>
            <arg value="--target"/>
            <arg value="clean"/>
        </exec>
    </target>

    <target name="upload" description="upload binaries to the device" depends="compile">
        <exec executable="platformio">
            <arg value="-f"/>
            <arg value="-c"/>
            <arg value="intellij"/>
            <arg value="run"/>
            <arg value="--target"/>
            <arg value="upload"/>
        </exec>
    </target>

</project>


After this we could add these ant targets to build config.

First open Ant plugin toolbar:


Then click on + sign and select build.xml file from the project root:



After this in Ant toolbar you will see available ant commands. You could run them right from the Ant build toolbar window:


Or you could create new build config.
To do this click "Edit Configurations..." in the main toolbar:


Click + sign to add new configuration and choose "Ant Target":


You will see new unnamed ant target build config:


Click on a ... button right below build config name - you will see all available ant targets. Choose one you want to execute, for example "upload":

Then click "Ok":

After this you will see new Ant build config in the toolbar:


So you could run it. First time you probably get error message that you have no configured JDK for the project. Despite the fact that you do not need JDK, you have to setup it in order to satisfy IDE requirements. Press Cmd+; and choose JDK:



Then click Ok.
After this you could run your PlatformIO commands right from IDE. You could see command output in the "Messages" panel:



That's it!
Not so much integration as you would probably expect, but for me it's much more better than using native Arduino IDE.

Thanks a lot for reading this long post to the end!
See you later!

30 сент. 2014 г.

Run grunt task with custom (or dynamically generated) configuration

Today I faced a problem about how to run grunt task with some dynamically generated params.

Usually grunt tasks are configured in the following way:

grunt.initConfig({
     requirejs: {
            'optimize': {
                options: {
                    /* put your options here */
                }
            }
        }
})

But what if your config have dynamic nature?
for example in my case my config looks like:

grunt.initConfig({
     requirejs: {
            'optimize': {
                options: grunt.file.readJSON("/path/to/build.json")
            }
        }
})

the problem is that file "/path/to/build.json" only appears there after calling another grunt task,
lets call it grunt init,
but whole grunt configuration is loaded when you run any grunt task so I get into a vicious circle:

i cant run init task because build.json isn't yet in place,
i cant it put in place until I run grunt init.

solution is to use custom grunt tasks plus use grunt.config API:

var merge = require('merge');
....

grunt.registerTask('requirejs-custom-opts', 'Run requirejs task with custom options', function () {
    var dynamicConfig = {
        requirejs: {
            'optimize': {
                options: {
                       /* Your options go here */
                }
            }
        }
    }

    grunt.config.init(merge(true, grunt.config.get(), dynamicConfig));

    grunt.task.run(['requirejs']);
});

Note how grunt.config API was used - I merged whole grunt config with my own changes,
Please also note that in this case I can not use templates API because i need options object, not a string property.

now you can use your custom task by calling

grunt requirejs-custom-opts

At a first glance it looks like a hack. Probably it is.
But I was not able to found more correct way to do this.

17 февр. 2012 г.

Linux command line under Windows

Let me share my experience about setting up linux terminal under Windows.

Some time ago i worked on Mac OS and so accustomed to the unix command line that I can't live without it when i had switch to Windows. That's why i decided to setup linux console under Windows.


Main requirements was:

1. Linux terminal itself - i need to do my usual work using unix commands.
2. Terminal window should supports transparency (i like this feature on Mac's terminal)
3. Terminal window should supports tabs - this is a "must have" feature for terminal window

A natural choise for No. 1 is cygwin project. It gives you full power of linux console under Windows


but its default terminal window doesn't satisfy 2'nd and third conditions. Let's fix this!
cygwin contains an excellent termial emulator - mintty:


it supports transparency as well as other options:

Let's add tabs. There is an excellent free Windows application Window Tabs,
it allows to add tabs to any kind of application:

You can setup it so tabs will be shown only for mintty process. You can use mintty's Alt+F2 shortcut to open new tab and setup shortcut to switch beetween tabs. The only restriction of free version is - max tabs number in one windows set: 3. But is's enough for most of my needs.

Thanks for attention!

16 февр. 2012 г.

Change IP settings from command line on Windows

I writing this post just as a reminder to myself, but maybe it also helps to someone else.

So to change IP settings from command line on Windows follow these steps:

1. Get name of your network interface:

> ipconfig



in this case interface has the name "Local Area Connection 3"

2. If you want to setup IP and DNS to be resolved by DHCP run following command:


> netsh interface ip set address "<interface name>" dhcp
> netsh interface ip set dns " <interface name> " dhcp


3. If you want to use static IP and DNS use following commands:

> netsh interface ip set address " <interface name> " static 192.168.0.2 255.255.255.0 gateway=192.168.0.1 gw=1

This will set static IP and gateway, then you can add any number of DNS servers:

> netsh interface ip add dns " <interface name> " 192.168.0.1
> netsh interface ip add dns " <interface name> " 8.8.8.8

Thats all,
enjoy :)

11 февр. 2012 г.

Small HTTP web server for functional testing

Some time ago I needed a webserver for functional testing of my java HTTP client library.
I looked for a web server which satisfy following conditions:

1. Embeddable - the main condition.
2. Easy to integrate with unit testing frameworks
3. Small amount of code and config to setup server
4. Quick startup and shutdown.
5. Small size of the library.

The first candidate which satisfy main condition is Jetty.
It is cool but it doesn't satisfy all other my conditions.

Next candidate is com.sun.net.httpserver.HttpServer which is embedded into JDK 1.6 and higher.
It is excellent candidate for my needs, so i decided to use it.
I've implemented some kind of abstraction layer over HttpServer to fully satisfify 2-nd and 3-d conditions and as a result i wrote very small library which i called anhttpserver (Another HTTP Server)

here is basic usage example of that library:

import anhttpserver.ByteArrayHandlerAdapter;
import anhttpserver.DefaultSimpleHttpServer;
import anhttpserver.HttpRequestContext;
import anhttpserver.SimpleHttpServer;


import java.io.IOException;

public class SimpleServer {

    public static void main(String[] args) throws Exception {
        SimpleHttpServer server = new DefaultSimpleHttpServer();
        server.start();
        server.addHandler("/index", new ByteArrayHandlerAdapter() {
            public byte[] getResponseAsByteArray(HttpRequestContext httpRequestContext) throws IOException {
                return "Hello world".getBytes();
            }
        });
    }
}

Now point your favorite browser to http://localhost:8000/index - you should see "Hello world".

Isn't it easy?


Let's write basic JUnit test which will show, how easy to write functional tests using this library:

import anhttpserver.ByteArrayHandlerAdapter;
import anhttpserver.DefaultSimpleHttpServer;
import anhttpserver.HttpRequestContext;
import anhttpserver.SimpleHttpServer;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import static org.junit.Assert.assertEquals;

public class SimpleTest {

    private SimpleHttpServer server;

    @Before
    public void init() {
        server = new DefaultSimpleHttpServer();
        server.start();
    }


    @After
    public void finish() {
        server.stop();
    }

    //In our example this is function we test,
    //in your case most probablt it will be some other entity
    private String getResult(String urlString) throws Exception {
        URLConnection connection = (new URL(urlString)).openConnection();
        InputStream is = connection.getInputStream();
        String result = IOUtils.toString(is);
        is.close();
        return result;
    }


    @Test
    public void basicServerTest() throws Exception {
        server.addHandler("/", new ByteArrayHandlerAdapter() {
            @Override
            public byte[] getResponseAsByteArray(HttpRequestContext httpRequestContext) throws IOException {
                String response = "Hello world!";
                return response.getBytes();
            }
        });

        assertEquals("Hello world!", getResult("http://localhost:8000"));
    }
}

More examples of using anhttpserver library you can see in source code of anhttpserver and anhttpclient projects which are open source and released under the MIT license.

Also there is one non usual example of usage of this library - jstreamserver (HTTP Live Streaming for IPad and IPhone).

Here i used anhttpclient not for functional testing but as an HTTP server.
For sure i do not recommend to use it in such way - i didn't perform any stability and performance testing, but this example is proof of the viability of anhttpserver.

You can download sources of anhttpserver here: https://github.com/sprilukin/anhttpserver

Thank you for attention,
Comments are welcome.