I wanted to use inexpensive Adafruit's IR to integrate Udoo with a remote control and audio/video applications such as MPD, XMBC and simply shut it down by pressing a button on a remote control.
It was not clear how to do that with this IR chip and what driver to use. Since I didn't find any LIRC kernel modules in the default Ubuntu distro for Udoo Dual, I've decided to build them.
My first attempt was around known lirc_serial driver that I tried to use with iMX6's serial port /dev/ttymxc3 that is normally used for SAM3X (Arduino) to iMX6 communications and programming SAMX3. This port has its Rx and Tx interfaces exposed through Arduino's GPIO #0 and #1.
However, all attempts to make it working this way were fruitless - something didn't allow the signals to go through from Arduino's GPIO #0 to iMX6 (either with or without jumper 18 that controls this port).
The second obvious approach was to change known lirc_rpi driver that I've successfully used with RaspberryPI and make it suitable for Udoo device.
Fortunately, the changes were not that big and I got my brand new lirc_udoo driver working well with the IR in a couple of days. This is how my hardware solution looks like:
The IR receiver is in the upper right corner, the red LED on the right is an activity monitor that I was already writing about in the previous blog.
If you use a device of the same configuration with a stock Ubuntu kernel, you might need only binary modules - lirc_dev and lirc_udoo.
If you want to compile the LIRC modules yourself, you'll need to install Udoo kernel sources and lirc_udoo sources (lirc-udoo-3.0.35-src.tgz). Download them to a local directory on your Udoo device and run the following commands:
cd <kernel-src>
7z x Kernel_Unico-master.zip
tar xzvf lirc-udoo-3.0.35.tgz
make oldconfig
chmod +x /root/kernel/Kernel_Unico-master/scripts/setsecoversion (I think this is a bug)
make prepare
make modulesmake modules_install
You'll also need to make links from /lib/modules/3.0.35 to kernel's 'build' and 'source' dirs:
cd /lib/modules/3.0.35/
ln -s <kernel-src>/Kernel_Unico-master build
ln -s <kernel-src>/Kernel_Unico-master source
Finally, to check if your newly created kernel module works run:
modprobe lirc_udoo gpio_in_pin=<N> debug=1
<N> is a iMX6's GPIO input pin number used as an IR's signal receiver. By default it's 92 and this is what you could see on the picture above.
If everything was built correctly you should see something like this in your /var/log/syslog file:
Dec 9 00:58:00 imx6-qsdl kernel: [ 83.145090] lirc_udoo: module is from the staging directory, the quality is unknown, you have been warned.
Dec 9 00:58:00 imx6-qsdl kernel: [ 83.147076] lirc_udoo: lirc_udoo_init: in=92 out=-1 softcarrier=1 sense=-1
Dec 9 00:58:00 imx6-qsdl kernel: [ 83.154221] lirc_udoo lirc_udoo.0: lirc_dev: driver lirc_udoo registered at minor = 0
Dec 9 00:58:00 imx6-qsdl kernel: [ 83.154253] lirc_udoo: driver registered 0!
Dec 9 00:58:00 imx6-qsdl kernel: [ 83.154298] lirc_udoo: is_right_chip gpio-2 64 92 00000000 00000000
Dec 9 00:58:00 imx6-qsdl kernel: [ 83.154326] lirc_udoo: cant claim input gpio pin 92
Dec 9 00:58:00 imx6-qsdl kernel: [ 83.154343] to_irq 348
Dec 9 00:58:00 imx6-qsdl kernel: [ 83.234761] lirc_udoo: Interrupt 348 obtained 0
After verifying that everything works as expected, you can remove 'debug' parameter in 'modprobe' to reduce the number of messages in syslog.
Installing all other LIRC tools (lircd, irw, irexec, mode2, etc.) is simple and doesn't differ from the RaspberryPI case.
Embedding, IoT and Fun Projects
Sunday, December 8, 2013
Saturday, November 30, 2013
Big Sound for small RaspberryPI with IR: Adding Favorites
As soon as I had created my music center with RaspberryPI controlled by an Onkyo remote, I've realized that I needed a few dedicated "favorites" buttons and a more complex configuration file for the remote to make sure that I could persist them and make available after a reboot.
Fortunately, Onkyo remote has a lot of buttons that I don't normally use, so I've dedicated the whole Deck B panel to favorites and used Group Preset Up/Down buttons to navigate between different favorites.
Now I have 7 pre-programmed buttons, which are sufficient to remember all my favorite Internet radio-stations and local MPD's playlists. Since I might want to re-program some favorites on fly, I've decided to use a combination of Stop+<FavoriteN> buttons to assign a new playlist to a button <FavoriteN>.
You can find all those new features in the new IR configuration file below. I think, it can be re-used by anyone who has the same model of Onkyo's remote - RC287S .
/etc/lirc/lircd.conf:
# Please make this file available to others
# by sending it to <lirc@bartelmus.de>
#
# this config file was automatically generated
# using lirc-0.9.0-pre1(default) on Sat Nov 16 03:37:07 2013
#
# contributed by
#
# brand: lircd.conf.conf
# model no. of remote control:
# devices being controlled by this remote:
#
begin remote
name ONKYO-RC-287S
flags RAW_CODES|CONST_LENGTH
eps 30
aeps 100
gap 108090
begin raw_codes
name KEY_POWER
9017 4480 624 509 579 1663
581 555 576 529 600 1670
577 530 600 1667 579 1662
583 1661 598 537 571 1670
599 1668 579 531 598 1678
569 1666 572 562 576 530
600 536 572 1669 598 536
581 555 574 531 600 534
582 554 576 1664 625 1618
598 536 584 1658 599 1675
576 1667 571 1672 592 1677
574
name KEY_LEFT
9054 4447 601 533 575 1667
601 533 625 509 579 1664
625 509 578 1672 616 1617
609 1659 579 538 604 1664
570 1676 622 501 574 1668
581 1661 607 527 581 1660
606 1673 565 1667 631 1610
606 530 577 556 574 1677
570 556 573 540 605 526
577 556 573 539 603 1666
569 1672 626 508 583 1652
631
name KEY_RIGHT
9040 4461 600 534 582 1658
601 535 572 562 578 1663
573 562 577 1663 588 1659
606 1660 576 531 609 1659
578 1665 591 543 576 1666
581 1661 608 526 581 553
576 1666 583 1660 606 1660
589 525 604 527 580 1667
600 540 569 1659 608 529
579 554 575 533 606 1662
575 1675 572 555 574 1667
579
name KEY_PLAY
9016 4485 628 505 581 1660
575 559 581 528 609 1657
583 527 601 1670 579 1666
570 1665 603 532 575 1665
604 1667 581 526 601 1666
582 1661 576 558 580 528
602 533 574 559 581 527
602 1667 580 527 603 1667
580 526 603 1672 581 1673
563 1666 603 1668 577 526
601 1673 572 527 602 1665
581
name KEY_PAUSE
9072 4439 569 555 574 1666
594 541 576 532 606 1664
574 532 606 1662 576 1677
570 1663 604 530 579 1661
607 1663 575 533 605 1672
565 1671 577 553 575 1668
579 555 574 1676 571 1663
606 529 579 554 575 1668
580 554 608 498 608 1669
567 534 605 530 579 1661
606 1662 576 532 616 1653
574
name KEY_LEFTALT
9015 4488 573 561 579 1660
575 560 579 528 601 1677
571 527 601 1669 578 1663
574 1665 603 533 583 1660
599 1668 579 528 601 1669
578 1665 574 562 575 530
599 1668 580 529 599 536
572 1670 598 536 571 1669
612 528 598 1649 600 526
581 1660 607 1672 565 532
608 1661 576 531 608 1659
578
name KEY_RIGHTALT
9044 4466 594 529 579 1664
603 529 579 556 573 1669
579 556 572 1669 587 1656
609 1667 567 538 600 1670
566 1676 583 546 572 1668
577 1665 601 533 573 1669
600 534 574 561 579 528
601 1668 577 531 600 1668
580 528 600 544 564 1668
598 1670 579 1664 573 561
578 1672 563 561 579 1664
572
name KEY_VOLUMEUP
9036 4464 597 537 579 1663
602 532 575 560 578 1662
573 567 573 1674 569 1663
599 1668 578 531 605 1665
571 1671 572 561 576 1667
579 1662 603 541 566 560
578 1661 573 563 575 534
603 530 576 558 580 1673
561 562 575 1668 577 556
572 1670 573 1668 597 1673
573 1669 574 560 577 1663
582
name KEY_VOLUMEDOWN
9032 4470 603 528 579 1666
605 529 574 559 580 1673
562 563 576 1615 627 1668
595 1677 567 533 603 1663
571 1672 573 575 563 1666
578 1662 603 533 574 1667
598 1679 565 534 603 538
569 559 579 528 598 1670
574 534 605 529 604 541
558 1674 572 1669 606 1662
572 1678 569 562 578 1661
579
name BTN_1
9009 4501 568 556 573 1668
579 557 572 536 603 1672
565 537 602 1662 574 1671
576 1666 601 533 584 1656
604 1666 580 528 602 1666
581 1679 567 549 580 529
599 1668 580 1665 571 571
567 1664 584 551 577 530
599 536 573 1669 597 538
571 566 576 1682 552 562
577 1665 570 1673 607 1661
576
name BTN_2
9018 4480 569 536 604 1666
571 537 602 542 565 1667
601 533 576 1666 599 1669
579 1671 566 560 579 1663
573 1668 602 537 572 1674
592 1668 577 531 600 535
572 562 578 529 600 1669
578 1671 566 560 577 530
598 537 572 1670 598 1670
577 1665 572 563 576 533
596 1671 576 1668 579 1663
614
name BTN_3
9058 4442 600 534 572 1670
599 536 572 562 576 1665
573 562 576 1666 572 1680
587 1672 573 535 606 1663
574 1666 581 562 566 1666
581 1663 605 529 578 556
573 1669 577 566 564 1669
578 1665 603 531 577 557
586 523 602 1674 562 537
602 1667 580 527 608 530
571 1667 601 1675 572 1662
574
name BTN_4
9015 4479 582 551 576 1666
581 553 577 532 607 1659
578 533 606 1662 574 1667
580 1661 607 528 579 1663
605 1668 575 529 602 1667
572 1669 578 556 582 1660
577 556 584 1660 576 568
571 1662 574 558 580 527
602 533 575 559 581 1662
583 552 579 1661 575 560
579 1663 574 1669 599 1668
579
name BTN_5
9019 4480 583 526 601 1668
589 518 603 533 573 1667
607 528 574 1668 600 1668
579 1662 574 561 579 1662
573 1669 599 535 572 1673
597 1670 577 531 604 1669
578 1659 572 576 563 531
597 1672 575 532 608 527
579 556 575 532 606 528
580 1669 598 1663 573 536
604 1663 573 1669 579 1664
602
name BTN_6
9021 4481 572 533 606 1664
581 527 603 532 576 1665
603 530 579 1665 602 1666
579 1662 576 557 572 1672
575 1666 603 532 575 1685
581 1669 580 528 601 1668
579 529 600 534 572 1678
593 1667 578 529 601 534
573 560 577 531 600 1668
580 1663 573 561 578 530
598 1671 577 1664 572 1679
590
name BTN_7
9013 4481 573 560 576 1666
573 561 577 530 599 1670
577 532 596 1671 576 1665
583 1663 606 527 580 1661
607 1661 575 534 606 1672
564 1667 580 554 573 535
603 1666 572 536 603 1665
585 524 603 531 576 1666
602 532 576 1666 602 532
586 1655 602 534 575 1667
601 1667 580 527 600 1677
572
name BTN_8
9024 4484 570 529 599 1680
566 530 598 538 570 1670
598 535 573 1672 596 1669
578 1666 571 563 575 1667
571 1670 608 526 591 1652
605 1664 573 534 606 533
574 582 547 560 578 556
556 554 573 560 578 556
553 562 565 1670 580 1661
605 1675 562 1670 578 1663
604 1665 572 1679 567 1665
603
name BTN_9
9043 4469 587 536 572 1670
598 536 570 565 576 1666
622 513 574 1666 570 1671
607 1668 590 521 598 1666
572 1666 579 555 573 1670
576 1665 603 532 579 1662
603 532 576 558 571 538
600 533 576 559 579 527
602 534 581 553 579 1663
626 1616 600 1667 580 1662
634 1608 599 1668 579 1665
624
end raw_codes
end remote
I've also changed a config file format for storing favorites and a current playlist in a JSON file and added support for playlists created at soundcloud.com. Internet radiostations are supported through traditional m3u files that MPD understands.
{
"current": "PlayList1",
"soundcloud": [
"soundcloud://playlist/xxxxxxxx"
],
"favorites": [
"soundcloud://playlist/xxxxxxxx",
"InternetRadio1",
"InternetRadio2",
"InternetRadio3",
"InternetRadio4",
"LocalPLayList1",
"LocalPLayList2"
]
}
where
"current" - the currently playing playlist
"soundcloud" - a list of soundclud URL's
"favorites" - a list of all favorites assigned to IR buttons
Finally, I had to change /etc/lirc/lircrc configuration file and Python script that is called when an IR button or combination of buttons are pressed.
/etc/lirc/lircrc:
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_POWER
config = sudo shutdown -h now
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_RIGHT
config = /usr/bin/mpc next
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_LEFT
config = /usr/bin/mpc prev
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_PLAY
config = /usr/bin/mpc toggle
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_PAUSE
button = BTN_1
config = /home/pi/pls_man.py -s 1
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_PAUSE
button = BTN_2
config = /home/pi/pls_man.py -s 2
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_PAUSE
button = BTN_3
config = /home/pi/pls_man.py -s 3
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_PAUSE
button = BTN_4
config = /home/pi/pls_man.py -s 4
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_PAUSE
button = BTN_5
config = /home/pi/pls_man.py -s 5
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_PAUSE
button = BTN_6
config = /home/pi/pls_man.py -s 6
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_PAUSE
button = BTN_7
config = /home/pi/pls_man.py -s 7
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = BTN_1
config = /home/pi/pls_man.py -f 1
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = BTN_2
config = /home/pi/pls_man.py -f 2
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = BTN_3
config = /home/pi/pls_man.py -f 3
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = BTN_4
config = /home/pi/pls_man.py -f 4
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = BTN_5
config = /home/pi/pls_man.py -f 5
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = BTN_6
config = /home/pi/pls_man.py -f 6
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = BTN_7
config = /home/pi/pls_man.py -f 7
flags = quit
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_LEFTALT
config = /home/pi/pls_man.py -p
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_RIGHTALT
config = /home/pi/pls_man.py -n
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = BTN_8
config = /home/pi/pls_man.py -P
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = BTN_9
config = /home/pi/pls_man.py -N
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_VOLUMEUP
repeat = 1
config = mpc volume +1
end
begin
remote = ONKYO-RC-287S
prog = irexec
button = KEY_VOLUMEDOWN
repeat = 1
config = mpc volume -1
end
pls_man.py script is provided below
#!/usr/bin/env python
# encoding: utf-8
'''
pls_man -- Manage Play List
pls_man is a module for controlling play lists through an IR remote
@author: ogryb
@copyright: 2013 Oleg Gryb. All rights reserved.
@license: GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with luna_mech. If not, see <http://www.gnu.org/licenses/>.
@contact: oleg@gryb.info
@deffield updated: 2013.11.18
'''
import sys
import os
import re
import json
from optparse import OptionParser
__all__ = []
__version__ = 0.1
__date__ = '2013-11-18'
__updated__ = '2013-11-18'
DEBUG = 0
TESTRUN = 0
PROFILE = 0
SOUND_CLOUD = ['soundcloud://playlist/12692664']
def main(argv=None):
'''Command line options.'''
program_name = os.path.basename(sys.argv[0])
program_version = "v0.1"
program_build_date = "%s" % __updated__
program_version_string = '%%prog %s (%s)' % (program_version, program_build_date)
#program_usage = '''usage: spam two eggs''' # optional - will be autogenerated by optparse
program_longdesc = '''''' # optional - give further explanation about what the program does
program_license = "Copyright 2013 Oleg Gryb \
Licensed under the GPL\nhttp://www.gnu.org/licenses/"
if argv is None:
argv = sys.argv[1:]
try:
# setup option parser
parser = OptionParser(version=program_version_string, epilog=program_longdesc, description=program_license)
parser.add_option("-c", "--config", dest="config", help="config json file [default: %default]", metavar="FILE")
parser.add_option("-v", "--verbose", dest="verbose", action="count", help="set verbosity level [default: %default]")
parser.add_option("-n", "--next", dest="nextpl",
action="store_true", default=False,
help="Next playlist")
parser.add_option("-p", "--prev", dest="prevpl",
action="store_true", default=False,
help="Previous playlist")
parser.add_option("-N", "--next-fav", dest="nextfav",
action="store_true", default=False,
help="Next favorites")
parser.add_option("-P", "--prev-fav", dest="prevfav",
action="store_true", default=False,
help="Previous favorites")
parser.add_option("-s", "--store-fav", dest="storenum",
help="Store favorite", default=0, type="int", metavar="NUMBER")
parser.add_option("-f", "--play-fav", dest="playnum",
help="Store favorite", default=0, type="int", metavar="NUMBER")
# set defaults
parser.set_defaults(config="~/.pls_man/config", verbosity=0)
# process options
(opts, args) = parser.parse_args(argv)
cf = os.path.expanduser(opts.config)
if not os.path.isfile(cf):
if not os.path.isdir(os.path.dirname(cf)):
os.system("mkdir -p %s" % os.path.dirname(cf))
cfj = dict()
cfj['current'] = ''
cfj['favorites'] = ["","","","","","",""]
cfj['soundcloud'] = SOUND_CLOUD
with open(cf, 'w') as out:
json.dump(cfj, out)
if not os.path.isfile(cf):
sys.exit("Can's create file %s" % cf)
io = open(cf)
cfj = json.load(io)
io.close()
if not cfj:
cfj = dict()
ind = 0
if (opts.nextpl or opts.prevpl):
if 'current' in cfj:
s = cfj['current']
lsa = []
if 'soundcloud' in cfj:
lsa = cfj['soundcloud']
ls = os.popen('mpc lsplaylists').read()
lsa = lsa + ls.split("\n")
del lsa [-1]
for i in range(0,len(lsa)-1):
if (s == lsa[i]):
if opts.nextpl:
ind = i+1
else:
ind = i-1
break
if ind < 0:
ind = len(lsa) - 1
if ind >= len(lsa):
ind = 0
if ind < 0:
ind = 0
if ind < len(lsa):
os.system("mpc clear")
loaded = os.system("mpc load %s" % lsa[ind])
if loaded == 0:
os.system("mpc play")
cfj['current'] = lsa[ind]
with open(cf, 'w') as out:
json.dump(cfj, out)
if (opts.nextfav or opts.prevfav):
if 'current' in cfj:
s = cfj['current']
lsa = []
if 'favorites' in cfj:
lsa = cfj['favorites']
for i in range(0,len(lsa)-1):
if (s == lsa[i]):
if opts.nextfav:
ind = i+1
while ind < len(lsa) and ((not lsa[ind]) or len(lsa[ind]) == 0):
ind += 1
else:
ind = i-1
while ind >= 0 and ((not lsa[ind]) or len(lsa[ind]) == 0):
ind -= 1
break
if ind < 0:
ind = len(lsa) - 1
while ind >= 0 and ((not lsa[ind]) or len(lsa[ind]) == 0):
ind -= 1
if ind >= len(lsa):
ind = 0
while ind < len(lsa) and ((not lsa[ind]) or len(lsa[ind]) == 0):
ind += 1
if 0 <= ind and ind < len(lsa):
os.system("mpc clear")
loaded = os.system("mpc load %s" % lsa[ind])
if loaded == 0:
os.system("mpc play")
cfj['current'] = lsa[ind]
with open(cf, 'w') as out:
json.dump(cfj, out)
if ( 0 < opts.storenum and opts.storenum <= 7 ):
if not 'favorites' in cfj:
cfj['favorites'] = ["","","","","","",""]
if 'current' in cfj:
s = cfj['current']
cfj['favorites'][opts.storenum-1] = s
with open(cf, 'w') as out:
json.dump(cfj, out)
if ( 0 < opts.playnum and opts.playnum <= 7 ):
ind = opts.playnum - 1
if 'favorites' in cfj and ind < len(cfj['favorites']):
fav = cfj['favorites'][ind]
if (len(fav) > 0):
os.system("mpc clear")
loaded = os.system("mpc load %s" % fav)
if loaded == 0:
os.system("mpc play")
cfj['current'] = fav
with open(cf, 'w') as out:
json.dump(cfj, out)
except Exception, e:
indent = len(program_name) * " "
sys.stderr.write(program_name + ": " + repr(e) + "\n")
sys.stderr.write(indent + " for help use --help")
return 2
if __name__ == "__main__":
if DEBUG:
sys.argv.append("-h")
if TESTRUN:
import doctest
doctest.testmod()
if PROFILE:
import cProfile
import pstats
profile_filename = 'pls_man_profile.txt'
cProfile.run('main()', profile_filename)
statsfile = open("profile_stats.txt", "wb")
p = pstats.Stats(profile_filename, stream=statsfile)
stats = p.strip_dirs().sort_stats('cumulative')
stats.print_stats()
statsfile.close()
sys.exit(0)
sys.exit(main())
Everything works as expected so far, switching between Internet radio-stations and local MPD's playlists stored on Raspberry's is very easy now.
Sunday, November 24, 2013
UDOO - RaspberryPI Talks to Arduino
Communication Schemes
There are two loosely coupled components in UDOO device - one is built around Atmel's SAM3X8E processor and the second one around ARM v7 Cortex A9, i.MX6 series processor. Since the first one resembles traditional Arduino's functionality and the second one is very similar to RaspberryPI, it would be fair to say that we're dealing with Arduino + RaspberryPI hybrid here.It would be interesting to learn, of course, how these two loosely coupled components can talk to each other. One of the obvious way of doing this would be by utilizing GPIO's available on both sides.
Possible connectivity scenarios are provided by UDOO in their "UDOO Starting Manual":
It's obvious from this diagram that I could take a signal from i.MX6's output GPIO and feed it to an SAM3X8E's input GPIO.
Since UDOO has only one green led, which simply stays on and never blinks, I've decided to add my own custom led on SAM3X8E that would monitor a status and network activity on i.MX6 side. If i.MX6 is running, it will send a pulse signal every few seconds to GPIO 134. Network activity signals will be sent to the same GPIO when a TCP packet received or send by i.MX6's wireless card. I monitor wireless interface because it's my primary one, but it can be easily changed to wired or any other network interface if necessary.
Solution Details
This is the final hardware solution:
GPIO 134 is connected to Arduino's A6, light diode's cathode is connected to the ground on J8 and anode to Arduino's DAC0.
The rest of that is coding. You'll need an activity monitor running on i.MX6 and a code for Arduino's controller that reads A6 and sends an analog signal to DAC0.
I've "demonized" my activity monitor by creating an init script and storing it in /etc/init.d/udoo-activity file:
#!/bin/bash
### BEGIN INIT INFO
# Provides: udoo-activity
# Required-Start: $remote_fs $all
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: Sends TCP activity and udoo pulse to a GPIO 134
### END INIT INFO
. /lib/lsb/init-functions
PATH=/sbin:/usr/sbin:/bin:/usr/bin
ACTIVITYPID=/var/run/udoo-activity.pid
PULSEPID=/var/run/udoo-pulse.pid
GPIODIR=/sys/class/gpio/gpio134
[ -f ${GPIODIR}/direction ] || exit 0
[ -f ${GPIODIR}/value ] || exit 0
echo out >${GPIODIR}/directionu
echo 0 >${GPIODIR}/value
do_stop () {
log_daemon_msg "Stopping UDOO activity monitors" "udoo-activity"
if [ -f "$PULSEPID" ]; then
kill -9 `cat $PULSEPID` >/dev/null 2>&1
fi
if [ -f "$ACTIVITYPID" ]; then
kill -9 `cat $ACTIVITYPID` >/dev/null 2>&1
fi
log_end_msg $?
echo 0 >${GPIODIR}/value
}
do_start () {
# Pulse Loop
while true; do
sleep 5
echo 1 >${GPIODIR}/value
sleep 0.0015
echo 0 >${GPIODIR}/value
done &
echo $! >$PULSEPID
# TCP Dump Loop
while true; do
echo 0 >${GPIODIR}/value
tcpdump -q -i wlan6 -n tcp -c 1 >/dev/null 2>&1
echo 1 >${GPIODIR}/value
sleep 1
done &
echo $! >$ACTIVITYPID
}
case "$1" in
start)
do_start
;;
stop)
do_stop
;;
force-reload|restart)
$0 stop
$0 start
;;
*)
echo "Usage: /etc/init.d/udoo-activity {start|stop|restart|force-reload}"
exit 1
;;
esac
exit 0
To start the monitor at i.MX6's boot, you'll need to update your init.d scripts:
update-rc.d udoo-activity defaults
Finally, the code for controlling Arduino's part:
// the setup routine runs once when you press reset:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
analogWriteResolution(12);
analogWrite(6, 0);
pinMode(6, INPUT);
analogWrite(6, 0);
pinMode(DAC0, OUTPUT);
analogWrite(DAC0, 0);
}
int BLINK_DURATION=50;
int IDLE_DURATION=2500;
int IDLE_DURATION_LIGHT=100;
int PULSE_DURATION=5500;
int LOOP_DURATION=10;
int idle_count = 0;
int light_on = 0;
int pulse_count = 0;
// the loop routine runs over and over again forever:
void loop() {
int level = analogRead(6);
if (level >= 900) {
blink(BLINK_DURATION);
pulse_count = 0;
idle_count = 0;
Serial.println(level);
}
else {
idle_count += 1;
if (pulse_count*LOOP_DURATION >= PULSE_DURATION) {
analogWrite(DAC0,0);
idle_count = 0;
light_on = 0;
}
else {
pulse_count += 1;
if (idle_count*LOOP_DURATION >= IDLE_DURATION && !light_on) {
analogWrite(DAC0,2048);
light_on = 1;
idle_count = 0;
}
else {
if (idle_count*LOOP_DURATION >= IDLE_DURATION_LIGHT && light_on) {
analogWrite(DAC0,0);
idle_count = 0;
light_on = 0;
}
}
}
}
// print out the value you read:
//Serial.println(sensorValue);
delay(LOOP_DURATION); // delay in between reads for stability
}
void blink(int duration) {
analogWrite(DAC0, 2048);
delay(duration);
analogWrite(DAC0, 0);
}
When there is no any network activity, the led will be slowly blinking, when the packets are received or sent by wlan6, it will blink fast. If i.MX6 is off or doesn't send a pulse, the led will be turned off. An apparent benefit of the last state (led is off) is that it can be used to determine when shutdown on i.MX6 is complete and when it's safe to turn the power off.
Yet another interesting thing that I've learned about UDOO is that even if you completely shut down i.MX6 9 (e.g. by running 'init 0') Arduino part of it will still be running.
Demo
At the video below you can see the led in two states: during the boot when the wireless interface is active trying to acquire a connection and after the boot is completed (starting @ 15th second) when there is no network activity and the led is blinking slowly because of the pulse signal sent by the i.MX6 board once in a few seconds.
Subscribe to:
Posts (Atom)