Showing posts with label yun. Show all posts
Showing posts with label yun. Show all posts
Sunday, January 4, 2015
cloudClock: github repository now available
Repository is now available in https://github.com/desordenado77/cloudClock
Thursday, January 1, 2015
cloudClock: ArduinoJson or python json
I am planning on having all data from the cloudClock stored in files in json format, so I looked for a json library for arduino. I found ArduinoJson, downloaded it, imported the library in the arduino 1.5 IDE and... not working... it complained about missing core-dependencies. Some research and I found the file:
~/Arduino/libraries/ArduinoJson/library.properties
Which has the following content:
name=ArduinoJson
version=4.0
author=Benoit Blanchon <http://blog.benoitblanchon.fr/>
maintainer=Benoit Blanchon <http://blog.benoitblanchon.fr/>
sentence=An efficient and elegant JSON library for Arduino
paragraph=Supports JSON parsing and formatting. Uses fixed memory allocation.
url=https://github.com/bblanchon/ArduinoJson
architectures=*
After much thought I decided to leave the responsibility of parsing json to python scripts running on the linino side, so that arduino would just call the python script and read its stdout. I will be uploading my scripts to github at some point.
~/Arduino/libraries/ArduinoJson/library.properties
Which has the following content:
name=ArduinoJson
version=4.0
author=Benoit Blanchon <http://blog.benoitblanchon.fr/>
maintainer=Benoit Blanchon <http://blog.benoitblanchon.fr/>
sentence=An efficient and elegant JSON library for Arduino
paragraph=Supports JSON parsing and formatting. Uses fixed memory allocation.
url=https://github.com/bblanchon/ArduinoJson
architectures=*
I had to add the lines in red bellow to the file to get the library to work in the arduino 1.5 IDE:
name=ArduinoJson
version=4.0
author=Benoit Blanchon <http://blog.benoitblanchon.fr/>
maintainer=Benoit Blanchon <http://blog.benoitblanchon.fr/>
sentence=An efficient and elegant JSON library for Arduino
paragraph=Supports JSON parsing and formatting. Uses fixed memory allocation.
url=https://github.com/bblanchon/ArduinoJson
architectures=*
core-dependencies=
dependencies=
email=
After much thought I decided to leave the responsibility of parsing json to python scripts running on the linino side, so that arduino would just call the python script and read its stdout. I will be uploading my scripts to github at some point.
Tuesday, December 30, 2014
cloudClock: DS3231 RTC
Bought one of this from Dealextreme a while ago for this project, but only now I had the time to look into trying it. The exact one I bought is the one in the picture above, link here.
In order to use it, I searched for available libraries and turns out someone had already done all the work. The library can be found here and requires installing also the Time library, available here. To connect it to the arduino is plain easy, vcc, ground, SDA and SCL and that's all. Sounded easy... plugged it, compiled the example and... FAIL... hmmm... it did not work... nothing... After reviewing the code and the soldering, could not see anything wrong, so I went to the basics... Arduino Yun pinout. If you see the Arduino Yun pinout you may notice how SDA and SCL are in 2 places and if you see my wiring diagram for the arduino yun internet radio, you will noticed that my rotary encoder is plugged in the pins carrying the SDA and SCL signals... oops... unplug the rotary encoder and there I had it... RTC working. So this is how it looks like now (corresponding change will have to be done to the yun radio code to adapt to the rotary encoder pin change, also the RTC module does not correspond to the one I am using, but pins are named identically):
Monday, October 20, 2014
cloudClock: ntpstat
In order to find out the status of the ntp daemon, there seem to be 2 possibilities: ntpq or ntpstat.
ntpq is by far the one that gives more info, really too much for my liking, I just want to find out if the clock is in sync or not!! so I went for ntpstat. As I mentioned in my previous post, there is no ntpstat in linino, so I had to compile it from scratch. This was easy. I got the ntpstat source code from here and compiled it doing:
../linino/trunk/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-gcc ntpstat.c -o ntpstat
ntpq is by far the one that gives more info, really too much for my liking, I just want to find out if the clock is in sync or not!! so I went for ntpstat. As I mentioned in my previous post, there is no ntpstat in linino, so I had to compile it from scratch. This was easy. I got the ntpstat source code from here and compiled it doing:
../linino/trunk/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-gcc ntpstat.c -o ntpstat
Monday, October 13, 2014
cloudClock: time keeping
Part of the beauty of the cloudClock is the fact that it does not require having to set the time. For that I will use ntpd to keep linino on time. Turns out that linino already has ntpd running:
/usr/sbin/ntpd -n -p 0.openwrt.pool.ntp.org -p 1.openwrt.pool.ntp.org -p 2.openwrt.pool.ntp.org -p 3.open
First thing I thought was that I would like to change the ntp servers being used and select some servers near by. I also wanted to the change the timezone to my current timezone. Turns out both those things are configured in the same file: /etc/config/system
Original file was:
config system
option hostname 'Arduino'
option timezone 'UTC'
option timezone_desc 'Rest of the World (UTC)'
config timeserver 'ntp'
list server '0.openwrt.pool.ntp.org'
list server '1.openwrt.pool.ntp.org'
list server '2.openwrt.pool.ntp.org'
list server '3.openwrt.pool.ntp.org'
option enable_server '0'
And my modified file is now:
config system
option hostname 'Arduino'
option timezone 'CET-1CEST,M3.5.0,M10.5.0/3'
option timezone_desc 'Europe/Madrid'
config timeserver 'ntp'
list server '0.pool.ntp.org'
list server '1.pool.ntp.org'
list server '2.pool.ntp.org'
list server '3.pool.ntp.org'
option enable_server '0'
I got the timezone to set from this list: http://wiki.openwrt.org/doc/uci/system#time.zones
I need a way to find out if ntpd is working correctly. There seems to be 2 possibilities: ntpstat and ntpq, but I could not find ntpstat in linino, so tried with ntpq. Unfortunately ntpq was not working either. My conclusion was that it was using busybox ntpd, rather than a fully featured ntpd, so I installed ntpd doing:
opkg update
opkg install ntpd
/etc/init.d/sysntpd disable
/etc/init.d/ntpd enable
/etc/init.d/ntpd start
Now ntpq works!!! just need to figure out how do I parse the output of ntpq to get something meaningful.
On the arduino side, I bought an RTC chip module to make sure the clock is on time, even when there is no internet connection. I will get back to that whenever the RTC module arrives.
/usr/sbin/ntpd -n -p 0.openwrt.pool.ntp.org -p 1.openwrt.pool.ntp.org -p 2.openwrt.pool.ntp.org -p 3.open
First thing I thought was that I would like to change the ntp servers being used and select some servers near by. I also wanted to the change the timezone to my current timezone. Turns out both those things are configured in the same file: /etc/config/system
Original file was:
config system
option hostname 'Arduino'
option timezone 'UTC'
option timezone_desc 'Rest of the World (UTC)'
config timeserver 'ntp'
list server '0.openwrt.pool.ntp.org'
list server '1.openwrt.pool.ntp.org'
list server '2.openwrt.pool.ntp.org'
list server '3.openwrt.pool.ntp.org'
option enable_server '0'
config system
option hostname 'Arduino'
option timezone 'CET-1CEST,M3.5.0,M10.5.0/3'
option timezone_desc 'Europe/Madrid'
config timeserver 'ntp'
list server '0.pool.ntp.org'
list server '1.pool.ntp.org'
list server '2.pool.ntp.org'
list server '3.pool.ntp.org'
option enable_server '0'
I got the timezone to set from this list: http://wiki.openwrt.org/doc/uci/system#time.zones
I need a way to find out if ntpd is working correctly. There seems to be 2 possibilities: ntpstat and ntpq, but I could not find ntpstat in linino, so tried with ntpq. Unfortunately ntpq was not working either. My conclusion was that it was using busybox ntpd, rather than a fully featured ntpd, so I installed ntpd doing:
opkg update
opkg install ntpd
/etc/init.d/sysntpd disable
/etc/init.d/ntpd enable
/etc/init.d/ntpd start
Now ntpq works!!! just need to figure out how do I parse the output of ntpq to get something meaningful.
On the arduino side, I bought an RTC chip module to make sure the clock is on time, even when there is no internet connection. I will get back to that whenever the RTC module arrives.
Saturday, October 11, 2014
cloudClock: getting flite to work in Arduino Yun
In my last entry I installed flite from opkg and when I tried to run it with a simple "flite -t hello" all I got was a Segmentation Fault, so next step was to fix that.
First thing was find out what was causing it to seg. fault, strace to the rescue. For newbies: strace is a linux tool for tracing system calls and signals... a must know for a linux developer. Strace was not included in linino by dafault, so "opkg install strace". Once installed I did: "strace flite" and got the following:
strace flite
execve("/usr/bin/flite", ["flite"], [/* 11 vars */]) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x77435000
stat("/etc/ld.so.cache", 0x7fce6bf0) = -1 ENOENT (No such file or directory)
open("/lib/libflite_cmu_us_kal16.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/libflite_cmu_us_kal16.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=3705608, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x77434000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0007\360\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 3772416, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x77087000
old_mmap(0x77087000, 3693236, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x77087000
old_mmap(0x7741c000, 15112, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x385000) = 0x7741c000
close(3) = 0
munmap(0x77434000, 4096) = 0
open("/lib/libflite_usenglish.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/libflite_usenglish.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=88944, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x77434000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0b\320\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 155648, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x77061000
old_mmap(0x77061000, 68232, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x77061000
old_mmap(0x77082000, 19312, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x11000) = 0x77082000
close(3) = 0
munmap(0x77434000, 4096) = 0
open("/lib/libflite_cmulex.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/libflite_cmulex.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=597680, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x77434000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0!\360\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 663552, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x76fbf000
old_mmap(0x76fbf000, 590444, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x76fbf000
old_mmap(0x77060000, 3760, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x91000) = 0x77060000
close(3) = 0
munmap(0x77434000, 4096) = 0
open("/lib/libm.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=85356, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x77434000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0\26\200\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 151552, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x76f9a000
old_mmap(0x76f9a000, 84896, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x76f9a000
old_mmap(0x76fbe000, 3436, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x14000) = 0x76fbe000
close(3) = 0
munmap(0x77434000, 4096) = 0
open("/lib/libflite.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/libflite.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=125740, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x77434000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0\\ \0\0\0004"..., 4096) = 4096
old_mmap(NULL, 192512, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x76f6b000
old_mmap(0x76f6b000, 121476, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x76f6b000
old_mmap(0x76f99000, 2860, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x1e000) = 0x76f99000
close(3) = 0
munmap(0x77434000, 4096) = 0
open("/lib/libgcc_s.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=77080, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x77434000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0006\320\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 143360, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x76f48000
old_mmap(0x76f48000, 76672, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x76f48000
old_mmap(0x76f6a000, 3352, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x12000) = 0x76f6a000
close(3) = 0
munmap(0x77434000, 4096) = 0
open("/lib/libc.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=359599, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x77434000
read(3, "\177ELF\1\2\1\0\0\0\0\0\0\0\0\0\0\3\0\10\0\0\0\1\0\0\237\320\0\0\0004"..., 4096) = 4096
old_mmap(NULL, 446464, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x76edb000
old_mmap(0x76edb000, 352964, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0x76edb000
old_mmap(0x76f41000, 7343, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x56000) = 0x76f41000
old_mmap(0x76f43000, 17508, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x76f43000
close(3) = 0
munmap(0x77434000, 4096) = 0
open("/lib/libflite_cmulex.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/libflite_cmulex.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=597680, ...}) = 0
close(3) = 0
open("/lib/libflite_usenglish.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/libflite_usenglish.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=88944, ...}) = 0
close(3) = 0
open("/lib/libgcc_s.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=77080, ...}) = 0
close(3) = 0
open("/lib/libc.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=359599, ...}) = 0
close(3) = 0
open("/lib/libflite.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/libflite.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=125740, ...}) = 0
close(3) = 0
open("/lib/libgcc_s.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=77080, ...}) = 0
close(3) = 0
open("/lib/libc.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=359599, ...}) = 0
close(3) = 0
open("/lib/libflite.so.1", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/libflite.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=125740, ...}) = 0
close(3) = 0
open("/lib/libgcc_s.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=77080, ...}) = 0
close(3) = 0
open("/lib/libc.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=359599, ...}) = 0
close(3) = 0
open("/lib/libc.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=359599, ...}) = 0
close(3) = 0
open("/lib/libm.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=85356, ...}) = 0
close(3) = 0
open("/lib/libgcc_s.so.1", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=77080, ...}) = 0
close(3) = 0
open("/lib/libc.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=359599, ...}) = 0
close(3) = 0
open("/lib/libc.so.0", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=359599, ...}) = 0
close(3) = 0
stat("/lib/ld-uClibc.so.0", {st_mode=S_IFREG|0755, st_size=28968, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x4000000, -1, 0) = 0x77434000
set_thread_area(0x7743b750) = 0
mprotect(0x76f41000, 4096, PROT_READ) = 0
mprotect(0x77436000, 4096, PROT_READ) = 0
ioctl(0, TIOCNXCL, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCNXCL, {B38400 opost isig icanon echo ...}) = 0
brk(0) = 0x9f2000
brk(0x9f3000) = 0x9f3000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xf0000} ---
+++ killed by SIGSEGV +++
Segmentation fault
From the highlighted text, you can see that it did not find any of the shared libraries that flite needs. A search for those libraries showed that they were on a different folder from where flite was searching. They were in /usr/lib as opposed to /lib:
root@Arduino:~# find / -name *flite*
/overlay/usr/bin/flite
/overlay/usr/lib/libflite_cmu_time_awb.so.1.3
/overlay/usr/lib/libflite_usenglish.so.1.3
/overlay/usr/lib/opkg/info/flite.control
/overlay/usr/lib/opkg/info/flite.list
/overlay/usr/lib/libflite_cmu_time_awb.so.1
/overlay/usr/lib/libflite_cmulex.so.1.3
/overlay/usr/lib/libflite_cmu_us_kal16.so.1.3
/overlay/usr/lib/libflite_usenglish.so.1
/overlay/usr/lib/libflite.so.1
/overlay/usr/lib/libflite_cmu_us_kal.so.1.3
/overlay/usr/lib/libflite_cmu_us_kal.so.1
/overlay/usr/lib/libflite.so.1.3
/overlay/usr/lib/libflite_cmulex.so.1
/overlay/usr/lib/libflite_cmu_us_kal16.so.1
/usr/bin/flite
/usr/lib/opkg/info/flite.control
/usr/lib/opkg/info/flite.list
/usr/lib/libflite_cmu_time_awb.so.1.3
/usr/lib/libflite_usenglish.so.1.3
/usr/lib/libflite_cmu_time_awb.so.1
/usr/lib/libflite_cmulex.so.1.3
/usr/lib/libflite_cmu_us_kal16.so.1.3
/usr/lib/libflite_usenglish.so.1
/usr/lib/libflite.so.1
/usr/lib/libflite_cmu_us_kal.so.1.3
/usr/lib/libflite_cmu_us_kal.so.1
/usr/lib/libflite.so.1.3
/usr/lib/libflite_cmulex.so.1
/usr/lib/libflite_cmu_us_kal16.so.1
I just copied them across to /lib, but that did not work. Strace did no longer complain about the libraries not being found, but seg. fault was still there. From here I figured out other people had gone through the same issue in openWRT and fixed it by compiling 1.4 instead of 1.3. They were so kind there to also share the new makefile, which did not quite fit, but it was a good starting point. So I replaced the Makefile for flite in my linino tree (you may want to see this again for how to compile packages for linino) in linino/trunk/feeds/packages/sound/flite with this one:
#
# Copyright (C) 2006-2010 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=flite
PKG_VERSION:=1.4-release
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:=http://www.speech.cs.cmu.edu/flite/packed/flite-1.4/
PKG_MD5SUM:=b7c3523b3bbc6f29ce61e6650cd9a428
PKG_CAT=bzcat
PKG_BUILD_PARALLEL:=1
PKG_INSTALL:=1
include $(INCLUDE_DIR)/package.mk
define Package/flite
SECTION:=sound
CATEGORY:=Sound
DEPENDS:=@!GCC_VERSION_3_4_6
TITLE:=Text-to-speech for embedded systems
URL:=http://www.speech.cs.cmu.edu/flite/index.html
endef
define Package/flite/description
Festival Lite is a stripped down version of Festival,
the well-developed text-to-speech program written in C++.
This program is written in C to keep memory usage low.
endef
TARGET_LDFLAGS += -lm
define Build/Configure
$(call Build/Configure/Default, \
--enable-shared \
--with-audio="oss" \
--with-vox="cmu_us_kal16" \
--prefix="$(PKG_INSTALL_DIR)/usr" \
--exec-prefix="$(PKG_INSTALL_DIR)/usr" \
--bindir="$(PKG_INSTALL_DIR)/usr/bin" \
)
endef
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include/flite
$(CP) $(PKG_INSTALL_DIR)/usr/include/flite/{cst,flite}*.h $(1)/usr/include/flite/
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libflite*.so.* $(1)/usr/lib/
endef
define Package/flite/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/flite $(1)/usr/bin/
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libflite*.so.* $(1)/usr/lib/
endef
$(eval $(call BuildPackage,flite))
I also remove the patches folder and compiled flite 1.4 by doing "make package/flite/compile V=s" in /linino/trunk. After that I removed the previously installed flite in linino by doing "opkg remove flite" and copied the result of my compilation by doing:
rsync -avz -e ssh linino/trunk/build_dir/target-mips_r2_uClibc-0.9.33.2/flite-1.4-release/ipkg-install/usr root@192.168.0.9:/
Running then "flite -t hello" resulted in my arduino saying hello. Unfortunately, randoms attempts of running the same line ended up on the board throwing an error message instead of talking. The error is the following:
flite -t hello
VAL: tried to access car in 119 typed val
Getting there, but not quite there yet...
In the same place where I got the suggestion of using version 1.4, they suggest running it many times until it succeeds. I am using this script (based on the one they had):
REP=1
until [ "$REP" -eq 0 ]
do
flite -voice kal16 -t "$1"
REP="$?"
done
In the same place where I got the suggestion of using version 1.4, they suggest running it many times until it succeeds. I am using this script (based on the one they had):
REP=1
until [ "$REP" -eq 0 ]
do
flite -voice kal16 -t "$1"
REP="$?"
done
The birth of a new project: CloudClock
So my alarm clock broke recently. Actually it was only the powersupply. What a great excuse for new project with my arduino yun!!
Since I built my grooveshark radio, my yun has been unused, I do not find time to listen to music at home these days, so the grooveshark radio was not of much use, so my broken alarm was a good excuse to put the yun back on business.
My plan is the following:
1. No screen: The thing should talk
2. Just one button: All the control should be via web
3. Should be reliable: I want it to be a real replacement for my broken alarm, so I want it to be reliable as a commercial device... or more.
For 1 and 2, I might end up cheating and using the 16x2 screen and the rotary encoder... who knows...
So my first step was getting the yun to talk. For that I decided to use festival lite (or flite). So... ssh into linino, opkg update, opkg install flite:
good news: the package was there
bad news: it did not fit in the available memory
So I had to extend my linino memory and for that I could use the SD card port. Knowing that someone else would have probably done this already, did a google search and voila: Expanding Yun Disk Space
Worked...
Boot again, ssh into linino, opkg update, opkg install flite... now it fitted!!!
next step was to give it a try: flite -t hello
Segmentation Fault
Back to the begining... now need to figure out why it does not work...
Since I built my grooveshark radio, my yun has been unused, I do not find time to listen to music at home these days, so the grooveshark radio was not of much use, so my broken alarm was a good excuse to put the yun back on business.
My plan is the following:
1. No screen: The thing should talk
2. Just one button: All the control should be via web
3. Should be reliable: I want it to be a real replacement for my broken alarm, so I want it to be reliable as a commercial device... or more.
For 1 and 2, I might end up cheating and using the 16x2 screen and the rotary encoder... who knows...
So my first step was getting the yun to talk. For that I decided to use festival lite (or flite). So... ssh into linino, opkg update, opkg install flite:
good news: the package was there
bad news: it did not fit in the available memory
So I had to extend my linino memory and for that I could use the SD card port. Knowing that someone else would have probably done this already, did a google search and voila: Expanding Yun Disk Space
Worked...
Boot again, ssh into linino, opkg update, opkg install flite... now it fitted!!!
next step was to give it a try: flite -t hello
Segmentation Fault
Back to the begining... now need to figure out why it does not work...
Saturday, February 22, 2014
Fully featured grooveshark radio
I finally got all the basic functionality that I was looking for on my yun based grooveshark radio. Now I can play grooveshark radios, playlists and user collections. I made all the code and schematic available in github for everyone to be able to use. It is here:
https://github.com/desordenado77/internet_radio
Excuse my python... this is my first python program attempt... Arduino I had some experience from before, but not an awful lot either.
Next step is to make a nice case for it.
UPDATE: I have added a hook to my github account to publish all my commits in the blog also
https://github.com/desordenado77/internet_radio
Excuse my python... this is my first python program attempt... Arduino I had some experience from before, but not an awful lot either.
Next step is to make a nice case for it.
UPDATE: I have added a hook to my github account to publish all my commits in the blog also
Saturday, February 8, 2014
Adding 16x2 LCD and Rotary Encoder
As mentioned in my previous post, I got the remaining parts I needed for my grooveshark radio project: LCD, rotary encoder and hifi USB audio DAC.
First step was to get the LCD and rotary encoder to work with Arduino. For that purpose I made a board following the schematic on the next picture:
The two black things in the bottom are connectors for the cables that go to the arduino.
You can get instructions on how to use the LCD here: http://arduino.cc/es/Tutorial/LiquidCrystal
And regarding the rotary encoder, I used this library: http://www.pjrc.com/teensy/td_libs_Encoder.html
Works like a charm!!!
And this is the previous Arduino code modified to use both the LCD and the rotary encoder (the linino side remains unchanged):
#include <Encoder.h>
#include <LiquidCrystal.h>
#include <FileIO.h>
#define GENRE_NONE 0
#define GENRE_ROCK 12
#define GENRE_BLUES 230
#define GENRE_ELECTRONICA 67
#define GENRE_CLASSICROCK 3529
#define GENRE_INDIE 136
#define GENRE_METAL 17
int stations[] = { GENRE_NONE,
GENRE_ROCK,
GENRE_BLUES,
GENRE_ELECTRONICA,
GENRE_CLASSICROCK,
GENRE_INDIE,
GENRE_METAL };
String stations_str[] = { "None",
"Rock",
"Blues",
"Electronica",
"Classic Rock",
"Indie",
"Metal" };
int genres;
int val = 0;
int enc_val = 0;
int prevVal = 0;
Process radio_process;
String label_song, label_artist;
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
Encoder knob(2,4);
int knob_sw = 3;
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("Grooveshark!!");
pinMode(knob_sw, INPUT);
digitalWrite(knob_sw, HIGH);
genres = sizeof(stations)/sizeof(int);
Serial.begin(9600);
Bridge.begin();
start_radio(val);
}
void loop() {
long knob_value = knob.read();
if(knob_value > 0) {
enc_val++;
if(enc_val>=genres) enc_val = genres - 1;
}
else {
if(knob_value < 0) {
enc_val--;
if(enc_val<0) enc_val = 0;
}
}
int sw_value = digitalRead(knob_sw);
Serial.println(sw_value);
if(!sw_value){
val = enc_val;
}
if(knob_value!=0 || !sw_value) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Radio:");
lcd.setCursor(0, 1);
if(enc_val == val) {
lcd.print("-");
}
else {
lcd.print(" ");
}
lcd.print(stations_str[enc_val]);
}
knob.write(0);
if(val != prevVal) {
String text;
text = "Value: ";
text += val;
start_radio(val);
prevVal = val;
}
char labelbuffer_song[256];
char labelbuffer_artist[256];
Bridge.get("songName", labelbuffer_song, 256);
if (String(labelbuffer_song).length() > 0 && label_song != String(labelbuffer_song)){
lcd.clear();
label_song = String(labelbuffer_song);
lcd.setCursor(0, 1);
lcd.print(label_song);
Bridge.get("songArtist", labelbuffer_artist, 256);
label_artist = String(labelbuffer_artist);
lcd.setCursor(0, 0);
lcd.print(label_artist);
}
}
void start_radio(int val) {
String parameter = "";
radio_process.close();
Process killer;
killer.begin("killall");
killer.addParameter("mpg123");
killer.run();
if(stations[val] != 0) {
radio_process.begin("python");
radio_process.addParameter("/root/examples-pygrooveshark/radio_mpg123.py");
parameter+= stations[val];
radio_process.addParameter(parameter);
radio_process.runAsynchronously();
}
else {
radio_process.begin("echo");
radio_process.addParameter("Do Nothing!!!");
radio_process.runAsynchronously();
}
}
First step was to get the LCD and rotary encoder to work with Arduino. For that purpose I made a board following the schematic on the next picture:
This is how the board looked like:
The two black things in the bottom are connectors for the cables that go to the arduino.
You can get instructions on how to use the LCD here: http://arduino.cc/es/Tutorial/LiquidCrystal
And regarding the rotary encoder, I used this library: http://www.pjrc.com/teensy/td_libs_Encoder.html
Works like a charm!!!
And this is the previous Arduino code modified to use both the LCD and the rotary encoder (the linino side remains unchanged):
#include <Encoder.h>
#include <LiquidCrystal.h>
#include <FileIO.h>
#define GENRE_NONE 0
#define GENRE_ROCK 12
#define GENRE_BLUES 230
#define GENRE_ELECTRONICA 67
#define GENRE_CLASSICROCK 3529
#define GENRE_INDIE 136
#define GENRE_METAL 17
int stations[] = { GENRE_NONE,
GENRE_ROCK,
GENRE_BLUES,
GENRE_ELECTRONICA,
GENRE_CLASSICROCK,
GENRE_INDIE,
GENRE_METAL };
String stations_str[] = { "None",
"Rock",
"Blues",
"Electronica",
"Classic Rock",
"Indie",
"Metal" };
int genres;
int val = 0;
int enc_val = 0;
int prevVal = 0;
Process radio_process;
String label_song, label_artist;
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
Encoder knob(2,4);
int knob_sw = 3;
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("Grooveshark!!");
pinMode(knob_sw, INPUT);
digitalWrite(knob_sw, HIGH);
genres = sizeof(stations)/sizeof(int);
Serial.begin(9600);
Bridge.begin();
start_radio(val);
}
void loop() {
long knob_value = knob.read();
if(knob_value > 0) {
enc_val++;
if(enc_val>=genres) enc_val = genres - 1;
}
else {
if(knob_value < 0) {
enc_val--;
if(enc_val<0) enc_val = 0;
}
}
int sw_value = digitalRead(knob_sw);
Serial.println(sw_value);
if(!sw_value){
val = enc_val;
}
if(knob_value!=0 || !sw_value) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Radio:");
lcd.setCursor(0, 1);
if(enc_val == val) {
lcd.print("-");
}
else {
lcd.print(" ");
}
}
knob.write(0);
if(val != prevVal) {
String text;
text = "Value: ";
text += val;
start_radio(val);
prevVal = val;
}
char labelbuffer_song[256];
char labelbuffer_artist[256];
Bridge.get("songName", labelbuffer_song, 256);
if (String(labelbuffer_song).length() > 0 && label_song != String(labelbuffer_song)){
lcd.clear();
label_song = String(labelbuffer_song);
lcd.setCursor(0, 1);
lcd.print(label_song);
Bridge.get("songArtist", labelbuffer_artist, 256);
label_artist = String(labelbuffer_artist);
lcd.setCursor(0, 0);
lcd.print(label_artist);
}
}
void start_radio(int val) {
String parameter = "";
radio_process.close();
Process killer;
killer.begin("killall");
killer.addParameter("mpg123");
killer.run();
if(stations[val] != 0) {
radio_process.begin("python");
radio_process.addParameter("/root/examples-pygrooveshark/radio_mpg123.py");
parameter+= stations[val];
radio_process.addParameter(parameter);
radio_process.runAsynchronously();
}
else {
radio_process.begin("echo");
radio_process.addParameter("Do Nothing!!!");
radio_process.runAsynchronously();
}
}
Moving the rotary encoder I can move through the radio genres and by pressing the rotary encoder shaft I can select it.
What is next? improve both the UI and the python script to add playlists, user favourites and popular songs.
What is next? improve both the UI and the python script to add playlists, user favourites and popular songs.
Friday, January 17, 2014
Using REST for communication between AVR and Linux
I changed my code on my previous post to use REST as a way to communicate between Arduino and Linux. REST is basically a web server running on the linux side which allows access to key/value pairs via web or through serial from Arduino. In particular I am using this now for sending the info about the song that is playing. From my python script I am calling curl to POST the info to the REST website and from Arduino I am doing Bridge.get calls to receive the data.
UPDATE:
There is a pycurl library that I could have used instead (and there seem to be other alternatives, I am just not a python expert), but this seemed quicker to implement at the time. Will find an alternative...
I am using urllib2 to do the POST requests to the REST website. Originally I was using curl (running it in a subprocess) but urllib2 avoids calling a separate process.
Here is the new python script:
from __future__ import print_function
import urllib
import urllib2
import urllib2
import subprocess
import sys
from grooveshark import Client
from grooveshark.classes import Radio
client = Client()
client.init()
cmdargs = str(sys.argv)
url_name='http://localhost/data/put/songName/'
url_artist='http://localhost/data/put/songArtist/'
url_album='http://localhost/data/put/songAlbum/'
for song in client.radio(sys.argv[1]):
song_name = unicode(song.name).encode("utf-8")
song_artist_name = unicode(song.artist.name).encode("utf-8")
song_album_name = unicode(song.album.name).encode("utf-8")
print(song_name)
print(song_artist_name)
print(song_album_name)
url_name_curl = url_name + urllib.quote(song_name)
urllib2.urlopen(url_name_curl)
url_artist_curl = url_artist + urllib.quote(song_artist_name)
urllib2.urlopen(url_artist_curl)
url_album_curl = url_album + urllib.quote(song_album_name)
urllib2.urlopen(url_album_curl)
sys.stdout.flush()
subprocess.call(['mpg123', song.stream.url])
UPDATE:
I am using urllib2 to do the POST requests to the REST website. Originally I was using curl (running it in a subprocess) but urllib2 avoids calling a separate process.
Important thing is to remember calling urllib.quote on the text to POST, as you will need to convert special characters to "%XX" to make it a valid URL.
On the Arduino side I am only getting the song name, but it is enough to get the idea of how this is done. This is how my sketch looks like now:
#include <FileIO.h>
#define GENRE_NONE 0
#define GENRE_ROCK 12
#define GENRE_BLUES 230
#define GENRE_ELECTRONICA 67
#define GENRE_CLASSICROCK 3529
#define GENRE_INDIE 136
#define GENRE_METAL 17
int stations[] = { GENRE_NONE,
GENRE_ROCK,
GENRE_BLUES,
GENRE_ELECTRONICA,
GENRE_CLASSICROCK,
GENRE_INDIE,
GENRE_METAL };
int genres;
int val = 0;
int prevVal = 0;
Process radio_process;
String label;
void setup() {
genres = sizeof(stations)/sizeof(int);
Bridge.begin();
Serial.begin(9600);
while(!Serial); // wait for Serial port to connect.
Serial.println("Grooveshark Radio example");
start_radio(val);
}
void loop() {
val = analogRead(3);
val = (val*genres)/1023;
if(val != prevVal) {
String text;
text = "Value: ";
text += val;
Serial.println(text);
start_radio(val);
prevVal = val;
}
// removed old code to print the output of the script:
/*
while(radio_process.available() > 0){
char c = radio_process.read();
Serial.print(c);
}
*/
char labelbuffer[256];
Bridge.get("songName", labelbuffer, 256);
if (String(labelbuffer).length() > 0 && label != String(labelbuffer)){
label = String(labelbuffer);
Serial.println(label);
}
delay(400);
}
void start_radio(int val) {
String parameter = "";
radio_process.close();
Process killer;
killer.begin("killall");
killer.addParameter("mpg123");
killer.run();
if(stations[val] != 0) {
radio_process.begin("python");
radio_process.addParameter("/root/examples-pygrooveshark/radio_mpg123.py");
parameter+= stations[val];
radio_process.addParameter(parameter);
radio_process.runAsynchronously();
}
else {
radio_process.begin("echo");
radio_process.addParameter("Do Nothing!!!");
radio_process.runAsynchronously();
}
}
Wednesday, January 15, 2014
Arduino Yun Grooveshark Radio
I got an Arduino Yun as Christmas preset this year. After a few days playing around with it, I decided that I wanted to turn it into an internet audio playback device. I found there is a cool python library to access Grooveshark, which is even cooler than traditional internet radios... I will explain here the steps to get it to work. I assume basic Linux and programming knowledge in my explanation.
The first step was to get USB audio working as per the explanations in here... easy...
Next step was to get some audio player running on the Linux side which would play an mp3 from a URL (rather than from file as madplay). I checked on the available packages and there was no mplayer, no vlc, no mpg123... crap... so I checked on how to compile my own packages. The first step was to compile linino image and packages:
git clone https://github.com/arduino/linino.git
cd linino/trunk
./scripts/feeds uninstall -a
rm -rf feeds
./scripts/feeds update -a
./scripts/feeds install -a
rm -f .config
git checkout .config
make oldconfig
make V=s
During this process I found some compile issues, in fact I did not get to build all the packages, but seems like it was enough to later build mpg123.
In order to build the mpg123 package, I got the makefile from here, copied it inside my linino tree in linino/trunk/package/feeds/packages/mpg123/ and then did:
make package/mpg123/compile V=s
Somehow that did not create a .ipk file to install in the yun, as I was expecting, but everything from the ipk package that should have been created was available in linino/trunk/build_dir/target-mips_r2_uClibc-0.9.33.2/mpg123-1.13.2/ipkg-install/, so I just had to copy that folder into a pen drive and from there into the yun filesystem.
When I tried to run mpg123 I faced another issue, libltdl shared library was missing. Seems like that library was built during the linino image compilation here: linino/trunk/staging_dir/target-mips_r2_uClibc-0.9.33.2/usr/lib/libltdl.so.7.3.0. As with mpg123 before, I copied it into a pen drive and into the filesystem of the yun. Et voila... mpg123 was working.
Unfortunately, sound quality alternated between OK and very bad (with stuttering sound). In order to fix this, I created the file /etc/asound.conf with the following contents:
pcm.dmixer {
type dmix
ipc_key 1024
ipc_key_add_uid false
ipc_perm 0666
slave {
pcm "hw:0,0"
### WARNING: do NOT add period_time, period_size or buffer_size here!!! ###
rate 44100
}
bindings {
0 0
1 1
}
}
pcm.dsp0 {
type plug
slave.pcm "dmixer"
}
pcm.!default {
type plug
slave.pcm "dmixer"
}
pcm.default {
type plug
slave.pcm "dmixer"
}
ctl.mixer0 {
type hw
card 0
}
This came from here. That seemed to fix the issues.
OK, so we now have mpg123 working, yuhuuu... next step was pygrooveshark. I downloaded it from here, put it into a pendrive and did:
python setup.py install
Based on the pygrooveshark radio example, I made this python script in /root/examples-pygrooveshark/radio_mpg123.py which takes a number representing the radio genre as parameter (17 is for METAL, if you want to try it from the command line):
from __future__ import print_function
import subprocess
import sys
from grooveshark import Client
from grooveshark.classes import Radio
client = Client()
client.init()
cmdargs = str(sys.argv)
for song in client.radio(sys.argv[1]):
print(song.name)
print(song.artist.name)
print(song.album.name)
sys.stdout.flush()
subprocess.call(['mpg123', song.stream.url])
Tried running it but found another issue. Do not remember the exact error, but basically python on the yun was built without SSL support. The solution was to copy the file linino/trunk/staging_dir/target-mips_r2_uClibc-0.9.33.2/root-ar71xx/usr/lib/python2.7/lib-dynload/_ssl.so in /usr/lib/python2.7/lib-dynload/_ssl.so in the yun filesystem. Once that was done, I was able to run pygrooveshark scripts from the yun linux terminal.
Last step was to get some way of launching the different radio genres from the arduino/AVR side. Here is the hardware setup:
And here the sketch running on the AVR side:
#include <FileIO.h>
#define GENRE_NONE 0
#define GENRE_ROCK 12
#define GENRE_BLUES 230
#define GENRE_ELECTRONICA 67
#define GENRE_CLASSICROCK 3529
#define GENRE_INDIE 136
#define GENRE_METAL 17
int stations[] = { GENRE_NONE,
GENRE_ROCK,
GENRE_BLUES,
GENRE_ELECTRONICA,
GENRE_CLASSICROCK,
GENRE_INDIE,
GENRE_METAL };
int genres;
int val = 0;
int prevVal = 0;
Process radio_process;
void setup() {
genres = sizeof(stations)/sizeof(int);
Bridge.begin();
Serial.begin(9600);
while(!Serial); // wait for Serial port to connect.
Serial.println("Grooveshark Radio example");
start_radio(val);
}
void loop() {
val = analogRead(3);
val = (val*genres)/1023;
if(val != prevVal) {
String text;
text = "Value: ";
text += val;
Serial.println(text);
start_radio(val);
prevVal = val;
}
while(radio_process.available() > 0){
char c = radio_process.read();
Serial.print(c);
}
delay(400);
}
void start_radio(int val) {
String parameter = "";
radio_process.close();
Process killer;
killer.begin("killall");
killer.addParameter("mpg123");
killer.run();
if(stations[val] != 0) {
radio_process.begin("python");
radio_process.addParameter("/root/examples-pygrooveshark/radio_mpg123.py");
parameter+= stations[val];
radio_process.addParameter(parameter);
radio_process.runAsynchronously();
}
else {
radio_process.begin("echo");
radio_process.addParameter("Do Nothing!!!");
radio_process.runAsynchronously();
}
}
I can change grooveshark radios by moving the potentiometer.
What is next? I have ordered an LCD screen and a rotary encoder for user interface. My plan is to allow playback of grooveshark user favourites and playlists, but that requires a lot more changes in both the AVR and Linux.
Subscribe to:
Posts (Atom)