Boost.Asioでシリアル通信してみる

にゃんにゃん.

自作の某ライブラリでhttpクライアントとして使っているBoost.Asioですが, シリアル通信もできるっぽいので, 雑にArduinoとPing-Pongしてみました.
arduino

環境

  • Arch Linux x86_64
  • Boost 1.57.0
  • clang 3.6.0
  • Arduino Uno
  • avr-gcc 4.9.2
  • avrdude 6.1

PC側

簡単ですね. Boostのドキュメント見ながらでも数分で書けました.

#include <chrono>
#include <thread>
#include <iostream>
#include <boost/asio.hpp>

auto main() -> int {
  boost::asio::io_service io;

  // ポートは /dev/ttyACM0
  boost::asio::serial_port serial(io, "/dev/ttyACM0");
  // 速度は 9600bps
  serial.set_option(boost::asio::serial_port_base::baud_rate(9600));

  // テキトウに5秒待つ
  std::this_thread::sleep_for(std::chrono::seconds(5));

  // "ping" を送信
  boost::asio::write(serial, boost::asio::buffer("ping\n"));

  // serial から response_buf に '\n' まで読み込む
  boost::asio::streambuf response_buf;
  boost::asio::read_until(serial, response_buf, '\n');

  // 表示して終わり
  std::cout << boost::asio::buffer_cast<const char*>(response_buf.data());
}
$ clang++ -std=c++1y -Wall -Wextra -lboost_system serial.cc
$ ./a.out

Arduino側

正直こっちのほうが時間がかかりました. 5時間位でしょうか…
まぁArduino(AVR)触ったのも2年ぶりくらいだし仕方ないね.

#define F_CPU 16000000UL
#define BAUD 9600

#include <avr/io.h>
#include <util/setbaud.h>
#include <stdio.h>
#include <string.h>

static FILE uart_stdin;
static FILE uart_stdout;

static int uart_getchar(FILE*) {
  loop_until_bit_is_set(UCSR0A, RXC0);
  return UDR0;
}

static int uart_putchar(char c, FILE*) {
  loop_until_bit_is_set(UCSR0A, UDRE0);
  UDR0 = c;
  return 0;
}

static void uart_init() {
  // baud rate の設定
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;

  // TX/RX を有効に
  UCSR0B = _BV(RXEN0) | _BV(TXEN0);
  // データは 8-bit
  UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);

  // シリアル入出力を stdin/stdout に当てる
  fdev_setup_stream(&uart_stdin, nullptr, uart_getchar, _FDEV_SETUP_READ);
  fdev_setup_stream(&uart_stdout, uart_putchar, nullptr, _FDEV_SETUP_WRITE);
  stdin = &uart_stdin;
  stdout = &uart_stdout;
}

auto main() -> int {
  uart_init();

  // 読み込む
  char str[10];
  scanf("%s", str);

  // 読み込んだデータが "ping" だったら "pong" を返す
  if (!strcmp(str, "ping")) {
    printf("pong\n");
  }
}
$ avr-g++ -std=c++1y -mmcu=atmega328p -Wall -Wextra -Os pingpong.cc
$ avr-objcopy -O ihex -j .text -j .data a.out pingpong.hex
$ avrdude -c arduino -P /dev/ttyACM0 -p m328p -b 115200 -u -e -U flash:w:pingpong.hex:a

see also

[ネタ] QWebViewでGUIアプリケーションを作る

CocoaTwit

以前から何度かつぶやいていた自作Twitterクライアント, CocoaTwit-QWebViewを公開しました.
img

A Simple and Cute Twitter Clientをコンセプトに, シンプルなデザインかつ細かな拡張のしやすいTwitterクライアントを目指しています.
また, 僕が今まで使ってきたTwitterクライアントの手が届かなかったところを改善して実装していこうと思っています.
ちなみにCocoaTwitという名前に特別な意味は無いです. ココアさんかわいい.

バイナリ配布は今のところ予定していませんが, 気になるLinux使いの方はビルドしてみてください.
(Macでもイケると思ったけど, twitppがApple Clangでビルドできなかった)

この記事で紹介する手法はネタです

正月くらいからこのCocoaTwitをタイトル通りの手法で開発していました.
しかし, もっとよさ気な方法を見つけたため設計を大幅変更することにしました1.

この時点でQWebView版CocoaTwitも本記事もある程度出来上がっており, 消してしまうのがもったいなかったためネタ記事として公開することにしました.
こんなブッ飛んだこともできるんだな〜って感じで読んでもらえると良いかと思います.

Read More »

Qt5でJSON

みょみょみょ.

最近, いろいろあってQt5を触っています(近いうちの記事で詳しく書きます).
ちょっとJSON文字列をQtの機能だけでParseしたくなって, どう書けばいいのか粘っていたらこうなった.

あるJSONの“relationship” => “source” => “screen_name”が指している文字列(“bert”)を取得することを考えてみます.

QtのJSON周りの主要なクラスにはQJsonDocument, QJsonObject, QJsonValueの3つがあるようです.
QJsonDocumentはJSONドキュメント自体を扱うクラス,
QJsonObjectはパースされたJSONのKeyを扱うクラス,
QJsonValueはJSONの各keyが指しているValueを扱うクラスです.

まず, JSON文字列をParseするにはQJsonDocumentクラスを使います. Parseする方法はいくつかありますが, QJsonDocument::fromJson()QByteArrayに変換したJSON文章を渡すのが確実っぽい感じでした.

ParseしたJSONの各要素を扱うため, QJsonDocument.object()を使ってQJsonDocumentからQJsonObjectを取得します.

QJsonObjectで, あるKeyが指しているValueを取得するにはQJsonObject.value("hoge")を使います. するとQJsonValueが返ってきます.

この状態で目的のValueに辿り着いたのであればQJsonValue.toString()QJsonValue.toDouble()で文字列や数値に変換してやります.
しかし, 更に深い要素が欲しいのであればQJsonValue.toObject()で再びQJsonObjectに変換してやり, 同様に.value("hoge").toObject().value("fuga")...と続けていきます.

求: Qtの機能だけでもっとCoolに各Valueを取得する方法

最近見つけたC++の便利な標準ライブラリいろいろ

みょん.

最近流行りの言語とかはあんなことも簡単にできるのか〜とか時々思ってしまうのですが, 実はC++の標準ライブラリにも結構便利な関数やクラスがいっぱい揃っているようです.
今日は, 僕が最近見つけたC++の標準ライブラリの便利な奴らいろいろを紹介したいと思います.

※ 以下のコードはgcc-4.9.2とclang-3.5.0で動作確認しました. ヴィズアルコンパイラとかは知りません.

Read More »

てすとおわりました

みょん.

後学期の中間テストが終わりました.
今回のテストはそんなに辛くなかったというか, 来週の専門科目の小テのほうが怖かったりします. はい.

✿ 最近のこと

twitpp

最近全く弄っていなかったのですが, あることが一段落したのでどんどん改良しています.
8月に書いたコードが汚すぎて手を付けられないくらいひどいので…..

改めてtwitppの紹介をすると, C++11以降(not VC++)でTwitterを扱うためのライブラリです.
開発当初はlibcurlを使っていましたがBoost.Asioに切り換え, Userstream接続なんかにも対応しました.

// consumer_key等をセット
twitpp::oauth::account account("CONSUMER", "CONSUMER_SECRET");
// access_tokenも設定できる
// twitpp::oauth::account account("CONSUMER", "CONSUMER_SECRET", "ACCESS", "ACCESS_SECRET");

// authorization urlを取得
account.get_authorize_url();
std::cout << account.authorize_url() << std::endl;

// PINを渡して認証
account.get_oauth_token(pin);

// oauth::clientクラスに認証したoauth::accountを渡す
twitpp::oauth::client oauth(account);

// ツイートする
auto res = oauth.post("https://api.twitter.com/1.1/statuses/update.json", {{"status", "Test Tweet!"}});
std::cout << res.response_body << std::endl;

// userstreamに接続
oauth.get("userstream.twitter.com", "/1.1/user.json", [](int& status, std::string& text) {
  std::cout << text << std::endl;
  text.clear();
});

ある程度いい感じになってきたと思っているので, 近いうちにこれを組み込んだあるものを作っていきたいなぁと思っています.

また, twitppは何度も言うようにコードが汚い部分が多く, 特にtwitpp::net::async_clientとかtwitpp::oauth::clientのlambda式を渡すget()post()は早急に改善したいなぁって感じです.

ではではー.