CINXE.COM
Ken Shirriff's blog: ir
<!DOCTYPE html> <html class='v2' dir='ltr' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'> <head> <link href='https://www.blogger.com/static/v1/widgets/3566091532-css_bundle_v2.css' rel='stylesheet' type='text/css'/> <meta content='width=1100' name='viewport'/> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <meta content='blogger' name='generator'/> <link href='http://www.righto.com/favicon.ico' rel='icon' type='image/x-icon'/> <link href='http://www.righto.com/search/label/ir' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Ken Shirriff's blog - Atom" href="http://www.righto.com/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Ken Shirriff's blog - RSS" href="http://www.righto.com/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Ken Shirriff's blog - Atom" href="https://www.blogger.com/feeds/6264947694886887540/posts/default" /> <link rel="me" href="https://www.blogger.com/profile/08097301407311055124" /> <!--Can't find substitution for tag [blog.ieCssRetrofitLinks]--> <meta content='http://www.righto.com/search/label/ir' property='og:url'/> <meta content='Ken Shirriff's blog' property='og:title'/> <meta content='Computer history, restoring vintage computers, IC reverse engineering, and whatever' property='og:description'/> <title>Ken Shirriff's blog: ir</title> <style type='text/css'>@font-face{font-family:'Play';font-style:normal;font-weight:400;font-display:swap;src:url(//fonts.gstatic.com/s/play/v19/6aez4K2oVqwIvtU2Gw.eot);}</style> <style id='page-skin-1' type='text/css'><!-- /* ----------------------------------------------- Blogger Template Style Name: Simple Designer: Blogger URL: www.blogger.com ----------------------------------------------- */ /* Variable definitions ==================== <Variable name="keycolor" description="Main Color" type="color" default="#66bbdd"/> <Group description="Page Text" selector="body"> <Variable name="body.font" description="Font" type="font" default="normal normal 12px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="body.text.color" description="Text Color" type="color" default="#222222"/> </Group> <Group description="Backgrounds" selector=".body-fauxcolumns-outer"> <Variable name="body.background.color" description="Outer Background" type="color" default="#66bbdd"/> <Variable name="content.background.color" description="Main Background" type="color" default="#ffffff"/> <Variable name="header.background.color" description="Header Background" type="color" default="transparent"/> </Group> <Group description="Links" selector=".main-outer"> <Variable name="link.color" description="Link Color" type="color" default="#2288bb"/> <Variable name="link.visited.color" description="Visited Color" type="color" default="#888888"/> <Variable name="link.hover.color" description="Hover Color" type="color" default="#33aaff"/> </Group> <Group description="Blog Title" selector=".header h1"> <Variable name="header.font" description="Font" type="font" default="normal normal 60px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="header.text.color" description="Title Color" type="color" default="#3399bb" /> </Group> <Group description="Blog Description" selector=".header .description"> <Variable name="description.text.color" description="Description Color" type="color" default="#777777" /> </Group> <Group description="Tabs Text" selector=".tabs-inner .widget li a"> <Variable name="tabs.font" description="Font" type="font" default="normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="tabs.text.color" description="Text Color" type="color" default="#999999"/> <Variable name="tabs.selected.text.color" description="Selected Color" type="color" default="#000000"/> </Group> <Group description="Tabs Background" selector=".tabs-outer .PageList"> <Variable name="tabs.background.color" description="Background Color" type="color" default="#f5f5f5"/> <Variable name="tabs.selected.background.color" description="Selected Color" type="color" default="#eeeeee"/> </Group> <Group description="Post Title" selector="h3.post-title, .comments h4"> <Variable name="post.title.font" description="Font" type="font" default="normal normal 22px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> </Group> <Group description="Date Header" selector=".date-header"> <Variable name="date.header.color" description="Text Color" type="color" default="#222222"/> <Variable name="date.header.background.color" description="Background Color" type="color" default="transparent"/> <Variable name="date.header.font" description="Text Font" type="font" default="normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="date.header.padding" description="Date Header Padding" type="string" default="inherit"/> <Variable name="date.header.letterspacing" description="Date Header Letter Spacing" type="string" default="inherit"/> <Variable name="date.header.margin" description="Date Header Margin" type="string" default="inherit"/> </Group> <Group description="Post Footer" selector=".post-footer"> <Variable name="post.footer.text.color" description="Text Color" type="color" default="#666666"/> <Variable name="post.footer.background.color" description="Background Color" type="color" default="#f9f9f9"/> <Variable name="post.footer.border.color" description="Shadow Color" type="color" default="#eeeeee"/> </Group> <Group description="Gadgets" selector="h2"> <Variable name="widget.title.font" description="Title Font" type="font" default="normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="widget.title.text.color" description="Title Color" type="color" default="#000000"/> <Variable name="widget.alternate.text.color" description="Alternate Color" type="color" default="#999999"/> </Group> <Group description="Images" selector=".main-inner"> <Variable name="image.background.color" description="Background Color" type="color" default="#ffffff"/> <Variable name="image.border.color" description="Border Color" type="color" default="#eeeeee"/> <Variable name="image.text.color" description="Caption Text Color" type="color" default="#222222"/> </Group> <Group description="Accents" selector=".content-inner"> <Variable name="body.rule.color" description="Separator Line Color" type="color" default="#eeeeee"/> <Variable name="tabs.border.color" description="Tabs Border Color" type="color" default="#eeeeee"/> </Group> <Variable name="body.background" description="Body Background" type="background" color="#f6fbf6" default="$(color) none repeat scroll top left"/> <Variable name="body.background.override" description="Body Background Override" type="string" default=""/> <Variable name="body.background.gradient.cap" description="Body Gradient Cap" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/gradients_light.png)"/> <Variable name="body.background.gradient.tile" description="Body Gradient Tile" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/body_gradient_tile_light.png)"/> <Variable name="content.background.color.selector" description="Content Background Color Selector" type="string" default=".content-inner"/> <Variable name="content.padding" description="Content Padding" type="length" default="10px" min="0" max="100px"/> <Variable name="content.padding.horizontal" description="Content Horizontal Padding" type="length" default="10px" min="0" max="100px"/> <Variable name="content.shadow.spread" description="Content Shadow Spread" type="length" default="40px" min="0" max="100px"/> <Variable name="content.shadow.spread.webkit" description="Content Shadow Spread (WebKit)" type="length" default="5px" min="0" max="100px"/> <Variable name="content.shadow.spread.ie" description="Content Shadow Spread (IE)" type="length" default="10px" min="0" max="100px"/> <Variable name="main.border.width" description="Main Border Width" type="length" default="0" min="0" max="10px"/> <Variable name="header.background.gradient" description="Header Gradient" type="url" default="none"/> <Variable name="header.shadow.offset.left" description="Header Shadow Offset Left" type="length" default="-1px" min="-50px" max="50px"/> <Variable name="header.shadow.offset.top" description="Header Shadow Offset Top" type="length" default="-1px" min="-50px" max="50px"/> <Variable name="header.shadow.spread" description="Header Shadow Spread" type="length" default="1px" min="0" max="100px"/> <Variable name="header.padding" description="Header Padding" type="length" default="30px" min="0" max="100px"/> <Variable name="header.border.size" description="Header Border Size" type="length" default="1px" min="0" max="10px"/> <Variable name="header.bottom.border.size" description="Header Bottom Border Size" type="length" default="0" min="0" max="10px"/> <Variable name="header.border.horizontalsize" description="Header Horizontal Border Size" type="length" default="0" min="0" max="10px"/> <Variable name="description.text.size" description="Description Text Size" type="string" default="140%"/> <Variable name="tabs.margin.top" description="Tabs Margin Top" type="length" default="0" min="0" max="100px"/> <Variable name="tabs.margin.side" description="Tabs Side Margin" type="length" default="30px" min="0" max="100px"/> <Variable name="tabs.background.gradient" description="Tabs Background Gradient" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/gradients_light.png)"/> <Variable name="tabs.border.width" description="Tabs Border Width" type="length" default="1px" min="0" max="10px"/> <Variable name="tabs.bevel.border.width" description="Tabs Bevel Border Width" type="length" default="1px" min="0" max="10px"/> <Variable name="post.margin.bottom" description="Post Bottom Margin" type="length" default="25px" min="0" max="100px"/> <Variable name="image.border.small.size" description="Image Border Small Size" type="length" default="2px" min="0" max="10px"/> <Variable name="image.border.large.size" description="Image Border Large Size" type="length" default="5px" min="0" max="10px"/> <Variable name="page.width.selector" description="Page Width Selector" type="string" default=".region-inner"/> <Variable name="page.width" description="Page Width" type="string" default="auto"/> <Variable name="main.section.margin" description="Main Section Margin" type="length" default="15px" min="0" max="100px"/> <Variable name="main.padding" description="Main Padding" type="length" default="15px" min="0" max="100px"/> <Variable name="main.padding.top" description="Main Padding Top" type="length" default="30px" min="0" max="100px"/> <Variable name="main.padding.bottom" description="Main Padding Bottom" type="length" default="30px" min="0" max="100px"/> <Variable name="paging.background" color="#ffffff" description="Background of blog paging area" type="background" default="transparent none no-repeat scroll top center"/> <Variable name="footer.bevel" description="Bevel border length of footer" type="length" default="0" min="0" max="10px"/> <Variable name="mobile.background.overlay" description="Mobile Background Overlay" type="string" default="transparent none repeat scroll top left"/> <Variable name="mobile.background.size" description="Mobile Background Size" type="string" default="auto"/> <Variable name="mobile.button.color" description="Mobile Button Color" type="color" default="#ffffff" /> <Variable name="startSide" description="Side where text starts in blog language" type="automatic" default="left"/> <Variable name="endSide" description="Side where text ends in blog language" type="automatic" default="right"/> */ /* Content ----------------------------------------------- */ body { font: normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #222222; background: #f6fbf6 none repeat scroll top left; padding: 0 40px 40px 40px; } html body .region-inner { min-width: 0; max-width: 100%; width: auto; } h2 { font-size: 22px; } a:link { text-decoration:none; color: #121fb3; } a:visited { text-decoration:none; color: #121fb3; } a:hover { text-decoration:underline; color: #1a00ff; } .body-fauxcolumn-outer .fauxcolumn-inner { background: transparent url(//www.blogblog.com/1kt/simple/body_gradient_tile_light.png) repeat scroll top left; _background-image: none; } .body-fauxcolumn-outer .cap-top { position: absolute; z-index: 1; height: 400px; width: 100%; } .body-fauxcolumn-outer .cap-top .cap-left { width: 100%; background: transparent url(//www.blogblog.com/1kt/simple/gradients_light.png) repeat-x scroll top left; _background-image: none; } .content-outer { -moz-box-shadow: 0 0 40px rgba(0, 0, 0, .15); -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .15); -goog-ms-box-shadow: 0 0 10px #333333; box-shadow: 0 0 40px rgba(0, 0, 0, .15); margin-bottom: 1px; } .content-inner { padding: 10px 10px; } .content-inner { background-color: #ffffff; } /* Header ----------------------------------------------- */ .header-outer { background: #f6fbf7 url(//www.blogblog.com/1kt/simple/gradients_light.png) repeat-x scroll 0 -400px; _background-image: none; } .Header h1 { font: normal normal 42px Play; color: #666666; text-shadow: 1px 2px 3px rgba(0, 0, 0, .2); } .Header h1 a { color: #666666; } .Header .description { font-size: 140%; color: #666666; } .header-inner .Header .titlewrapper { padding: 22px 30px; } .header-inner .Header .descriptionwrapper { padding: 0 30px; } /* Tabs ----------------------------------------------- */ .tabs-inner .section:first-child { border-top: 0 solid #eeeeee; } .tabs-inner .section:first-child ul { margin-top: -0; border-top: 0 solid #eeeeee; border-left: 0 solid #eeeeee; border-right: 0 solid #eeeeee; } .tabs-inner .widget ul { background: #f5f5f5 url(//www.blogblog.com/1kt/simple/gradients_light.png) repeat-x scroll 0 -800px; _background-image: none; border-bottom: 1px solid #eeeeee; margin-top: 0; margin-left: -30px; margin-right: -30px; } .tabs-inner .widget li a { display: inline-block; padding: .6em 1em; font: normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #999999; border-left: 1px solid #ffffff; border-right: 1px solid #eeeeee; } .tabs-inner .widget li:first-child a { border-left: none; } .tabs-inner .widget li.selected a, .tabs-inner .widget li a:hover { color: #000000; background-color: #eeeeee; text-decoration: none; } /* Columns ----------------------------------------------- */ .main-outer { border-top: 0 solid #eeeeee; } .fauxcolumn-left-outer .fauxcolumn-inner { border-right: 1px solid #eeeeee; } .fauxcolumn-right-outer .fauxcolumn-inner { border-left: 1px solid #eeeeee; } /* Headings ----------------------------------------------- */ div.widget > h2, div.widget h2.title { margin: 0 0 1em 0; font: normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif; color: #000000; } /* Widgets ----------------------------------------------- */ .widget .zippy { color: #999999; text-shadow: 2px 2px 1px rgba(0, 0, 0, .1); } .widget .popular-posts ul { list-style: none; } /* Posts ----------------------------------------------- */ h2.date-header { font: normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif; } .date-header span { background-color: transparent; color: transparent; padding: inherit; letter-spacing: inherit; margin: inherit; } .main-inner { padding-top: 30px; padding-bottom: 30px; } .main-inner .column-center-inner { padding: 0 15px; } .main-inner .column-center-inner .section { margin: 0 15px; } .post { margin: 0 0 25px 0; } h3.post-title, .comments h4 { font: normal normal 22px Arial, Tahoma, Helvetica, FreeSans, sans-serif; margin: .75em 0 0; } .post-body { font-size: 110%; line-height: 1.4; position: relative; } .post-body img, .post-body .tr-caption-container, .Profile img, .Image img, .BlogList .item-thumbnail img { padding: 2px; background: #ffffff; border: 1px solid #ffffff; -moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); } .post-body img, .post-body .tr-caption-container { padding: 5px; } .post-body .tr-caption-container { color: #222222; } .post-body .tr-caption-container img { padding: 0; background: transparent; border: none; -moz-box-shadow: 0 0 0 rgba(0, 0, 0, .1); -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .1); box-shadow: 0 0 0 rgba(0, 0, 0, .1); } .post-header { margin: 0 0 1.5em; line-height: 1.6; font-size: 90%; } .post-footer { margin: 20px -2px 0; padding: 5px 10px; color: #666666; background-color: #f9f9f9; border-bottom: 1px solid #eeeeee; line-height: 1.6; font-size: 90%; } #comments .comment-author { padding-top: 1.5em; border-top: 1px solid #eeeeee; background-position: 0 1.5em; } #comments .comment-author:first-child { padding-top: 0; border-top: none; } .avatar-image-container { margin: .2em 0 0; } #comments .avatar-image-container img { border: 1px solid #ffffff; } /* Comments ----------------------------------------------- */ .comments .comments-content .icon.blog-author { background-repeat: no-repeat; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9sLFwMeCjjhcOMAAAD+SURBVDjLtZSvTgNBEIe/WRRnm3U8RC1neQdsm1zSBIU9VVF1FkUguQQsD9ITmD7ECZIJSE4OZo9stoVjC/zc7ky+zH9hXwVwDpTAWWLrgS3QAe8AZgaAJI5zYAmc8r0G4AHYHQKVwII8PZrZFsBFkeRCABYiMh9BRUhnSkPTNCtVXYXURi1FpBDgArj8QU1eVXUzfnjv7yP7kwu1mYrkWlU33vs1QNu2qU8pwN0UpKoqokjWwCztrMuBhEhmh8bD5UDqur75asbcX0BGUB9/HAMB+r32hznJgXy2v0sGLBcyAJ1EK3LFcbo1s91JeLwAbwGYu7TP/3ZGfnXYPgAVNngtqatUNgAAAABJRU5ErkJggg==); } .comments .comments-content .loadmore a { border-top: 1px solid #999999; border-bottom: 1px solid #999999; } .comments .comment-thread.inline-thread { background-color: #f9f9f9; } .comments .continue { border-top: 2px solid #999999; } /* Accents ---------------------------------------------- */ .section-columns td.columns-cell { border-left: 1px solid #eeeeee; } .blog-pager { background: transparent none no-repeat scroll top center; } .blog-pager-older-link, .home-link, .blog-pager-newer-link { background-color: #ffffff; padding: 5px; } .footer-outer { border-top: 0 dashed #bbbbbb; } /* Mobile ----------------------------------------------- */ body.mobile { background-size: auto; } .mobile .body-fauxcolumn-outer { background: transparent none repeat scroll top left; } .mobile .body-fauxcolumn-outer .cap-top { background-size: 100% auto; } .mobile .content-outer { -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, .15); box-shadow: 0 0 3px rgba(0, 0, 0, .15); } .mobile .tabs-inner .widget ul { margin-left: 0; margin-right: 0; } .mobile .post { margin: 0; } .mobile .main-inner .column-center-inner .section { margin: 0; } .mobile .date-header span { padding: 0.1em 10px; margin: 0 -10px; } .mobile h3.post-title { margin: 0; } .mobile .blog-pager { background: transparent none no-repeat scroll top center; } .mobile .footer-outer { border-top: none; } .mobile .main-inner, .mobile .footer-inner { background-color: #ffffff; } .mobile-index-contents { color: #222222; } .mobile-link-button { background-color: #121fb3; } .mobile-link-button a:link, .mobile-link-button a:visited { color: #ffffff; } .mobile .tabs-inner .section:first-child { border-top: none; } .mobile .tabs-inner .PageList .widget-content { background-color: #eeeeee; color: #000000; border-top: 1px solid #eeeeee; border-bottom: 1px solid #eeeeee; } .mobile .tabs-inner .PageList .widget-content .pagelist-arrow { border-left: 1px solid #eeeeee; } .content-outer { max-width: 1400px !important; } /* fix header */ #header-inner { width: 100% !important; background-position: right !important; } .titlewrapper { padding: 11px 30px 0 !important; } .descriptionwrapper { margin-bottom: 0 !important; } .description { font-size: 120% !important; } /* suppress things */ .date-header { display: none; } #Attribution1 { display: none; } .post-author, .post-timestamp, .reaction-buttons { display: none; } /* h2: sidebar titles */ /* h3: post title */ .post-title , .entry-title { font-size: 180% !important; margin-top: 0 !important; } .entry-title a:link, .entry-title a:visited, .entry-title a:active{ color: #a03; } #main h2 { color:#333; margin-bottom:.4em; margin-top: 13px; font-size:140%; } #main h3 { color:#333; margin-bottom:.4em; margin-top: 13px; font-size:110%; } #main h4 { color:#333; margin-bottom:.5em; } #sidebar-right-1 a:link, #sidebar-right-1 a:visited, #sidebar-right-1 a:active { color: #666; } #sidebar-right-1 h2 { font-size: 100%; color: #666; } /* disable image box */ element.style { } table.chargers img { height: 18px; } table.chargers img { height: 18px; } .post-body img, .post-body .tr-caption-container { padding: 5px; } .post-body img, .post-body .tr-caption-container, .Profile img, .Image img, .BlogList .item-thumbnail img { padding: 0; background: #ffffff; border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } /* Special items */ a:link img.hilite, a:visited img.hilite { color: #fff; } a:hover img.hilite, a:hover img.hilite2 { color: #f66; } a:active img.hilite { color: #33c; } .hilite {cursor:zoom-in} pre {color:#000000;border:1px solid #000000;} pre.repl { background-color:#e0e0f0; font-size:120%;} pre.arc { background-color:#e0e0f0; font-size:120%;} pre.code { background-color:#e0f0e0; font-size:120%; white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;text-wrap:unrestricted;} code { font-size: 100%;} blockquote { font-size: 110%; background: transparent url("//static.righto.com/images/blockquote.gif") no-repeat 0 0; margin: 20px 0px; padding: 0px 40px;} div.cite {font-size: .8em;.; font-style: italic; color: #888; margin-bottom: 9px;} a.ref { color: gray;vertical-align: super; text-decoration: none; font-size:60%;margin-left: 2px;} a img.hilite { border: 1px solid; color: #888; z-index: 2; } a img.hilite2, a:active img.hilite2 { border: 1px solid; color: #f6fbf6; } table.chargers { border-width: 1px; border-spacing: 2px; border-style: outset; border-color: gray; border-collapse: collapse; background-color: white; } table.chargers th.maker { padding-right: 5px; text-align: right; } table.chargers th { border-width: 1px; padding: 3px; border-style: inset; border-color: gray; background-color: white; text-align: center; } table.chargers img { height: 18px; } table.chargers td { text-align: center; border-width: 1px; padding: 2px 8px; border-style: inset; border-color: gray; background-color: white; } --></style> <style id='template-skin-1' type='text/css'><!-- body { min-width: 750px; } .content-outer, .content-fauxcolumn-outer, .region-inner { min-width: 750px; max-width: 750px; _width: 750px; } .main-inner .columns { padding-left: 0px; padding-right: 240px; } .main-inner .fauxcolumn-center-outer { left: 0px; right: 240px; /* IE6 does not respect left and right together */ _width: expression(this.parentNode.offsetWidth - parseInt("0px") - parseInt("240px") + 'px'); } .main-inner .fauxcolumn-left-outer { width: 0px; } .main-inner .fauxcolumn-right-outer { width: 240px; } .main-inner .column-left-outer { width: 0px; right: 100%; margin-left: -0px; } .main-inner .column-right-outer { width: 240px; margin-right: -240px; } #layout { min-width: 0; } #layout .content-outer { min-width: 0; width: 800px; } #layout .region-inner { min-width: 0; width: auto; } --></style> <meta content='width=device-width, initial-scale=1.0, maximum-scale=12.0, minimum-scale=.25, user-scalable=yes' name='viewport'/> <meta content='mw8ww70r3jW0GzXY6j1d' name='follow_it-verification-code'/> <link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=6264947694886887540&zx=3956e174-e56c-4fb5-a38a-a6c44dbc69e8' media='none' onload='if(media!='all')media='all'' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=6264947694886887540&zx=3956e174-e56c-4fb5-a38a-a6c44dbc69e8' rel='stylesheet'/></noscript> <meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> </head> <body class='loading'> <div class='navbar no-items section' id='navbar'> </div> <div itemscope='itemscope' itemtype='http://schema.org/Blog' style='display: none;'> <meta content='Ken Shirriff's blog' itemprop='name'/> </div> <div class='body-fauxcolumns'> <div class='fauxcolumn-outer body-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content'> <div class='content-fauxcolumns'> <div class='fauxcolumn-outer content-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content-outer'> <div class='content-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left content-fauxborder-left'> <div class='fauxborder-right content-fauxborder-right'></div> <div class='content-inner'> <header> <div class='header-outer'> <div class='header-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left header-fauxborder-left'> <div class='fauxborder-right header-fauxborder-right'></div> <div class='region-inner header-inner'> <div class='header section' id='header'><div class='widget Header' data-version='1' id='Header1'> <div id='header-inner' style='background-image: url("https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-4KXwYe0lQ4HFzhAye9vvRlij2ZYvMbfPCnqEE__1o85Fjo3XgefxJQhWRdwR3EzNWNMWT3yMaj2QZaT9GazqQx3C6oWa3-hBNlRHG7f-Oib-lv1Wq_C2_A0rt8xZgs87iNqzRVKK7H0A/s800/background.jpg"); background-position: left; width: 550px; min-height: 105px; _height: 105px; background-repeat: no-repeat; '> <div class='titlewrapper' style='background: transparent'> <h1 class='title' style='background: transparent; border-width: 0px'> <a href='http://www.righto.com/'> Ken Shirriff's blog </a> </h1> </div> <div class='descriptionwrapper'> <p class='description'><span>Computer history, restoring vintage computers, IC reverse engineering, and whatever</span></p> </div> </div> </div></div> </div> </div> <div class='header-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </header> <div class='tabs-outer'> <div class='tabs-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left tabs-fauxborder-left'> <div class='fauxborder-right tabs-fauxborder-right'></div> <div class='region-inner tabs-inner'> <div class='tabs no-items section' id='crosscol'></div> <div class='tabs no-items section' id='crosscol-overflow'></div> </div> </div> <div class='tabs-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='main-outer'> <div class='main-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left main-fauxborder-left'> <div class='fauxborder-right main-fauxborder-right'></div> <div class='region-inner main-inner'> <div class='columns fauxcolumns'> <div class='fauxcolumn-outer fauxcolumn-center-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-left-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-right-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <!-- corrects IE6 width calculation --> <div class='columns-inner'> <div class='column-center-outer'> <div class='column-center-inner'> <div class='main section' id='main'><div class='widget Blog' data-version='1' id='Blog1'> <div class='blog-posts hfeed'> <div class='status-msg-wrap'> <div class='status-msg-body'> Showing posts with label <b>ir</b>. <a href="http://www.righto.com/">Show all posts</a> </div> <div class='status-msg-border'> <div class='status-msg-bg'> <div class='status-msg-hidden'>Showing posts with label <b>ir</b>. <a href="http://www.righto.com/">Show all posts</a></div> </div> </div> </div> <div style='clear: both;'></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPYJE0KVJEc0Ac4F_-PCbTugKlp7OvV_hkypxLNu7nLwWZJGYjXXZxNAsY_T5y0W0tTTZWNKcZBvRiWWiOCrDhJi6ZbfZjU92aqzilKeTOVqlqyiWlARHErnG2alDnLhRWWfaSlzo0_MVZ/w400/arduino-ir.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='3784843694276450072' itemprop='postId'/> <a name='3784843694276450072'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2017/12/decoding-air-conditioner-controls.html'>Decoding an air conditioner control's checksum with differential cryptanalysis</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-3784843694276450072' itemprop='description articleBody'> <style> pre.irremote {border:none;background-color:#eee;max-width:30em;padding:4px;max-height:5em; overflow:auto} code {background-color:#eee;font-size:80%;} </style> <p>Back in 2009 I wrote an Arduino library (<a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">IRRemote</a>) to encode and decode infrared signals for remote controls. I got an email recently from someone wanting to control an air conditioner. It turns out that air conditioner remote controls are much complicated than TV remote controls: the codes are longer and include a moderately complex checksum. My reader had collected 35 signals from his air conditioner remote control, but couldn't figure out the checksum algorithm. I decided to use differential cryptanalysis to figure out the checksum, which was overkill but an interesting exercise. In case anyone else wants to decode a similar remote control, I've written up how I found the algorithm.</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPYJE0KVJEc0Ac4F_-PCbTugKlp7OvV_hkypxLNu7nLwWZJGYjXXZxNAsY_T5y0W0tTTZWNKcZBvRiWWiOCrDhJi6ZbfZjU92aqzilKeTOVqlqyiWlARHErnG2alDnLhRWWfaSlzo0_MVZ/w9999/arduino-ir.jpg"><img alt="My IR remote library can be used with the Arduino to send and receive signals. (This is not the air conditioner remote.)" class="hilite" height="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPYJE0KVJEc0Ac4F_-PCbTugKlp7OvV_hkypxLNu7nLwWZJGYjXXZxNAsY_T5y0W0tTTZWNKcZBvRiWWiOCrDhJi6ZbfZjU92aqzilKeTOVqlqyiWlARHErnG2alDnLhRWWfaSlzo0_MVZ/w400/arduino-ir.jpg" title="My IR remote library can be used with the Arduino to send and receive signals. (This is not the air conditioner remote.)" width="300" /></a><div class="cite">My IR remote library can be used with the Arduino to send and receive signals. (This is not the air conditioner remote.)</div></p> <p>The problem is to find a checksum algorithm that when given three bytes of input (left), computes the correct one byte checksum (right).</p> <pre class="irremote"> 10100001 10010011 01100011 => 01110111 10100001 10010011 01100100 => 01110001 10100001 10010011 01100101 => 01110000 10100001 10010011 01100110 => 01110010 10100001 10010011 01100111 => 01110011 10100001 10010011 01101000 => 01111001 10100001 10010011 01101001 => 01111000 10100001 10010011 01101010 => 01111010 10100001 10010011 01101011 => 01111011 10100001 10010011 01101100 => 01111110 10100001 10010011 01101101 => 01111111 10100001 10010011 01101110 => 01111100 10100001 10010011 01101111 => 01111101 10100001 10010011 01110001 => 01100100 10100001 10010011 01110010 => 01100110 10100001 10010011 01110011 => 01100111 10100001 10010011 01110100 => 01100001 10100001 10010011 01110101 => 01100000 10100001 10010011 01110111 => 01100011 10100001 10010011 01110111 => 01100011 10100001 10010011 01111000 => 01101001 10100001 10010011 01101000 => 01111001 10100001 00010011 01101000 => 11111001 10100001 00010011 01101100 => 11111110 10100001 10010011 01101100 => 01111110 10100001 10010100 01111110 => 01101011 10100001 10000010 01101100 => 01100000 10100001 10000001 01101100 => 01100011 10100001 10010011 01101100 => 01111110 10100001 10010000 01101100 => 01111100 10100001 10011000 01101100 => 01110100 10100001 10001000 01101100 => 01101100 10100001 10010000 01101100 => 01111100 10100001 10011000 01101100 => 01110100 10100010 00000010 11111111 => 01111110 </pre> <p>The idea behind differential cryptanalysis is to look at the outputs resulting from inputs that have a small difference, to see what patterns emerge (<a href="https://en.wikipedia.org/wiki/Differential_cryptanalysis">details</a>). Finding air conditioner checksums is kind of a trivial application of differential cryptanalysis, but using differential cryptanalysis provides a framework for approaching the problem. I wrote a <a href="https://gist.github.com/shirriff/f4a45ba24ad19216225aa85525492f6b">simple program</a> that found input pairs that differed in one bit and displayed the difference (i.e. xor) between the corresponding checksums. The table below shows the differences.</p> <pre class="irremote"> 000000000000000000000001 : 00000001 000000000000000000000010 : 00000010 000000000000000000000010 : 00000011 000000000000000000000100 : 00000100 000000000000000000000100 : 00000110 000000000000000000000100 : 00000111 000000000000000000001000 : 00001100 000000000000000000001000 : 00001110 000000000000000000001000 : 00001111 000000000000000000010000 : 00010000 000000000000100000000000 : 00001000 000000000001000000000000 : 00011000 000000001000000000000000 : 10000000 </pre> <p>The first thing to notice is that changing one bit in the input causes a relatively small change in the output. If the checksum were something cryptographic, a single bit change would entirely change the output (so you'd see half the bits flipped on average). Thus, we know we're dealing with a simple algorithm.</p> <p>The second thing to notice is the upper four bits of the checksum change simply: changing a bit in the upper four bits of an input byte changes the corresponding bit in the upper four bits of the output. This suggests that the the three bytes are simply xor'd to generate the upper four bits. In fact, my reader had already determined that the xor of the input bytes (along with 0x20) yielded the upper four bits of the checksum.</p> <p>The final thing to notice is there's an unusual avalanche pattern in the lower four bits. Changing the lowest input bit changes the lowest checksum bit. Changing the second-lowest input bit changes the second-lowest checksum bit and potentially the last checksum bit. Likewise changing the fourth-lowest input bit changes the fourth-lowest checksum bit and potentially the bits to the right. And the change pattern always has 1's potentially followed by 0's, not a mixture. (1100, 1110, 1111)</p> <p>What simple operation has this sort of avalanche effect? Consider adding two binary numbers. If you change a high-order bit of an input, only that bit will change in the output. If you change a low-order input bit, the low-order bit of the output will change. But maybe there will be a carry, and the next bit will change. And if there's a carry from that position, the third bit will change. Likewise, changing a bit in the middle will change that bit and potentially some of the bits to the left (due to carries). So if you change the low-order bit, the change in the output could be 0001 (no carry), or 0011, or 0111, or 1111 (all carries). This is the same pattern seen in the air conditioner checksums but backwards. This raises the possibility that the checksum is using a binary sum, but we're looking at the bits backwards.</p> <p>So I made <a href="https://gist.github.com/shirriff/83cb8bf7d9aa4866c6d538ac130b659e">a program</a> that reversed the bits in the input and output, and took the sum of the four bits from each byte. The output below shows the reversed input, the sum, and the 4-bit value from the correct checksum. Note that the sum and the correct value usually add up to 46 or 30 (two short of a multiple of 16). This suggested that the checksum is <code>(-sum-2) & 0xf</code>. <pre class="irremote"> 110001101100100110000101 32 14 001001101100100110000101 22 8 101001101100100110000101 30 0 011001101100100110000101 26 4 111001101100100110000101 34 12 000101101100100110000101 21 9 100101101100100110000101 29 1 010101101100100110000101 25 5 110101101100100110000101 33 13 001101101100100110000101 23 7 101101101100100110000101 31 15 011101101100100110000101 27 3 111101101100100110000101 35 11 100011101100100110000101 28 2 010011101100100110000101 24 6 110011101100100110000101 32 14 001011101100100110000101 22 8 101011101100100110000101 30 0 111011101100100110000101 34 12 111011101100100110000101 34 12 000111101100100110000101 21 9 000101101100100110000101 21 9 000101101100100010000101 21 9 001101101100100010000101 23 7 001101101100100110000101 23 7 011111100010100110000101 17 13 001101100100000110000101 15 0 * 001101101000000110000101 19 12 * 001101101100100110000101 23 7 001101100000100110000101 11 3 001101100001100110000101 12 2 001101100001000110000101 12 3 * 001101100000100110000101 11 3 001101100001100110000101 12 2 111111110100000001000101 23 7 </pre></p> <p>That formula worked with three exceptions (marked with asterisks). Studying the exceptions showed that adding in byte 1 bit 3 and byte 2 bit 7 yielded the correct answer in all cases. </p> <h2>Conclusion</h2> <p>Putting this together yields the following algorithm (<a href="https://gist.github.com/shirriff/dd04fe1026036eb8deaf6c6e3744af53">full code here</a>): <pre class="irremote" style="max-height:100em;max-width:80em;display:inline-block;"> inbytes = map(bitreverse, inbytes) xorpart = (inbytes[0] ^ inbytes[1] ^ inbytes[2] ^ 0x4) & 0xf sumpart = (inbytes[0] >> 4) + (inbytes[1] >> 4) + (inbytes[2] >> 4) + (inbytes[2] & 1) + ((inbytes[1] >> 3) & 1) + 1 sumpart = (-sumpart) & 0xf result = bitreverse((sumpart << 4) | xorpart) </pre></p> <p>Is this the right formula? It gives the right checksum for all the given inputs. However, some bits never change in the input data; in particular all inputs start with "101000", so there's no way of knowing how they affect the algorithm. They could be added to the sum, for instance, replacing the constant <code>+1</code>. The constant 0x4 in the xor also makes me a bit suspicious. It's quite possible that the checksum formula would need to be tweaked if additional input data becomes available.</p> <p>I should point out that determining the checksum formula is unnecessary for most air conditioning applications. Most users could just hard-code the checksums for the handful of commands they want to send, rather than working out the general algorithm.</p> <p>Thanks to Antonio Martinez Lavin, maker of the <a href="http://www.cuby.mx/us">Cuby air conditioner controller</a> for posing this problem. If you want to use my IR library, it is on <a href="https://github.com/z3t0/Arduino-IRremote">GitHub</a>. I'm no longer actively involved with the library, so please post issues on the GitHub repository rather than on this blog post. Thanks to Rafi Kahn, who has taken over library maintenance and improvement.</p> <p>Follow me on <a href="https://twitter.com/kenshirriff">Twitter</a> or <a href="http://www.righto.com/feeds/posts/default">RSS</a> to find out about my latest blog posts.</p> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/3784843694276450072' onclick=''> 8 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=3784843694276450072' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=3784843694276450072&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=3784843694276450072&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=3784843694276450072&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=3784843694276450072&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=3784843694276450072&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=3784843694276450072&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a>, <a href='http://www.righto.com/search/label/reverse-engineering' rel='tag'>reverse-engineering</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='//static.righto.com/images/rigol/rigol_ir_display-s400.png' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='8967838651041212651' itemprop='postId'/> <a name='8967838651041212651'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2013/07/rigol-oscilloscope-hacks-with-python.html'>Four Rigol oscilloscope hacks with Python</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-8967838651041212651' itemprop='description articleBody'> <style> .gist { } .gist-data { height: 350px; } .gist-meta { font-size: 80% !important; } </style> A Rigol oscilloscope has a USB output, allowing you to control it with a computer and and perform additional processing externally. I was inspired by Cibo Mahto's article <a href="http://www.cibomahto.com/2010/04/controlling-a-rigol-oscilloscope-using-linux-and-python">Controlling a Rigol oscilloscope using Linux and Python</a>, and came up with some new Python oscilloscope hacks: super-zoomable graphs, generating a spectrogram, analyzing an IR signal, and dumping an oscilloscope trace as a WAV file. The key techniques I illustrate are connecting to the oscilloscope with Windows, accessing a megabyte of data with Long Memory, and performing analysis on the data. <p> <a href="//static.righto.com/images/rigol/rigol_ir_display.png"><img alt="Analyzing the IR signal from a TV remote using an IR sensor and a Rigol DS1052E oscilloscope." class="hilite" src="//static.righto.com/images/rigol/rigol_ir_display-s400.png" title="Analyzing the IR signal from a TV remote using an IR sensor and a Rigol DS1052E oscilloscope." width="400"> </a> <p> <div class="cite"> Analyzing the IR signal from a TV remote using an IR sensor and a Rigol DS1052E oscilloscope. </div> <h2>Super-zoomable graphs</h2> One of the nice features of the Rigol is "Long Memory" - instead of downloading the 600-point trace that appears on the screen, you can record and access a high-resolution trace of 1 million points. In this hack, I show how you can display this data with Python, giving you a picture that you can easily zoom into with the mouse. <p> The following screenshot shows the data collected by hooking the oscilloscope up to an IR sensor. In the above picture, the sensor is the three-pin device below the screen. Since I've developed an <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">IR library for Arduino</a>, my examples focus on IR, but any sort of signal could be used. By enabling Long Memory, we can download not just the data on the screen, but 1 million data points, allowing us to zoom way, way in. The graph below shows what it sent when you press a button on the TV remote - the selected button transmits a code, followed by a periodic repeat signal as long as the button is held down. <p> <a href="//static.righto.com/images/rigol/rigol_ir1.png"><img alt="The IR signal from a TV remote. The first block is the code, followed by period repeat signals while the button is held down." class="hilite" src="//static.righto.com/images/rigol/rigol_ir1-w350.png" title="The IR signal from a TV remote. The first block is the code, followed by period repeat signals while the button is held down." width="350"> </a> <p> <div class="cite"> The IR signal from a TV remote. The first block is the code, followed by period repeat signals while the button is held down. </div> But with Long Memory, we can interactively zoom way on the waveform and see the actual structure of the code - long header pulses followed by a sequence of wide and narrow pulses that indicate the particular button. That's not the end of the zooming - we can zoom way in on an edge of a pulse and see the actual rise time of the signal over a few microseconds. You can do some pretty nice zooming when you have a million datapoints to plot. <p> <a href="//static.righto.com/images/rigol/rigol_ir2a.png"><img alt="Zooming in on the first part of the waveform shows the structure of the code - long header pulses followed by wide and narrow pulses." class="hilite" src="//static.righto.com/images/rigol/rigol_ir2a-w350.png" title="Zooming in on the first part of the waveform shows the structure of the code - long header pulses followed by wide and narrow pulses." width="350"> </a> <a href="//static.righto.com/images/rigol/rigol_ir3a.png"><img alt="Zooming way, way in on the edge of a pulse shows the rise time of the signal." class="hilite" src="//static.righto.com/images/rigol/rigol_ir3a-w350.png" title="Zooming way, way in on the edge of a pulse shows the rise time of the signal." width="350"> </a> <p> To use this script, first enable Long Memory by going to Acquire: MemDepth. Next, set the trigger sweep to Single. Capture the desired waveform on the oscilloscope. Then run the Python script to upload the data to your computer, which will display a plot using <code>matplotlib</code>. To zoom, click the "+" icon at the bottom of the screen. This lets you pan back and forth through the data by holding down the left mouse button. You can zoom in and out by holding the right mouse button down and moving the mouse right or left. The magnifying glass icon lets you select a zoom rectangle with the mouse. You can zoom on your oscilloscope too, of course, but using a mouse and having labeled axes can be much more convenient. <p> <script src="https://gist.github.com/shirriff/bb010c7dbd7f0ce69cba.js"></script> <p> A few things to notice about the code. The first few lines get the list of instruments connected to VISA and open the USB instrument (i.e. your oscilloscope). The timeout and chunk size need to be increased from the defaults to download the large amount of data without timeouts. <p> Next, <code>ask_for_values</code> gets various scale values from the oscilloscope so the axes can be labeled properly. By setting the mode to <code>RAW</code> we download the full dataset, not just what is visible on the screen. We get the raw data from channel 1 with <code>:WAV:DATA? CHAN1</code>. The first 10 bytes are a header and should be discarded. Next, the raw bytes are converted to numeric values with Mahto's formulas. Finally, <code>matplotlib</code> plots the data. <p> There are a couple "gotchas" with Long Memory. First, it only works reliably if you capture a single trace by setting the trigger sweep to "single". Second, downloading all this data over USB takes 10 seconds or so, which can be inconveniently slow. <h2>Analyze an IR signal</h2> Once we can download a signal from the oscilloscope, we can do more than just plot it - we can process and analyze it. In this hack, I decode the IR signal and print the corresponding hex value. Since it takes 10 seconds to download the signal, this isn't a practical way of using an IR remote for control. The point is to illustrate how you can perform logic analysis on the oscilloscope trace by using Python. <p> This code shows how the Python script can wait for the oscilloscope to be triggered and enter the <code>STOP</code> state. It also shows how you can use Python to initialize the oscilloscope to a desired configuration. The oscilloscope gets confused if you send too many commands at once, so I put a short delay between the commands. <p> <script src="https://gist.github.com/shirriff/6027183.js"></script> <h2>Generate a spectrogram</h2> Another experiment I did was using Python libraries to generate a <a href="https://en.wikipedia.org/wiki/Spectrogram">spectrogram</a> of a signal recorded by the oscilloscope. I simply hooked a microphone to the oscilloscope, spoke a few words, and used the script below to analyze the signal. The spectrogram shows low frequencies at the bottom, high frequencies at the top, and time progresses left to right. This is basically a FFT swept through time. <p> <a href="//static.righto.com/images/rigol/spectrogram.png"><img alt="A spectrogram generated by matplotlib using data from a Rigol DS1052E oscilloscope." class="hilite" src="//static.righto.com/images/rigol/spectrogram-s400.png" title="A spectrogram generated by matplotlib using data from a Rigol DS1052E oscilloscope." width="400"> </a> <p> <div class="cite"> A spectrogram generated by matplotlib using data from a Rigol DS1052E oscilloscope. </div> To use this script, set up the oscilloscope for Long Memory as before, record the signal, and then run the script. <p> <script src="https://gist.github.com/shirriff/fe6e78f22972b52cabce.js"></script> <h2>Dump data to a .wav file</h2> You might want to analyze the oscilloscope trace with other tools, such as <a href="http://audacity.sourceforge.net/">Audacity</a>. By dumping the oscilloscope data into a WAV file, it can easily be read into other software. Or you can play the data and hear how it sounds. <p> To use this script, enable Long Memory as described above, capture the signal, and run the script. A file <code>channel1.wav</code> will be created. <p> <script src="https://gist.github.com/shirriff/1a74ef2d3f98b5fe3110.js"></script> <h2>How to install the necessary libraries</h2> Before connecting your oscilloscope to your Windows computer, there are several software packages you'll need. <ul> <li>I assume you have Python already installed - I'm using 2.7.3. <li> Install <a href="http://joule.ni.com/nidu/cds/view/p/id/3342/lang/en">NI-VISA Run-Time Engine 5.2</a>. This is National Instruments Virtual Instrument Software Architecture, providing an interface to hardware test equipment. <li> Install <a href="http://sourceforge.net/projects/pyvisa/">PyVISA</a>, the Python interface to VISA. <li> If you want to run the graphical programs, install <a href="http://www.numpy.org/">Numpy</a> and <a href="http://matplotlib.org/">matplotlib</a>. </ul> You can also use Rigol's <a href="http://www.rigolna.com/products/digital-oscilloscopes/ds1000e/#tabs-4">UltraScope for DS1000E</a> software, but the included NI_VISA 4.3 software doesn't work with pyVisa - I ended up with <code>VI_WARN_CONFIG_NLOADED</code> errors. If you've already installed Ultrascope, you'll probably need to uninstall and reinstall NI_VISA. <p> If you're using Linux instead of Windows, see <a href="http://www.cibomahto.com/2010/04/controlling-a-rigol-oscilloscope-using-linux-and-python">Mehta's article</a>. <h2>How to control and program the oscilloscope</h2> Once the software is installed (below), connect the oscilloscope to the computer's USB port. Use the USB port on the back of the oscilloscope, not the flash drive port on the front panel. <p> Hopefully the code examples above are clear. First, the Python program must get the list of connected instruments from pyVisa and open the USB instrument, which will have a name like <code>USB0::0x1AB1::0x0588::DS1ED141904883</code>. Once the oscilloscope connection is open, you can use <code>scope.write()</code> to send a command to the oscilloscope, <code>scope.ask()</code> to send a command and read a result string, and <code>scope.ask_for_values()</code> to send a command and read a float back from the oscilloscope. <p> When the oscilloscope is under computer control, the screen shows <span style="color:red">Rmt</span> and the front panel is non-responsive. The "Force" button will restore local control. Software can release the oscilloscope by sending the corresponding ":KEY:FORCE" command. <p> Error handling in pyVisa is minimal. If you send a bad command, it will hang and eventually timeout with <code>VisaIOError: VI_ERROR_TMO: Timeout expired before operation completed.</code> <p> The API to the oscilloscope is specified in the <a href="http://www.rigolna.com/products/digital-oscilloscopes/ds1000e/ds1052e/#tabs-2">DS1000D/E Programming Guide</a>. If you do any Rigol hacking, you'll definitely want to read this. Make sure you use the right programming guide for your oscilloscope model - other models have slightly different commands that seem plausible, but they will timeout if you try them. <p> <h2>Conclusions</h2> Connecting an oscilloscope to a computer opens up many opportunities for processing the measurement data, and Python is a convenient language to do this. The Long Memory mode is especially useful, since it provides extremely detailed data samples. <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/8967838651041212651' onclick=''> 20 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=8967838651041212651' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=8967838651041212651&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=8967838651041212651&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=8967838651041212651&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=8967838651041212651&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=8967838651041212651&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=8967838651041212651&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/electronics' rel='tag'>electronics</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a>, <a href='http://www.righto.com/search/label/oscilloscope' rel='tag'>oscilloscope</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/afterburner.png' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='2813975442021002809' itemprop='postId'/> <a name='2813975442021002809'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2010/12/64-bit-rc6-codes-arduino-and-xbox.html'>64-bit RC6 codes, Arduino, and Xbox remotes</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-2813975442021002809' itemprop='description articleBody'> <img align="right" alt="" height="333" src="http://static.righto.com/images/afterburner.png" width="250"> I've extended my Arduino IRremote library to support RC6 codes up to 64 bits long. Now your Arduino can control your Xbox by acting as an IR remote control. (The previous version of my library only supported 32 bit codes, so it didn't work with the 36-bit Xbox codes.) Details of the IRremote library are <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">here</a>. <p> Note: I don't actually have an Xbox to test this code with, so please let me know if the code works for you. <h4>Download</h4> This code is in my "experimental" branch since I'd like to get some testing before releasing it to the world. To use it: <ul> <li>Download the IRremote library zip file from GitHub from the <a href="https://github.com/shirriff/Arduino-IRremote/zipball/experimental">Arduino-IRremote experimental</a> branch. <li>Unzip the download <li>Move/rename the shirriff-Arduino-IRremote-nnnn directory to arduino-000nn/libraries/IRremote. </ul> <h4>Sending an Xbox code</h4> The following program simply turns the Xbox on, waits 10 seconds, turns it off, and repeats. <pre class="code"> #include <IRremote.h> IRsend irsend; unsigned long long OnOff = 0xc800f740cLL; int toggle = 0; void sendOnOff() { if (toggle == 0) { irsend.sendRC6(OnOff, 36); } else { irsend.sendRC6(OnOff ^ 0x8000, 36); } toggle = 1 - toggle; } void setup() {} void loop() { delay(10000); // Wait 10 seconds sendOnOff(); // Send power signal } </pre> The first important thing to note is that the On/Off code is "unsigned long long", and the associated constant ends in "LL" to indicate that it is a long long. Because a regular long is only 32 bits, a 64-bit long long must be used to hold the 64 bit code. If you try using a regular long, you'll lose the top 4 bits ("C") from the code. <p> The second thing to notice is the toggle bit (which is explained in more detail below). Every time you send a RC5 or RC6 code, you must flip the toggle bit. Otherwise the receiver will ignore the code. If you want to send the code multiple times for reliability, don't flip the toggle bit until you're done. <h4>Receiving an Xbox code</h4> The following code will print a message on the serial console if it receives an Xbox power code. It will also dump the received value. <pre class="code"> #include <IRremote.h> int RECV_PIN = 11; IRrecv irrecv(RECV_PIN); decode_results results; void setup() { Serial.begin(9600); irrecv.enableIRIn(); // Start the receiver } void loop() { if (irrecv.decode(&results)) { if ((results.value & ~0x8000LL) == 0xc800f740cLL) { Serial.println("Got an OnOff code"); } Serial.println(results.value >> 32, HEX); Serial.println(results.value, HEX); irrecv.resume(); // Receive the next value } } </pre> Two things to note in the above code. First, the received value is anded with ~0x8000LL; this clears out the toggle bit. Second, Serial.println is called twice, first to print the top 32 bits, and second to print the bottom 32 bits. <p> The output when sent power codes multiple times is: <pre> Got an OnOff code C 800FF40C Got an OnOff code C 800F740C Got an OnOff code C ... </pre> Note that the received value is split between the two Serial.println calls. Also note that the output oscillates between ...F740C and ...FF40C as the sender flips the toggle bit. This is why the toggle bit must be cleared when looking for a particular value. <p> The IRremote/IRrecvDump example code has also been extended to display values up to 64 bits, and can be used for testing. <h4>A quick description of RC6 codes</h4> RC6 codes are somewhat more complicated than the usual IR code. They come in 20 or 36 bit varieties (that I know of). The code consists of a leader pulse, a start bit, and then the 20 (or 36) data bits. A 0 bit is sent as a space (off) followed by a mark (on), while a 1 bit is sent as a mark (on) followed by a space (off). <p> The first complication is the fourth data bit sent (called a trailer bit for some reason), is twice as long as the rest of the bits. The IRremote library handles this transparently. <p> The second complication is RC5 and RC6 codes use a "toggle bit" to distinguish between a button that is held down and a button that is pressed twice. While a button is held down, a code is sent. When the button is released and pressed a second time, a new code with one bit flipped is sent. On the third press, the original code is sent. When sending with the IRremote library, you must keep track of the toggle bit and flip it each time you send. When receiving with the IRremote library, you will receive one of two different codes, so you must clear out the toggle bit. (I would like the library to handle this transparently, but I haven't figured out a good way to do it.) <p> For details of the RC6 encoding with diagrams and timings, see <a href="http://www.sbprojects.com/knowledge/ir/rc6.htm">SB projects</a>. <h4>The LIRC database</h4> The <a href="http://lirc.org">LIRC project</a> collects IR codes for many different remotes. If you want to use RC6 codes from LIRC, there a few things to know. A typical code is the <a href="http://lirc.sourceforge.net/remotes/microsoft/Xbox360">Xbox360</a> file, excerpted below: <pre class="code"> begin remote name Microsoft_Xbox360 bits 16 flags RC6|CONST_LENGTH pre_data_bits 21 pre_data 0x37FF0 toggle_bit_mask 0x8000 rc6_mask 0x100000000 begin codes OpenClose 0x8BD7 XboxFancyButton 0x0B9B OnOff 0x8BF3 ... </pre> To use these RC6 code with the Arduino takes a bit of work. First, the codes have been split into 21 bits of pre-data, followed by 16 bits of data. So if you want the OnOff code, you need to concatenate the bits together, to get 37 bits: 0x37ff08bf3. The second factor is the Arduino library provides the first start bit automatically, so you only need to use 36 bits. The third issue is the LIRC files inconveniently have 0 and 1 bits swapped, so you'll need to invert the code. The result is the 36-bit code 0xc800f740c that can be used with the IRremote library. <p> The <i>rc6_mask</i> specifies which bit is the double-wide "trailer" bit, which is the fourth bit sent (both in 20 and 36 bit RC6 codes). The library handles this bit automatically, so you can ignore it. <p> The <i>toggle_bit_mask </i> is important, as it indicates which position needs to be toggled every other transmission. For example, to transmit OnOff you will send 0xc800f740c the first time, but the next time you will need to transmit 0xc800ff40c. <p> More details of the LIRC config file format are at <a href="http://winlirc.sourceforge.net/technicaldetails.html">WinLIRC</a>. <h4>Xbox codes</h4> Based on the LIRC file, the following Xbox codes should work with my library: <style type='text/css'> table.boxed { border-collapse: collapse; border: 1px solid gray; } table.boxed td { padding: 5px; text-align: right; font-family: courier;} col.l { border-left: 1px solid gray } col.r { border-right: 1px solid gray; } </style> <table class="boxed"> <col class="l"> <col class="r"> <col class="l"> <col class="r"> <col class="l"> <col class="r"> <tr><td>OpenClose</td><td>0xc800f7428</td><td>XboxFancyButton</td><td>0xc800ff464</td><td>OnOff</td><td>0xc800f740c</td></tr> <tr><td>Stop</td><td>0xc800ff419</td><td>Pause</td><td>0xc800f7418</td><td>Rewind</td><td>0xc800ff415</td></tr> <tr><td>FastForward</td><td>0xc800f7414</td><td>Prev</td><td>0xc800ff41b</td><td>Next</td><td>0xc800f741a</td></tr> <tr><td>Play</td><td>0xc800ff416</td><td>Display</td><td>0xc800f744f</td><td>Title</td><td>0xc800ff451</td></tr> <tr><td>DVD_Menu</td><td>0xc800f7424</td><td>Back</td><td>0xc800ff423</td><td>Info</td><td>0xc800f740f</td></tr> <tr><td>UpArrow</td><td>0xc800ff41e</td><td>LeftArrow</td><td>0xc800f7420</td><td>RightArrow</td><td>0xc800ff421</td></tr> <tr><td>DownArrow</td><td>0xc800f741f</td><td>OK</td><td>0xc800ff422</td><td>Y</td><td>0xc800f7426</td></tr> <tr><td>X</td><td>0xc800ff468</td><td>A</td><td>0xc800f7466</td><td>B</td><td>0xc800ff425</td></tr> <tr><td>ChUp</td><td>0xc800f7412</td><td>ChDown</td><td>0xc800ff413</td><td>VolDown</td><td>0xc800ff411</td></tr> <tr><td>VolUp</td><td>0xc800ff410</td><td>Mute</td><td>0xc800ff40e</td><td>Start</td><td>0xc800ff40d</td></tr> <tr><td>Play</td><td>0xc800f7416</td><td>Enter</td><td>0xc800ff40b</td><td>Record</td><td>0xc800f7417</td></tr> <tr><td>Clear</td><td>0xc800ff40a</td><td>0</td><td>0xc800f7400</td><td>1</td><td>0xc800f7401</td></tr> <tr><td>2</td><td>0xc800ff402</td><td>3</td><td>0xc800f7403</td><td>4</td><td>0xc800ff404</td></tr> <tr><td>5</td><td>0xc800f7405</td><td>6</td><td>0xc800ff406</td><td>7</td><td>0xc800f7407</td></tr> <tr><td>8</td><td>0xc800ff408</td><td>9</td><td>0xc800f7409</td><td>100</td><td>0xc800ff41d</td></tr> <tr><td>Reload</td><td>0xc800f741c</td><td></td><td></td><td></td><td></td></tr> </table> <h4>Key points for debugging</h4> The following are the main things to remember when dealing with 36-bit RC6 codes: <ul> <li>Any 36-bit hex values must start with "0x" and end with "LL". If you get the error "integer constant is too large for 'long' type", you probably forgot the LL. <li>You must use "long long" or "unsigned long long" to hold 36-bit values. <li>Serial.print will not properly print 36-bit values; it will only print the lower 32 bits. <li>You must flip the toggle bit every other time when you send a RC6 code, or the receiver will ignore your code. <li>You will receive two different values for each button depending if the sender has flipped the toggle bit or not. </ul> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/2813975442021002809' onclick=''> 23 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=2813975442021002809' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=2813975442021002809&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=2813975442021002809&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=2813975442021002809&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=2813975442021002809&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=2813975442021002809&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=2813975442021002809&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/lego-remote.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='6871228182188003233' itemprop='postId'/> <a name='6871228182188003233'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2010/11/control-your-mouse-with-ir-remote.html'>Control your mouse with an IR remote</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-6871228182188003233' itemprop='description articleBody'> <img align="right" height="248" src="http://static.righto.com/images/lego-remote.jpg" width="350"> You can use an IR remote to control your computer's keyboard and mouse by using my Arduino <a href="http://www.righto.com/2010/11/irremote-library-now-runs-on-teensy.html">IR remote library</a> and a small microcontroller board called the <a href="http://www.pjrc.com/teensy/index.html">Teensy</a>. By pushing the buttons on your IR remote, you can steer the cursor around the screen, click on things, and enter digits. The key is the Teensy can simulate a USB keyboard and mouse, and provide input to your computer. <h3>How to do this</h3> I built a simple sketch that uses the remote from my DVD player to move and click the mouse, enter digits, or page up or down. Follow these steps: <ul> <li> The hardware is nearly trivial. Connect a IR detector to the Teensy: detector pin 1 to Teensy input 11, detector pin 2 to ground, and detector pin 3 to +5 volts. <li> Install the <a href="http://www.righto.com/2010/11/irremote-library-now-runs-on-teensy.html">latest version of my IR remote library</a>, which has support for the Teensy. <li> Download the <a href="/files/IRusb.pde">IRusb sketch</a>. <li> In the Arduino IDE, select <i>Tools > Board: Teensy 2.0</i> and select <i>Tools > USB Type: Keyboard and Mouse</i>. <li>Modify the sketch to match the codes from your remote. Look at the serial console as you push the buttons on your remote, and modify the sketch accordingly. (This is explained in more detail below.) </ul> To reiterate, this sketch won't work on a standard Arduino; you need to use a Teensy. <h3>How the sketch works</h3> The software is straightforward because the Teensy has USB support built in. First, the IR library is initialized to receive IR codes on pin 11: <pre class="code"> #include <IRremote.h> int RECV_PIN = 11; IRrecv irrecv(RECV_PIN); decode_results results; void setup() { irrecv.enableIRIn(); // Start the receiver Serial.begin(9600); } </pre> Next, the <i>decode</i> method is called to receive IR codes. If the hex value for the received code corresponds to a desired button, a USB mouse or keyboard command is sent. If a code is not recognized, it is printed on the serial port. Finally, after receiving a code, the <i>resume</i> method is called to resume receiving IR codes. <pre class="code"> int step = 1; void loop() { if (irrecv.decode(&results)) { switch (results.value) { case 0x9eb92: // Sony up Mouse.move(0, -step); // up break; case 0x5eb92: // Sony down Mouse.move(0, step); // down break; ... case 0x90b92: // Sony 0 Keyboard.print("0"); break; ... default: Serial.print("Received 0x"); Serial.println(results.value, HEX); break; } irrecv.resume(); // Resume decoding (necessary!) } } </pre> You may wonder where the codes such as 0x9eb92 come from. These values are for my Sony DVD remote, so chances are they won't work for your remote. To get the values for your remote, look at the serial console as you press the desired buttons. As long as you have a supported remote type (NEC, Sony, RC5/6), you'll get the hex values to put into the sketch. Simply copy the hex values into the sketch, and perform the desired action. <p> There are a few details to note. If your remote uses the RC5 or RC6 format, there are actually two different codes assigned to each button, and the remote alternates between them. Push the button twice to see if you'll need to use two different codes. If you want to send a non-ASCII keyboard code, such as Page Down, you'll need to use a slightly more complex set of commands (<a href="http://www.pjrc.com/teensy/td_keyboard.html">documentation</a>). For example, the following code sends a Page UP if it receives a RC5 Volume Up from the remote. Note that there are two codes for volume up, and note that <i>KEY_PAGE_UP</i> is sent, followed by 0 (no key). <pre class="code"> case 0x10: // RC5 vol up case 0x810: Keyboard.set_key1(KEY_PAGE_UP); Keyboard.send_now(); Keyboard.set_key1(0); Keyboard.send_now(); break; </pre> <h3>Improvements</h3> <p> My first implementation of the sketch as described above was very easy, but there were a couple displeasing things. The first problem was the mouse movement was either very slow (with a small step size) or too jerky (with a large step size). Second, if you press a number on the remote, the keyboard input rapidly repeats because the IR remote repeatedly sends the IR code, so you end up with "111111" when you just wanted "1". <p> The solution to the mouse movement is to implement acceleration - as you hold the button down, the mouse moves faster. This was straightforward to implement. The sketch checks if the button code was received within 200ms of the previous code. If so, the sketch speeds up the mouse movement by increasing the step size. Otherwise it resets the step size to 1. The result is that tapping the button gives you fine control by moving the mouse a little bit, while holding the button down lets you zip across the screen: <pre class="code"> if (millis() - lastTime > GAP) { step = 1; } else if (step > 20) { step += 1; } </pre> Similarly, to prevent the keyboard action from repeating, we only output keypresses if the press is more then 200ms after the previous. This results in a single keyboard action no matter how long a button is pressed down. The same thing is done to prevent multiple mouse clicks. <pre class="code"> if (millis() - lastTime > GAP) { switch (results.value) { case 0xd0b92: Mouse.click(); break; case 0x90b92: Keyboard.print("0"); break; ... </pre> <p> Now you can control your PC from across the room by using your remote. Thanks to Paul Stoffregen of <a href="http://www.pjrc.com/">PJRC</a> for porting my IR remote library to the Teensy and sending me a Teensy for testing. <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/6871228182188003233' onclick=''> 5 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=6871228182188003233' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=6871228182188003233&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6871228182188003233&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6871228182188003233&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6871228182188003233&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6871228182188003233&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6871228182188003233&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/lego-teensy.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='5496820013144250309' itemprop='postId'/> <a name='5496820013144250309'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2010/11/irremote-library-now-runs-on-teensy.html'>IRremote library now runs on the Teensy, Arduino Mega, and Sanguino</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-5496820013144250309' itemprop='description articleBody'> <img align="right" alt="" height="248" src="http://static.righto.com/images/lego-teensy.jpg" width="350"> Thanks to Paul Stoffregen of <a href="http://www.pjrc.com/">PJRC</a>, my <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">Arduino IR remote library</a> now runs on a bunch of different platforms, including the <a href="http://www.pjrc.com/teensy/">Teensy</a>, <a href="http://arduino.cc/en/Main/ArduinoBoardMega">Arduino Mega</a>, and <a href="http://sanguino.cc">Sanguino</a>. Paul has details <a href="http://www.pjrc.com/teensy/td_libs_IRremote.html">here</a>, along with documentation on the library that I admit is better than mine. <p> I used my new <a href="http://www.righto.com/2010/11/testing-arduino-ir-remote-library.html">IRremote test setup</a> to verify that the library works fine on the Teensy. I haven't tested my library on the other platforms because I don't have the hardware so let me know if you have success or run into problems. <h3>Download</h3> The latest version of the IRremote library with the multi-platform improvements is on <a href="https://github.com/shirriff/Arduino-IRremote">GitHub</a>. To download and install the library: <ul> <li>Download the <a href="https://github.com/shirriff/Arduino-IRremote/zipball/master">IRremote library</a> zip file from GitHub. <li>Unzip the download <li>Move/rename the <i>shirriff-Arduino-IRremote-nnnn</i> directory to <i>arduino-000nn/libraries/IRremote</i>. </ul> <p> Thanks again to Paul for adding this major improvement to my library and sending me a Teensy to test it out. You can see from the picture that the Teensy provides functionality similar to the Arduino in a much smaller package that is also breadboard-compatible; I give it a thumbs-up. <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/5496820013144250309' onclick=''> 22 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=5496820013144250309' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=5496820013144250309&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5496820013144250309&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5496820013144250309&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5496820013144250309&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5496820013144250309&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5496820013144250309&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/test2-lego.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='6076104597725540166' itemprop='postId'/> <a name='6076104597725540166'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2010/11/testing-arduino-ir-remote-library.html'>Testing the Arduino IR remote library</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-6076104597725540166' itemprop='description articleBody'> <img align="right" alt="" height="265" src="http://static.righto.com/images/test2-lego.jpg" width="350"> I wrote an IR remote library for the Arduino (<a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">details</a>) that has turned out to be popular. I want to make sure I don't break things as I improve the library, so I've created a test suite that uses a pair of Arduinos: one sends data and the other receives data. The receiver verifies the data, providing an end-to-end test that the library is working properly. <h3>Overview of the test</h3> The first Arudino repeatedly sends a bunch of IR codes to the second Arduino. The second Arduino verifies that the received code is what is expected. If all is well, the second Arduino flashes the LED for each successful code. If there is an error, the second Arudino's LED illuminates for 5 seconds. The test cycle repeats forever. Debugging information is output to the second Arduino's serial port, which is helpful for tracking down the cause of errors. <h3>Hardware setup</h3> The test hardware is pretty simple: one Arduino transmits, and one Arduino receives. An IR LED is connected to pin 3 of the first Arduino to send the IR code. An IR detector is connected to pin 11 of the second Arduino to receive the IR code. A LED is connected to pin 3 of the second Arduino to provide the test status. <br> <img alt="schematic of test setup" height="292" src="http://static.righto.com/images/test2-schematic.png" width="494"> <h3>Details of the test software</h3> One interesting feature of this test is the same sketch runs on the sending Arduino and the receiving Arduino. The test looks for an input on pin 11 to decide if it is the receiver: <pre class="code"> void setup() { Serial.begin(9600); // Check RECV_PIN to decide if we're RECEIVER or SENDER if (digitalRead(RECV_PIN) == HIGH) { mode = RECEIVER; irrecv.enableIRIn(); pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); Serial.println("Receiver mode"); } else { mode = SENDER; Serial.println("Sender mode"); } } </pre> Another interesting feature is the test suite is expressed very simply: <pre class="code"> test("SONY4", SONY, 0x12345, 20); test("SONY5", SONY, 0x00000, 20); test("SONY6", SONY, 0xfffff, 20); test("NEC1", NEC, 0x12345678, 32); test("NEC2", NEC, 0x00000000, 32); test("NEC3", NEC, 0xffffffff, 32); ... </pre> Each test call has a debugging string, the type of code to send/receive, the value to send/receive, and the number of bits. <p> On the sender, the <i>test</i>method sends the code, while on the receiver, the method verifies that the proper code is received. The SENDER code calls the appropriate send method based on the type, and then delays before the next test. The RECEIVER code waits for a code. If it's correct, it flashes the LED. Otherwise, it sets the state to ERROR. <pre class="code"> void test(char *label, int type, unsigned long value, int bits) { if (mode == SENDER) { Serial.println(label); if (type == NEC) { irsend.sendNEC(value, bits); } else if (type == SONY) { ... } delay(200); } else if (mode == RECEIVER) { irrecv.resume(); // Receive the next value unsigned long max_time = millis() + 30000; // Wait for decode or timeout while (!irrecv.decode(&results)) { if (millis() > max_time) { mode = ERROR; // timeout return; } } if (type == results.decode_type && value == results.value && bits == results.bits) { // flash LED } else { mode = ERROR; } } } </pre> The trickiest part of the code is synchronizing the sender and the receiver. This happens in <i>loop()</i>. The receiver waits for 1 second without any transmission, while the sender pauses for 2 seconds after each time through the tests. Thus, the receiver will wait while the sender is running through tests, and then will start listening just before the sender starts the next cycle of tests. One other thing to point out is if there is an error, the receiver will skip through all the remaining tests, light the LED to indicate the error, and then will wait to sync up again. This avoids the problem of one bad test getting the receiver permanently out of sync; the receiver is able to re-sync and continue successfully after a failed test. <pre class="code"> void loop() { if (mode == SENDER) { delay(2000); // Delay for more than gap to give receiver a better chance to sync. } else if (mode == RECEIVER) { waitForGap(1000); } else if (mode == ERROR) { // Light up for 5 seconds for error mode = RECEIVER; // Try again return; } </pre> The test also includes some raw mode tests. These are a bit more complicated, since I want to test the various combinations of sending and receiving in raw mode. <h3>Download and running</h3> I'm gradually moving my development to GitHub at <a href="https://github.com/shirriff/Arduino-IRremote">https://github.com/shirriff/Arduino-IRremote</a>. <p> The code fragments above have been slightly abbreviated; the full code for the test sketch is <a href="https://github.com/shirriff/Arduino-IRremote/raw/master/examples/IRtest2/IRtest2.pde">here</a>. <p> To download the library and try out the two-Arduino test: <ul> <li>Download the <a href="https://github.com/shirriff/Arduino-IRremote/zipball/master">IRremote library</a> zip file. <li>Unzip the download <li>Move/rename the <i>shirriff-Arduino-IRremote-nnnn</i> directory to <i>arduino-000nn/libraries/IRremote</i>. The test sketch is in <i>examples/IRtest2</i>. </ul> <p> To run the test, install the sketch on two Arduinos. The test should automatically start running. Note that it is a bit tricky to use two Arduinos at once. They will probably get assigned different serial ports, and you can switch ports using the Tools menu. If you get confused, you can plug one Arduino in at a time, and then you can be sure about which one is getting installed. <p> My plan is to do more development on the library, now that I have a reasonably solid test suite and I can be more confident that I don't break things. Let me know if there are specific features you'd like. <p> Thanks go to <a href="http://sparkfun.com">SparkFun</a> for giving me the second Arduino that made this test possible. <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/6076104597725540166' onclick=''> 11 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=6076104597725540166' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=6076104597725540166&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6076104597725540166&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6076104597725540166&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6076104597725540166&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6076104597725540166&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=6076104597725540166&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/tvb-lego.png' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='4446448485025928609' itemprop='postId'/> <a name='4446448485025928609'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2010/11/improved-arduino-tv-b-gone.html'>Improved Arduino TV-B-Gone</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-4446448485025928609' itemprop='description articleBody'> <img align="right" alt="" height="266" src="http://static.righto.com/images/tvb-lego.png" style="padding-left: 10px" width="350"> <div style="background-color:#ddd; border: none; padding: 5px; margin-right: 10px;"> Oct 2016: An updated version of the code is on <a href="https://github.com/shirriff/Arduino-TV-B-Gone">github</a>, thanks to <a href="http://www.electricrcaircraftguy.com/">Gabriel Staples</a>. </div> <p> The <a href="http://www.tvbgone.com/cfe_tvbg_main.php">TV-B-Gone</a> is a tiny infrared remote that can turn off almost any TV. A while ago, I ported the TV-B-Gone software to the Arduino; for details on the port and how it works see my previous post on the <a href="http://www.righto.com/2009/12/tv-b-gone-for-arduino.html">Arduino TV-B-Gone</a>. <p> Mitch Altman, the inventor of the TV-B-Gone, made some improvements to the code for a weekly <a href="https://www.noisebridge.net/wiki/Arduino_tvbgone_for_Newbies_Workshop">TV-B-Gone constructing workshop</a> in San Francisco at Noisebridge. If you're in the San Francisco area and are interested in the TV-B-Gone, you might want to check it out. <p> The main bug fix in the new version is the European codes will now work (if you ground pin 5). (The problem was a bunch of #ifdefs to fit the codes into the ATtiny's limited memory; taking out the #ifdefs fixed the problems.) Pressing the trigger button during transmission will now restart the codes. The delay between codes was increased, which should make transmission more reliable. The Arduino's processor will now sleep when not transmitting (thanks to <a href="http://www.ka1kjz.com/?p=561">ka1kjz</a>). (Unfortunately, the rest of the Arduino components are still draining power, so sleep mode will be more useful with stripped-down Arduino variants.) <p> Important: the pins have been changed around in the new version (to avoid conflicts with the serial port). Pin 2 is now the trigger switch, Pin 3 is the IR output, and Pin 5 is grounded if you want European codes. If you built an Arduino TV-B-Gone before and want to use the new code, make sure you connect to the right pins. <p>Here's Mitch Altman's schematic for the Arduino TV-B-Gone (click for larger): <a href="/images/Arduino TV-B-Gone schematic.pdf"><img alt="Arduino TV-B-Gone schematic" height="594" src="http://static.righto.com/images/tv-b-gone-schematic.png" width="500"></a> <p> To build the Arduino TV-B-Gone, follow the above schematic and download the sketch from <a href="https://github.com/shirriff/Arduino-TV-B-Gone">github</a>. My previous post on the <a href="http://www.righto.com/2009/12/tv-b-gone-for-arduino.html">Arduino TV-B-Gone</a> has more information on wiring it up, if you need it. <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/4446448485025928609' onclick=''> 61 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=4446448485025928609' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=4446448485025928609&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4446448485025928609&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4446448485025928609&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4446448485025928609&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4446448485025928609&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4446448485025928609&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/sony-ir.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='5993882865203908388' itemprop='postId'/> <a name='5993882865203908388'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2010/03/understanding-sony-ir-remote-codes-lirc.html'>Understanding Sony IR remote codes, LIRC files, and the Arduino library</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-5993882865203908388' itemprop='description articleBody'> This article describes how to understand Sony IR codes and how to get them from the LIRC files. The article is intended to describe codes for use with my <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">Arduino infrared remote library</a>, but the information should be generally applicable. This article is aimed at the hardware hacker and assumes that you are familiar with binary and hexadecimal, so be warned :-) <p> One key point of this article is that there are three different ways to interpret the same IR signal and turn it into a hex code. Understanding these three ways will allow you to get codes from different sources and understand them correctly. <h3>The IR transmission of the code</h3> When you press a button on a Sony remote control, an infrared signal is transmitted. This transmission consists of a 40kHz signal which is turned on and off in a particular pattern. Different buttons correspond to different codes, which cause the signal to be turned on and off in different patterns. <p> The following waveform shows the IR code transmitted for STOP on my Sony CD remote control (RM-DC335). When the signal is high, a 40 kHz IR signal is transmitted, and when the signal is low, nothing is transmitted. In other words, the signal is actually rapidly turning on and off when it appears to be on in the figure. (The IR receiver demodulated the signal, so you don't see the 40 kHz transitions.) <br> <img alt="IR transmission for a Sony remote control" height="72" src="http://static.righto.com/images/sony-ir.jpg" width="600"> <br> A Sony IR signal starts with 2400 microseconds on and 600 microseconds off; that's the first wide pulse. A "1" bit is transmitted with 1200 microseconds on and 600 microseconds off, while a "0" bit is transmitted with 600 microseconds on and 600 microseconds off. (This encoding is also called SIRC or SIRCS encoding.) <p> You may notice the "on" parts of the waveform appear wider than the "off" parts, even when both are supposed to be 600 microseconds. This is a result of the IR receiver, which switches on faster than switching off. <p> The above waveform represents one transmission of a 12-bit code. This transmission is normally repeated as long as the button is held down, and a minimum of three times. Each transmission starts 45ms after the previous one started. The Sony protocol also supports 15 and 20 bit codes, which are the same as above except with more bits. <p> For more information on the low-level transmission of Sony codes, see <a href="https://www.sbprojects.net/knowledge/ir/sirc.php">sbprojects.net</a>. <h3>Three ways to interpret the codes</h3> The Sony encoding seems straightforward, but there are several different ways the signal can be interpreted. I will call these <i>official decoding</i>, <i>bit decoding</i>, and <i>bit-1 decoding</i>. Different sources use any of these three, which can cause confusion. I will explain these three decodings, using the previous waveform as an example. <h4>Official decoding</h4> <img alt="Official Sony decoding" height="104" src="http://static.righto.com/images/sony-official.jpg" width="600"> <br> The "official" Sony protocol views the 12-bit code as 7 command bits and 5 address or device bits, transmitted least-significant-bit first (i.e. "backwards"). The device bits specify the type of device receiving the code, and the command bits specify a particular command for this device. In this example, the device bits (yellow) are 10001 when read right-to-left, which is 17 decimal. The command bits (blue) are 0111000 when read right-to-left, which is 56 decimal. The device value 17 corresponds to a CD player, and the command 56 corresponds to the STOP command (<a href="http://www.hifi-remote.com/sony/Sony_cd.htm">details</a>). <p> Sony 15 bit codes are similar, with 7 command bits and 8 device bits. Sony 20 bit codes have 7 command bits, 5 device bits, and 8 extended device bits. <h4>Bit decoding</h4> <img alt="Decoding Sony IR code as a sequence of bits" height="104" src="http://static.righto.com/images/sony-bits.jpg" width="600"> <br> Many IR decoders just treat the signal as a sequence of bits, most-significant-bit first. I will call this <i>bit decoding</i>. Applying this interpretation to the above code, the code is interpreted as 0001 1101 0001 binary, or 1d1 hex, or 465 in decimal. Note that the last bit doesn't really consist of 1200 microseonds on and 600 microseconds off; it consists of 1200 microseconds on followed by a lot of time off. In other words, the transmission is off for 600 microseconds and then continues to be off until the next code is transmitted. <p> An alternative but equivalent interpretation is to view the code as a 2400 microsecond header, followed by 12 bits, where each bit is off then on (rather than on then off). A "1" bit is 600 microseconds off and 1200 microseconds on, while a "0" bit is 600 microseconds off and 600 microseconds on. This yields the same value as before (232 decimal), but avoids the special handling of the last bit. <br> <img alt="Short one bit decoding" height="104" src="http://static.righto.com/images/sony-bits2.jpg" width="600"> <h4>Bit-1 decoding</h4> <img alt="Short one bit decoding" height="104" src="http://static.righto.com/images/sony-short.jpg" width="600"> <br> Many IR decoders drop the last bit, which I will call <i>bit-1 decoding</i>. Because the last bit doesn't end nicely with 600 microseconds off, some IR decoding algorithms treat the signal as 11 bits of data, ending with 600 microseconds on as a trailer. In this interpretation, the above code is 000 1110 1000 binary, or 0e8 hex, or 232 decimal. (Note that doubling this value and adding 1 yields the previous decoding of 465.) <h4>Discussion</h4> <p> Is the code really 17/44 or 465 or 232? The official decoding is "right" in the sense that it is what the manufacturer intends. In addition, it reveals the internal structure of the code and the codes make more sense. For instance, the buttons 1-9 have consecutive codes with the official decoding, but not with the others. The other decodings are fine to use as long as you're consistent; the main thing is to understand that different sources use different decodings. My Arduino library uses the second <i>bit decoding</i> interpretation. The different decodings can be converted from one form to another with binary arithmetic. <h3>Getting codes from a remote</h3> Probably the easiest way to get the codes for your device is to use your existing remote control and see what codes it transmits. You can use my <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">Arduino IR library</a> to do the decoding, with the IRrecvDump demo program. Take a 3-pin IR decoder, hook it up to an Arduino, and then you can read the values for each button press on the serial port. <p> Alternatively, you can look at the transmitted codes with an oscilloscope. For the diagrams above, I used an IR receiver module connected to two resistors (to drop the voltage), connected to the line input of my PC. I used the <a href="http://www.zeitnitz.de/Christian/scope_en">Zeitnitz Soundcard Oscilloscope</a> program to display the signal. This lets you see exactly what is being transmitted, but you will need to stare at the screen, write down a bunch of 0's and 1's, and convert the binary value to get your codes. <h3>Getting codes from LIRC files</h3> The best source for IR codes that I've found is the Linux Infrared Remote Control project (<a href="http://www.lirc.org">lirc.org</a>), which has a <a href="http://lirc.sourceforge.net/remotes/">huge collection</a> of config files for various remotes. (LIRC also includes a large collection of device drivers for many types of IR input/output hardware, and a software library.) <p> The LIRC config file format is documented at <a href="http://winlirc.sourceforge.net/technicaldetails.html">WinLIRC</a>, but I will walk through some examples. <h4>Bit decoding</h4> The <a href="http://lirc.sourceforge.net/remotes/sony/RM-S530">RM-S530</a> LIRC file treats the codes as 12 bits long, using what I call <i>bit decoding</i>: <pre> begin remote name Sony bits 12 flags SPACE_ENC|CONST_LENGTH eps 30 aeps 100 header 2470 557 one 1243 556 zero 644 556 gap 45076 min_repeat 2 toggle_bit 0 begin codes sleep 0x0000000000000061 cd_stop 0x00000000000001D1 ... </pre> This file indicates that each entry is 12 bits long. A header consists of on for 2470 microseconds and off for 557 microseconds. A one bit consists of on for 1243 microseconds and off for 556 microseconds. A zero bit consists of on for 644 microseconds and off for 556 microseconds. Codes are repeated a minimum of 2 more times, with a gap of 45076 microseconds from start to start as the codes are constant length (CONST_LENGTH). <p> You may be wondering why these time values don't match the official values of 2400, 1200, and 600 microseconds. First, the LIRC data is generally measured from actual remotes, so the real-world timings don't quite match the theory. Second, IR sensors have some lag in detecting "on" and "off", and they typically stretch out the "on" time by ~100 microseconds, shortening the "off" time equally. <p> The LIRC file then lists the hex code associated with each button. For example the CD STOP code is hex 1D1, which is the same value as described earlier. <h4>Bit-1 decoding</h4> The LIRC file for the <a href="http://lirc.sourceforge.net/remotes/sony/RM-D302">RM-D302</a> remote treats the codes as 11 bits and a trailing pulse. This is what I call the <i>bit-1 decoding</i>: <pre> begin remote name RM-D302 bits 11 flags SPACE_ENC|CONST_LENGTH eps 30 aeps 100 header 2367 638 one 1166 637 zero 565 637 ptrail 1166 gap 45101 min_repeat 2 toggle_bit 0 begin codes cd_stop 0x00000000000000E8 </pre> The key differences with the previous file are the ptrail field, indicating a trailing pulse of 1166 microseconds; and the bit count of 11 instead of 12. Note that the code value is different from the first file, even thought the IR transmission is exactly the same. The hex code 0E8 is the same as described earlier under <i>bit-1 decoding</i>. <h4>Pre_data and post_data bits</h4> Some LIRC files break apart the codes into constant pre_data bits, the code itself, and constant post_data bits. For instance, the file for my <a href="http://lirc.sourceforge.net/remotes/sony/RM-D335">RM-D335 remote</a>: <pre> begin remote name SONY bits 7 flags SPACE_ENC eps 20 aeps 0 header 2563 520 one 1274 520 zero 671 520 ptrail 1274 post_data_bits 4 post_data 0x8 gap 25040 min_repeat 2 begin codes CONTINUE 0x000000000000005C ... STOP 0x000000000000000E ... </pre> This file indicates that each code entry is 7 bits long, but there are also 4 post data bits. This means that after transmitting the 7 bits for the code, 4 additional bits are transmitted with the "post data" hex value 0x8, i.e. 1000 binary. <p> Putting this together the STOP button has the hex value 0E, which corresponds to the seven bits 000 1110. This is followed by four post data bits 1000, so the total transmission is the eleven bits 000 1110 1000, which is 0E8 hex, the same as before for the <i>bit-1 decoding</i>. <p> One more thing to notice in this LIRC file is it doesn't have the CONST_LENGTH flag, and the gap is 25ms instead of 45ms. This indicates the gap is from the end of one code to the start of the next, rather than from the start of one code to the start of the next. Specifying a gap between codes isn't how Sony codes are actually defined, it's close enough. <h4>LIRC summary</h4> Note that these LIRC files all indicate exactly the same IR transmission; they just interpret it differently. The first file defines the STOP code as 1D1, the second as E8, and the third as 0E. <p> What does this mean to you? If you want to get a Sony code from a LIRC file and use it with the Arduino library, you need to have a 12 bit (or 15 or 20 bit) code to pass to the library (<i>bit decoding</i>). Look up the code in the file and extract the specified number of bits. If there are any pre_data or post_data bits, append them as appropriate. If the result is one bit short and the LIRC file has a ptrail value, append a 1 bit on the end to convert from <i>bit-1 decoding</i> to <i>bit decoding</i>. Convert the result to hex and you should have the proper code for your device, that can be used with the Arduino library. <h3>Getting codes from hifi-remote.com</h3> The most detailed site I've found on Sony codes specifically is <a href="http://www.hifi-remote.com/sony">hifi-remote.com/sony</a>. An interesting thing about this site is it analyzes the structure of the codes. While the LIRC files just list the codes, the hifi-remote site tries to explain why the codes are set up the way they are. <p> Note that this site expresses codes in Sony format, i.e. most-significant-bit first, and separating the device part of the code from the command part of the code. Also for a 20-bit Sony code, the 13 bit device code is expressed as a 5 bit value and an 8 bit value separated by a period. As a result, you may need to do some binary conversion and reverse the bits to use these codes. <p> To work through an example, I can look up the data for a <a href="http://www.hifi-remote.com/sony/Sony_cd.htm">Sony CD</a>. There are multiple device codes, but assume for now I know my device code is 17. The table gives the code 56 for STOP. Convert 56 to the 7 bit binary value 0111000 and reverse it to get 0001110. Convert 17 to the 5 bit binary value 10001 and reverse it to get 10001. Put these together to et 000111010001, which is 1D1 hex, as before. <p> To work through a 20-bit example, if I have a <a href="http://www.hifi-remote.com/sony/Sony_vdcombo.htm"> Sony VCR/DVD Combo</a> with a device code of 26.83, the site tells me that the code for "power" is 21. Convert 21 to a 7 bit binary value, 26 to a 5 bit binary value, and 83 to a 8 bit binary value. Then reverse and concatenate the bits: binary 1010100 + 01011 + 11001010, which is a8bca in hex. To confirm, the <a href="http://lirc.sourceforge.net/remotes/sony/RMT-V501A">RMT-V501A</a> LIRC file lists power as A8B with post_data of CA. <p> To use this site, you pretty much have to know the device code for your device already. To find that, obtain a code for your device (e.g. from your existing remote or from LIRC), split out and reverse the appropriate bits, and look up the device code on the site. Alternatively, there are only a few different device codes for a particular type of device, so you can just try them all and see what works. <p> This site also has information on "discrete codes". To understand discrete codes, consider the power button on a remote that toggles between "on" and "off". This may be inconvenient for automated control, since without knowing the current state, you don't know if sending a code will turn the device on or off. The solution is the "discrete code", which provides separate "on" and "off" codes. Discrete codes may also be provided for operations such as selecting an input or mode. Since these codes aren't on the remote, they are difficult to obtain. <h3>Other sites</h3> <p> Additional config files are available at <a href="http://irremote.psiloc.com">irremote.psiloc.com</a>. These are in LIRC format, but translated to XML. The site <a href="http://www.remotecentral.com/">remotecentral.com</a> has a ton of information on remotes, but mostly expressed in proprietary formats. <h3>Conclusion</h3> Hopefully this will clear up some of the confusion around Sony remote codes, without adding additional confusion :-) <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/5993882865203908388' onclick=''> 30 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=5993882865203908388' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=5993882865203908388&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5993882865203908388&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5993882865203908388&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5993882865203908388&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5993882865203908388&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5993882865203908388&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/break-detector.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='4273537437022776299' itemprop='postId'/> <a name='4273537437022776299'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2010/03/detecting-ir-beam-break-with-arduino-ir.html'>Detecting an IR Beam Break with the Arduino IR Library</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-4273537437022776299' itemprop='description articleBody'> One reader asked how to use my <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">Arduino Infrared Library</a> to detect breakage of an IR beam. The answer was too long for the comments section, so I've extended into a blog post. One straightforward way is to use the library to modulate an IR LED at 38kHz, and use a standard IR detector module to detect the signal. The output from the module can be simply read as a digital input. <p> Here is a simple sketch to do that. The IR LED is connected to pin 3 through a 100 ohm resistor, the detector is connected to pin 2, and a status LED is connected to pin 13 (if your Arduino board doesn't have it already.) To create the modulated output, simply call <code>irsend.enableIROut(38);</code> to set the PWM to 38kHz, and then <code>irsend.mark(0)</code> to send a mark (i.e. turn the output on). The loop simply reads the input from the detector, inverts it (since the detector is active-low), and writes it to the status LED. <pre class="code"> #include <IRremote.h> #define PIN_IR 3 #define PIN_DETECT 2 #define PIN_STATUS 13 IRsend irsend; void setup() { pinMode(PIN_DETECT, INPUT); pinMode(PIN_STATUS, OUTPUT); irsend.enableIROut(38); irsend.mark(0); } void loop() { digitalWrite(PIN_STATUS, !digitalRead(PIN_DETECT)); } </pre> You should see the pin 13 LED light up when the IR receiver detects an infrared signal, and go dark when the receiver does not detect an infrared signal. The circuit is basically trivial, but there's a <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">schematic</a> at my original article if you need one. The following picture shows the detector setup. Note the illuminated status LED. <br> <img alt="IR detector circuit" height="624" src="http://static.righto.com/images/break-detector.jpg" width="500"> <br> If the circuit doesn't work, first use a cell phone camera to verify that the infrared LED is lit. If the LED is not lit, try reversing it. Here's my cellphone's view of the illuminated LED: <br> <img alt="illuminated infrared LED" height="348"" src="http://static.righto.com/images/break-phone.jpg" widh="500"> <br> Next, point a TV remote control at the detector and make sure the status LED flashes. If the status LED doesn't come on, make sure you wired the detector properly, and connected to input 2 of the Arduino. If the status LED won't turn off when you break the beam, you probably aren't blocking the IR signal well enough. The detector is very sensitive, and IR bounces off many things, so you may need to separate the LED and detector by several feet and make sure you're fully blocking the IR beam. Note that the library assumes you're using a ATmega168/328, so you're on your own if you have a different processor. <p> The tricky part of this is the optics - figuring out how to set up the LED and receiver so the beam gets interrupted when you want it to. Also, you'll probably want to modify the detection logic to do something more interesting than just set the status LED, but that's left as an exercise for the reader :-) <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/4273537437022776299' onclick=''> 37 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=4273537437022776299' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=4273537437022776299&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4273537437022776299&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4273537437022776299&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4273537437022776299&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4273537437022776299&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4273537437022776299&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/traffic-dontwalk.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='4676258495472100746' itemprop='postId'/> <a name='4676258495472100746'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2010/01/dont-walk-controlling-pedestrian-sign.html'>Don't walk! Controlling a pedestrian sign with an Arduino</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-4676258495472100746' itemprop='description articleBody'> My latest project is controlling a pedestrian sign with an Arduino, so it will automatically step through the states of walk, flashing don't walk, and solid don't walk. In addition, I added infrared remote control support so I can use a remote control to turn the sign on and off, set it to a particular state, or start the cycle. <br> <object height="344" width="425"><param name="movie" value="http://www.youtube.com/v/zRBpZHlhGjI&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="https://www.youtube.com/v/zRBpZHlhGjI&hl=en&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object> <h3>The hardware</h3> <img alt="A pedestrian sign controlled by an Arduino." height="327" src="http://static.righto.com/images/traffic-dontwalk.jpg" width="550"> <br> The pedestrian sign is controlled by two relays that switch 120-volt AC on and off; one powers the "walk" part of the sign, and one powers the "don't walk" part. <br> <img alt="The Arduino circuitry." height="300" src="http://static.righto.com/images/traffic-circuit.jpg" width="400"> <br> The Arduino drives the relays through transistors connected to 9-volt supply. Technically the relays are 12-volt relays, but they seem to work with 9 volts. I used one 10A relay, and one 5A relay, just because that's what I had around. <br> <img alt="The relays controlling the sign." height="300" src="http://static.righto.com/images/traffic-relays.jpg" width="400"> <br> Needless to say, 120 volts can be dangerous, both to yourself and to your Arduino. Follow the appropriate precautions. I make no claims about the safety of this circuit. <p> The remote control input uses an IR detector module connected to the Arduino. For details on the IR detection, see the article on my <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">IRremote</a> library. The code section below describes how to modify the code to support different remotes. <br> <img alt="Schematic of the pedestrian sign controller." height="369" src="http://static.righto.com/images/traffic-schematic.png" width="500"> <p> I found the IR detector didn't work super-reliably when the sign was turned on. This was probably due to high-frequency electrical interference since adding some capacitors helped, but the light itself could have been interfering. I probably should have wired up the relay circuit and the IR detector circuit farther apart to minimize interference, as I did when <a href="http://www.righto.com/2009/11/ir-bubbles-controlling-relay-with.html">controlling a DC motor</a>. <h3>Inside the pedestrian sign</h3> You may be curious about what's inside a pedestrian sign. What I have is the lighting unit; this goes inside the metal case that you see attached to a traffic pole. (In case you're worried, I didn't steal this from an intersection. I got it on ebay from some city that was replacing their units with more efficient LED units.) <p> Inside the signal are two neon tubes, roughly the shape of the hand and the pedestrian; generating red and white light respectively. I use "neon tube" in the generic sense; I don't know what gas is actually inside. Note that the tubes are not colored and the cover is clear; the red color is entirely from the gas discharge. <br> <img alt="The neon tubes the pedestrian sign" height="300" src="http://static.righto.com/images/traffic-sign-internal.jpg" width="400"> <br> Beneath the tubes are two high-voltage driver circuits, one for each tube. Each driver circuit runs off 120V AC and has an oscillator (using a LM2903 comparator) driving a flyback transformer through a power transistor (under the board). This generates multi-kilovolts to drive the tubes. Note at the far left the standoffs that keep the output wire an inch above the circuit board due to the high voltage. Needless to say, I stay away from the circuitry while it is operating. Each driver board has a separate AC input; when AC is fed in, the tube lights up. One drawback of the driver circuitry is it makes a high-pitched whine when turned on. I originally planned to use the sign to indicate unittest pass/fail status, but it was too annoying to people nearby. <br> <img alt="The power circuits for the pedestrian sign" height="300" src="http://static.righto.com/images/traffic-sign-power.jpg" width="400"> <h3>The code</h3> The Arduino code is available at <a href="http://static.righto.com/files/IRtraffic.pde">IRtraffic.pde</a> and has two main functions: IR processing and light cycle processing. <p> In the IR code, the IR remote is used to select one of five states: walk illuminated, blinking don't walk, don't walk illuminated, off, or cycling (which goes through the first three states). The IR functionality uses my <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">IRremote</a> library to decode the output from a remote control. <p> The code has the values for a particular remote control hard-coded. I used a Sony DVD remote: <pre class="code"> #define OFF_CODE 0x1CB92 // Stop on Sony DVD remote #define WALK_CODE 0xB92 // 1 on Sony DVD remote #define BLINK_CODE 0x80b92 // 2 on Sony DVD remote #define DONT_CODE 0x40b92 // 3 on Sony DVD remote #define CYCLE_CODE 0x4CB92 // Play on Sony DVD remote </pre> The first part of the <code>loop</code> function calls the IR library to see if an IR signal has been decoded. If so, it switches to the appropriate mode. If an unexpected IR value is encountered, it is printed to the serial port. <pre class="code"> void loop() { // Process the IR input, if any if (irrecv.decode(&results)) { if (results.value == WALK_CODE) { Serial.write("Walk\n"); mode = MODE_WALK; cycle = false; } else if (results.value == DONT_CODE) { Serial.write("Don't walk\n"); mode = MODE_DONT; cycle = false; } else if (results.value == OFF_CODE) { Serial.write("Off\n"); mode = MODE_OFF; cycle = false; } else if (results.value == BLINK_CODE) { Serial.write("Blinking don't walk\n"); mode = MODE_BLINK; blinkOn = true; nextBlinkMillis = millis() + 500; // 500 ms blink cycle = false; } else if (results.value == CYCLE_CODE) { Serial.write("Cycle\n"); nextCycleMillis = millis() + 5000; // delay 5 seconds cycle = true; mode = MODE_WALK; } else { Serial.print("unexpected value: "); Serial.println(results.value, HEX); } irrecv.resume(); // Resume decoding (necessary!) } </pre> If you want to use a different remote, simply look at the "unexpected values" printed to the serial port while pressing the desired buttons, copy the hex values into the code, recompile, and reinstall. For instance, to use some Tivo buttons, simply change the button definitions to: <pre class="code"> #define OFF_CODE 0x20df10ef #define WALK_CODE 0xa10cd00f #define BLINK_CODE 0xa10c8807 #define DONT_CODE 0xa10cc807 #define CYCLE_CODE 0xa10c6c03 </pre> The other main function of the code is timing. There are two timing cycles going on. First, if cycle mode is enabled, the mode is advanced through walk, blink, and don't walk every five seconds. Second, if in the blinking don't walk phase, the output is turned on or off every half second. <p> I originally used delays of 500 or 1000 ms for the timing, but this had the disadvantage that the light wasn't very responsive to the remote control - it would wait up to 1 second before processing the remote control value. I rewrote the code using the <a href="http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay">BlinkWithoutDelay</a> approach. In this approach, there are no delays in the loop code. Instead, the millis() value is checked to see if it is time to change state. If nothing needs to be done, loop() ends without any delay. <p> In more detail, the boolean <code>cycle</code> is true if the light is to cycle between the three phases. In this case, <code>nextCycleMillis</code> is set to the time at which we move to the next cycle (i.e. 5 seconds in the future). Once we reach that time, the mode is advanced. The boolean <code>blinkOn</code> keeps track of whether the don't walk sign is on or off while blinking. <pre class="code"> if (cycle && millis() >= nextCycleMillis) { if (mode == MODE_WALK) { mode = MODE_BLINK; blinkOn = false; nextBlinkMillis = millis() + 500; // 500 ms blink nextCycleMillis = millis() + 5000; // delay 5 seconds } else if (mode == MODE_BLINK) { mode = MODE_DONT; nextCycleMillis = millis() + 5000; // delay 5 seconds } else { mode = MODE_WALK; nextCycleMillis = millis() + 5000; // delay 5 seconds } } </pre> The other independent time is <code>nextBlinkMillis</code>. This is the time at which the don't walk sign should change state, and it is set 500ms into the future. <pre class="code"> if (mode == MODE_BLINK && millis() >= nextBlinkMillis) { blinkOn = !blinkOn; nextBlinkMillis = millis() + 500; // 500 ms blink } </pre> The code may be confusing at first due to the two independent times (nextCycleMillis and nextBlinkMillis) and state variables (mode and blinkOn). It seemed simpler this way rather than folding both cycles into one. <p> Finally, the code sets the appropriate lights on or off: <pre class="code"> if (mode == MODE_WALK) { digitalWrite(DONT_PIN, LOW); digitalWrite(WALK_PIN, HIGH); } else if (mode == MODE_DONT || (mode == MODE_BLINK && blinkOn)) { digitalWrite(DONT_PIN, HIGH); digitalWrite(WALK_PIN, LOW); } else { digitalWrite(DONT_PIN, LOW); digitalWrite(WALK_PIN, LOW); } </pre> <h3>Conclusion</h3> I have two extra pedestrian signs; I'll give them away for free if you can pick them up in the SF Bay Area. <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/4676258495472100746' onclick=''> 4 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=4676258495472100746' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=4676258495472100746&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4676258495472100746&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4676258495472100746&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4676258495472100746&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4676258495472100746&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=4676258495472100746&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='5947052936271263149' itemprop='postId'/> <a name='5947052936271263149'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2010/01/using-arbitrary-remotes-with-arduino.html'>Using arbitrary remotes with the Arduino IRremote library</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-5947052936271263149' itemprop='description articleBody'> My <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">IRremote</a> library decodes output from many infrared remotes: Sony, NEC, RC5, and RC6. However, many remotes use other protocols. While it's not too hard to add support for other protocols, I wanted to show how the library can be used with arbitrary remote controls. <p> This post describes a simple routine that will generate a unique code for each key on an arbitrary remote. The demo application flashes the LED the appropriate number of times when I push the 0-9 button on my remote. <h3>How it works</h3> The IRremote library records the duration of each (modulated) pulse sent by the remote control. Each key on the remote corresponds to a particular code value, which is converted to a particular sequence of pulses. If you know the encoding algorithm, you can determine the code value, and thus the key pressed. However, for many applications it doesn't really matter what the original code value is, as long as you can uniquely distinguish each key. Thus, if you can turn each unique sequence of pulses into a unique value, then this value will indicate the desired key. <p> To do this, I look at the duration of successive pulses. If the pulse is shorter than the previous, I assign 0. If the pulse is the same length, I assign 1. If the pulse is longer, I assign 2. (I compare on-durations with on-durations and off-durations with off-duations.) The result is a sequence of 0's, 1's, and 2's. I hash these values into a 32-bit hash value. <p> With luck, the 32-bit hash value will be unique for each key. Note that these hash values are arbitrary, and don't have any obvious connection with the underlying code value. Most encoding protocols use two different durations, so comparing shorter vs longer will work, but you can imagine a code with multiple duration values that wouldn't work here. In addition, hash collisions could occur, but are pretty unlikely with a 32-bit hash. <h3>Code</h3> The code can be downloaded from <a href="http://static.righto.com/files/IRhashdecode.pde">IRhashcode.pde</a>. The sample application prints the "real" decoded value and the hash value. The "real" value will only work for supported protocols (Sony, RC5, RC6, NEC), but the hash value should work for almost any remote control. <p> The code is pretty straightforward. <code>compare()</code> compares the two measured durations within the 20% tolerance. <pre class="code"> int compare(unsigned int oldval, unsigned int newval) { if (newval < oldval * .8) { return 0; } else if (oldval < newval * .8) { return 2; } else { return 1; } } </pre> The actual decoding is fairly simple. <code>results->rawbuf</code> holds the measured durations as space, mark, space, mark, ... The loop compares each duration with the next of the same type, and adds that value to the hash result. <pre class="code"> #define FNV_PRIME_32 16777619 #define FNV_BASIS_32 2166136261 unsigned long decodeHash(decode_results *results) { unsigned long hash = FNV_BASIS_32; for (int i = 1; i+2 < results->rawlen; i++) { int value = compare(results->rawbuf[i], results->rawbuf[i+2]); // Add value into the hash hash = (hash * FNV_PRIME_32) ^ value; } return hash; } </pre> The mystery FNV numbers come from the <a href="http://isthe.com/chongo/tech/comp/fnv/#FNV-param">FNV 32-bit hash function</a>, which combines all the values into a single 32-bit value. <p> The following example code prints out the "real" decoded value and the hash decoded value to the serial port. You will want to use this code to figure out what hash value is associated with each key on the remote. <pre class="code"> void loop() { if (irrecv.decode(&results)) { Serial.print("'real' decode: "); Serial.print(results.value, HEX); Serial.print(", hash decode: "); Serial.println(decodeHash(&results), HEX); irrecv.resume(); // Resume decoding (necessary!) } } </pre> Here's a slightly more realistic example. It receives a code from a Philips remote and flashes the LED appropriately. If you press "1", it flashes once, if you press "8" it flashes 8 times, etc. The code simply uses a case statement to match against the pressed key, and blinks that many times. <p> You will need to modify this to work with your remote. If it doesn't recognize the code, it will print it to the serial output. Put these unrecognized values into the code to make it work with your remote. <pre class="code"> #define LEDPIN 13 void blink() { digitalWrite(LEDPIN, HIGH); delay(200); digitalWrite(LEDPIN, LOW); delay(200); } void loop() { if (irrecv.decode(&results)) { unsigned long hash = decodeHash(&results); switch (hash) { case 0x322ddc47: // 0 (10) blink(); // fallthrough case 0xdb78c103: // 9 blink(); case 0xab57dd3b: // 8 blink(); case 0x715cc13f: // 7 blink(); case 0xdc685a5f: // 6 blink(); case 0x85b33f1b: // 5 blink(); case 0x4ff51b3f: // 4 blink(); case 0x15f9ff43: // 3 blink(); case 0x2e81ea9b: // 2 blink(); case 0x260a8662: // 1 blink(); break; default: Serial.print("Unknown "); Serial.println(hash, HEX); } irrecv.resume(); // Resume decoding (necessary!) } } </pre> <h3>Debugging</h3> The most likely problem is a key will occasionally have different code values. This is likely due to random errors in measuring the pulses. The code considers any durations within +/- 20% to be equal; you can try increasing this value. <p> If you're using a RC5/RC6 remote, each key will alternate between two different values. In that case, you probably want to use the "real" decoded value, rather than the hashed value, since you can mask out the toggle bit. <p> If your remote uses a protocol with multiple duration values, you probably won't get unique values from this algorithm. <p> For other problems, see the <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">IRremote page</a>, which also has a schematic for wiring up the IR detector. <h3>Conclusion</h3> This IR hash algorithm extends the IRremote library to be usable with many more types of infrared remote controls. Please let me know if you use it, and I'll add a link to your project if you want. <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/5947052936271263149' onclick=''> 21 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=5947052936271263149' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=5947052936271263149&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5947052936271263149&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5947052936271263149&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5947052936271263149&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5947052936271263149&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5947052936271263149&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/irweb-g1.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='3879397241658203130' itemprop='postId'/> <a name='3879397241658203130'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2009/12/arc-beats-python-for-web-controlled.html'>Arc beats Python for a web-controlled stereo</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-3879397241658203130' itemprop='description articleBody'> I recently set up a web interface to my stereo, implementing it in both Python and Arc. I found that, much to my surprise, writing the Arc implementation was much easier than the Python implementation in this case. <p> In my stereo controller system, I go to a web page that has an image of the appropriate remote control, and click the button. The Javascript in the web page sends a hex code back to the server, which sends the code to an Arduino microcontroller board, which converts the code into an infrared signal. The stereo interprets this signal as a command from the remote control and performs the desired action. It sounds complicated, but it responds quickly, even if I use the browser on my cell phone. I wrote up <a href="http://www.righto.com/2009/11/controlling-your-stereo-over-web-with.html">more details on the system</a> earlier. <br> <img alt="Remote control on G1 phone" height="523" src="http://static.righto.com/images/irweb-g1.jpg" width="600"> <br> The web server for this project is fairly straightforward: it needs to serve some static HTML pages and images, and needs to receive POST messages and forward the data over the serial port to the Arduino. I originally wrote the code in Python: <pre class="code"> import cgi import serial from BaseHTTPServer import HTTPServer from SimpleHTTPServer import SimpleHTTPRequestHandler class MyHandler(SimpleHTTPRequestHandler): def do_POST(self): if self.path == '/arduino': form = cgi.FieldStorage(fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD':'POST'}) code = form['code'].value print 'Sent:', code arduino.write(code) self.send_response(200) self.send_header('Content-type', 'text/html') return return self.do_GET() arduino = serial.Serial('/dev/ttyUSB0', 9600, timeout=2) server = HTTPServer(('', 8080), MyHandler).serve_forever() </pre> The Python web server is based on <a href="https://docs.python.org/library/simplehttpserver.html">SimpleHTTPServer</a>. To handle POST requests to the <code>/arduino</code> URL, I made a simple handler subclass that pulls the data out of the response, sends it to the serial port, and returns a blank response. The last two lines open the serial port and start up the server. The static web page serving comes "for free." <p> After writing this, I decided to try writing a version in Arc: <pre class="code"> (= srvops* (table)) (= arduino-serial (outfile "/dev/ttyUSB0" 'binary)) (defopr || req "/index.html") (defop arduino req (w/stdout (stderr) (let code (arg req "code") (write code arduino-serial) (prn "Sent code:" code)))) (thread (serve 8080)) </pre> Since you may not be familiar with the <a href="http://www.righto.com/doc/srv.html">Arc web server</a>, I'll give a brief explanation. The first line clears out the server's default pages (login, whoami, prompt, etc) that make sense for <a href="http://news.ycombinator.com">news.yc</a>, but not for me. The next line opens the serial port. Next, the mysterious || redirects the home page. The next four lines are the handler for "/arduino": the "code" parameter is pulled out of the request (<code>req</code>). The code is written to the serial port, and printed to the log. The last line starts a serving thread on port 8080. <p> I'm not going to count tokens since that's a silly metric, but the Arc code is a clear winner here. The first Python disadvantage is the hideous <code>cgi.FieldStorage</code> call to parse the POST data; apparently this is the way to do it, but it took me considerable time to get this right. The second Python disadvantage is the necessity to set up the return code and content-type for the response. I ended up with a browser-specific bug when I didn't have this right, since some Javascript interpreters expect a particular response. Arc automatically sends a valid response. The main Arc disadvantage is there's no real serial port support; the Arc code just opens the port and hopes for the best. On the other hand, Python's serial library lets you set the baud rate, timeouts, and other parameters. <p> Arc and Python have a few more minor differences. Python requires imports, which Arc doesn't. Arc has the silly clearing of <code>srvops*</code> to avoid unwanted pages. Starting the server thread is simpler in Arc but not as flexible. <p> To summarize, I found the Python code difficult and error-prone to write, and the Arc code was shorter and just worked. This was a surprise to me; usually I find Python straightforward and Arc gives me pain when I have to write a bunch of code for some trivial thing it doesn't support. (For example, generating a time string in my <a href="http://www.righto.com/2009/08/arc-arduino-arm-temperature-monitoring.html">temperature monitoring</a>.) In this case, however, Arc came out ahead. Perhaps this is because Arc's flagship application is a web server, so it handles web serving well. <p> Obviously this is a fairly trivial program - the complexity is actually in the Javascript code and the <a href="http://www.righto.com/2009/11/controlling-your-stereo-over-web-with.html">C++ code on the Arduino</a> - so I'm not claiming this as an overall victory for Arc over Python. But it's still interesting to find Arc came out ahead in this case. <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/3879397241658203130' onclick=''> 1 comment: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=3879397241658203130' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=3879397241658203130&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=3879397241658203130&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=3879397241658203130&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=3879397241658203130&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=3879397241658203130&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=3879397241658203130&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arc' rel='tag'>arc</a>, <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/arduino-tv-b-gone.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='5267438637132076842' itemprop='postId'/> <a name='5267438637132076842'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2009/12/tv-b-gone-for-arduino.html'>TV-B-Gone for the Arduino</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-5267438637132076842' itemprop='description articleBody'> I've ported the TV-B-Gone code to run on the <a href="http://www.arduino.cc/">Arduino</a> board. If you haven't seen a TV-B-Gone, it's a cute gadget that you point at a TV that's bothering you, and it turns the TV off. Internally, it's an infrared remote that broadcasts more than 100 different off codes that work on almost any TV. I figured it would be interesting to get the TV-B-Gone running on the Arduino. <br><img alt="TV-B-Gone running on an Arduinio" height="409" src="http://static.righto.com/images/arduino-tv-b-gone.jpg" width="500"> <h3>Update (November 2010)</h3> I have a new, improved version of the software. Details and download are <a href="http://www.righto.com/2010/11/improved-arduino-tv-b-gone.html">here</a>. <h3>The software</h3> <iframe align="right" src="http://rcm-na.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=rightocom&o=1&p=8&l=as1&m=amazon&f=ifr&md=10FE9736YVPPT7A0FBG2&asins=B0006GD9CE" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe> I started with the TV-B-Gone firmware, which is <a href="http://www.ladyada.net/make/tvbgone/download.html">available</a> under Creative Commons license. The TV-B-Gone runs on an ATtiny85 microcontroller, not the ATmega328 used by the Arduino, so some porting was required. One tricky part of the port is the IR signals are generated using the low-level hardware timer for PWM (pulse-width modulation). Since the ATtiny85 runs at 8MHz, and the Arduino runs at 16MHz, the timing code needed to be re-written, both the 10us delay loop and the timer register operations. The quick summary is I'm using Timer 2, scaling the clock by 8, using OCR2A to control the frequency and OCR2B to control the duty cycle, and have output on pin 3 (OC2B). (You are not expected to understand this. See my article on <a href="http://www.righto.com/2009/07/secrets-of-arduino-pwm.html">Secrets of Arduino PWM</a> for details of how these timers work.) <pre class="code"> #define freq_to_timerval(x) (F_CPU / 8 / x - 1) ... pinMode(IRLED, OUTPUT); TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); TCCR2B = _BV(WGM22) | _BV(CS21); ... OCR2A = freq; OCR2B = freq / 3; // 33% duty cycle </pre> Another tricky thing is the original firmware stores the IR codes in program space, not RAM. The microcontrollers use a <a href="https://en.wikipedia.org/wiki/Harvard_architecture">Harvard architecture</a>, which means they have separate memory and data paths for code and data, unlike normal processors that use a <a href="https://en.wikipedia.org/wiki/Von_Neumann_architecture">von Neumann architecture</a>. Because RAM storage is so small on these microcontrollers, the IR codes are stored in program space, with the result you need to use special methods to access them, rather than normal C pointers. Program memory storage is indicated with the <a href="http://www.arduino.cc/en/Tutorial/Memory">PROGMEM</a> macro and pulled out of memory using special functions such as <code>pgm_read_byte</code>. This makes the code somewhat confusing, for example: <pre class="code"> const struct IrCode *NApowerCodes[] PROGMEM = { &code_na000Code, ... } data_ptr = (PGM_P)pgm_read_word(NApowerCodes+i); </pre> <p> The original firmware stores the codes as compressed indices into tables of durations. See the <a href="http://www.ladyada.net/make/tvbgone/design.html">TV-B-Gone design</a> for details. Unfortunately, the Arduino's compiler didn't like the zero-length array in the IrCode structure, so I needed to rewrite the long file of codes to include another level of indirection. <p> Apart from these factors, porting was straightforward, and I tried to keep the original code where possible. I ripped out all the power-up and watchdog code. I replaced the low-level serial code with the Arduino's Serial library. Finally, I packaged it up into an Arduino sketch, which you can <a href="http://static.righto.com/files/arduino-tv-b-gone-1.zip">download</a>. (Update: get the improved version <a href="http://www.righto.com/2010/11/improved-arduino-tv-b-gone.html">here</a>.) <h3>The hardware</h3> The hardware is straightfoward. I use pin 13 for the status LED; some Arduinos conveniently have an LED already wired up. Pin 3 is the PWM output to the IR LED through a 100 ohm resistor. If you want more range, add a <a href="http://www.ladyada.net/make/tvbgone/design.html">driver transistor</a> and use multiple IR LEDs. Pin 0 (update: pin 5) selects North American or European codes; leave it unconnected for North America and ground it for European. Pin 1 (update: 2) is connected via a pushbutton to ground to trigger the code transmission. (Update: pins have changed in the new version.) <p> To use the Arduino TV-B-Gone, point the IR LED at your TV, push the button, and your TV should turn off when the circuit hits the right code, which could take up to a minute. The visible LED should flash for each code that is transmitted. If the circuit doesn't work, use a cellphone camera to verify that the IR LED is transmitting. Don't expect more than a few feet range unless you use a transistor to increase the power. The code will print debugging output to the serial port if you set <code>DEBUG</code> in <code>main.h</code>. <h3>Summary</h3> Is the Arduino TV-B-Gone practical? If you want a TV-B-Gone that you can carry around to amaze your friends, the <a href="http://www.adafruit.com/index.php?main_page=product_info&cPath=20&products_id=73">kit</a> or <a href="https://www.amazon.com/gp/product/B0006GD9CE?ie=UTF8&tag=rightocom&linkCode=as2&camp=1789&creative=390957&creativeASIN=B0006GD9CE">product</a><img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=rightocom&l=as2&o=1&a=B0006GD9CE" style="border:none !important; margin:0px !important;" width="1" /> is much more compact, has high-powered IR outputs for longer range, and is nicely packaged. However, the Arduino platform is convenient for experimenting, and many people already have it, so I expect people will find it interesting. <p> You might wonder why I'm not using my <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">Arduino Infrared Library</a> for this project. Actually, I plan to at some point, but I wanted to get the straightforward port working first. In addition, my library will need some extensions to support all the codes that the TV-B-Gone supports. <p> I hope you enjoy the Arduino TV-B-Gone, and remember to use it for good, not evil! <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/5267438637132076842' onclick=''> 43 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=5267438637132076842' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=5267438637132076842&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5267438637132076842&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5267438637132076842&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5267438637132076842&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5267438637132076842&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=5267438637132076842&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> <div class="date-outer"> <div class="date-posts"> <div class='post-outer'> <div class='post hentry' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='http://static.righto.com/images/irweb-g1.jpg' itemprop='image_url'/> <meta content='6264947694886887540' itemprop='blogId'/> <meta content='1341619272327259710' itemprop='postId'/> <a name='1341619272327259710'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='http://www.righto.com/2009/11/controlling-your-stereo-over-web-with.html'>Controlling your stereo over the web with the Arduino infrared library</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-1341619272327259710' itemprop='description articleBody'> Here's how you can control your stereo over the web. Not only that, but any other electronics with a IR remote control can now be controlled through your browser. You can even use your smart phone's browser to control your stereo from across the room or around the world. <br> <img alt="Remote control on G1 phone" height="523" src="http://static.righto.com/images/irweb-g1.jpg" width="600"> <br> This project has several pieces: a simple Python web server running on your computer, an Arduino with my <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">infrared library</a>, and an IR LED or other emitter. The Python web server provides a web page with a graphical remote control. Clicking on the web page sends a code to the web server, which sends it over the serial port to the Arduino, which sends it to the IR LED, which controls your device. <h3>The web server</h3> I used a rather trivial Python web server (based on <a href="https://docs.python.org/library/simplehttpserver.html">SimpleHTTPServer</a>) that performs two tasks. First, it provides the static HTML pages and images. Second, it receives the POST requests and sends them to the Arduino using the <a href="http://pyserial.sourceforge.net/">pyserial</a> library. <p> The following code excerpt shows the handler that processes POSTs to <code>/arduino</code> by extracting the <code>code</code> value out of the POST data and sending it to the Arduino over the serial line. The Python server automatically provides static pages out of the current directory by default; this is how the HTML files and images are served. The code assumes the serial port is </code>/dev/ttyUSB0</code>, which is typically the case on Linux. <pre class="code"> class MyHandler(SimpleHTTPRequestHandler): def do_POST(self): if self.path == '/arduino': form = cgi.FieldStorage(fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD':'POST'}) code = form['code'].value arduino.write(code) self.send_response(200) self.send_header('Content-type', 'text/html') return return self.do_GET() arduino = serial.Serial('/dev/ttyUSB0', 9600, timeout=2) server = HTTPServer(('', 8080), MyHandler).serve_forever() </pre> The server can be accessed locally at <code>http://localhost:8080</code>. You may need to mess around with your firewall and router to access it externally; this is left as an exercise for the reader. I found that using my cell phone's browser via Wi-Fi worked surprisingly well, and over the cellular network there was just a slight lag (maybe 1/3 second). <h3>The Arduino code</h3> The code on the Arduino is pretty simple. It reads a command from the serial port and makes the appropriate IR library call. Commands consist of a character indicating the type of code, followed by 8 hex characters. For instance, "S0000004d1" sends the code 4d1 using Sony protocol; this is "play" on my Sony CD player. "N010e03fc" sends 010e03fc using NEC protocol; this turns my Harman Kardon stereo on. The full code is <a href="http://static.righto.com/files/IRwebremote_files.zip">here</a>, but some highlights: <pre class="code"> void processSerialCode() { if (Serial.available() < 9) return; char type = Serial.read(); unsigned long code = 0; // Read 8 hex characters into code (omitted) if (type == 'N') { irsend.sendNEC(code, 32); } else if (type == 'S') { // Send Sony code 3 times irsend.sendSony(code, 12); delay(50); irsend.sendSony(code, 12); delay(50); irsend.sendSony(code, 12); } // More code for RC5 and RC6 } </pre> In more detail, the Arduino waits for 9 characters to be available on the serial port. It then parses the hex value and calls the appropriate IR library send routine. The Arduino code does some special-case stuff for the different code types. Sony codes are transmitted three times as the protocol requires. The RC5 and RC6 protocol uses a <a href="http://www.sbprojects.com/knowledge/ir/rc5.htm">toggle bit</a> that is flipped on each transmission. (Disclaimer: I don't have RC5/RC6 devices, so this code is untested.) If your device uses a different protocol that the library doesn't support, you're out of luck unless you add the protocol to the library. That's probably not too hard; a couple people have already implemented new protocols. <br> <img alt="Arduino controlling stereo via IR" height="291" src="http://static.righto.com/images/irweb-arduino.jpg" width="500"> <h3>The web page</h3> Most of the smarts of the system are in the web page. In my setup, I have a HK-3370 stereo, and a Sony CDP-CE335 CD player. I took a picture of the remote for each and used an HTML image map to make each button clickable. Clicking on a button uses Ajax to POST the appropriate IR code to the server. <p> I use Ajax to send the code to the server to avoid reloading the web page on every click. The Javascript code is verbose but straightforward. The first part of the code creates the XML request object; unfortunately different browsers use different objects. The next part of the code creates and sends the POST request. The actual data sent to the server is, for instance, "code=N12345678" to send 0x12345678 using NEC protocol. <pre class="code"> function button(value) { if (window.XMLHttpRequest) { request = new XMLHttpRequest(); } else if (window.ActiveXObject) { try { request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } request.open('POST', '/arduino', true); request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); request.setRequestHeader('Content-length', value.length); request.setRequestHeader('Connection', 'close'); request.send('code=' + value); } </pre> The clickable buttons are defined in the HTML through an image and an image map. Generating the image and the image map is the hard part of the whole project: <pre class="code"> <img src="hk3370.png" width="268" height="800" border="0" usemap="#map" /> <map name="map"> <area shape="rect" coords="60,97,85,111" href="#" alt="on" onClick="button('N010e03fc')" /> <area shape="rect" coords="104,98,129,109" href="#" alt="off" onClick="button('N010ef906')" /> ... </pre> Each line in the map defines a region of the image as a button with a particular code. When clicked, this region will call the <code>button</code> function with the appropriate code, causing the code to be sent to the web server, the Arduino, and finally to the stereo. The <code>alt</code> text isn't actually used, but I recommend it to keep track of what button is associated with each line. The <code>href</code> causes the cursor to change when you go over the region, but isn't necessary. <br> <img alt="Image of remote control in Internet Explorer" height="350" src="http://static.righto.com/images/irweb-ie.png" width="407"> <p> In this approach, the Arduino code and web server code are very simple, as they don't need to know the functions of the codes. A different way to implement this system would be to put the table of codes ("SONY_CD_ON" = 4d1, etc.) either in the web server code or the Arduino code. <p> To generate the web pages, I took a picture of the remote with my camera and cleaned up the picture with GIMP. I used the <a href="http://docs.gimp.org/en/plug-in-imagemap.html">GIMP image map plugin</a> to create the image map. I outlined each button, then filled in the URL with the appropriate IR code, and filled in the alt text with the name of the button. Finally, I copied the map file into the HTML file and edited it to use the Javascript function. <p> The easiest way to obtain the IR codes is to use the <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">IRrecvDump example sketch</a> included in my IR library. Simply press the button on your remote, see what code was sent, and put that code into the image map. Alternatively, you may be able to find codes in the LIRC database. <p> Once you get going, it's actually fairly quick to generate the image map. Select a button in the editor, click the physical button on the remote, copy the displayed value into the editor, and move on to the next button. As long as you don't get obsessive and start tweaking the regions to line up perfectly, it's pretty quick. <p> If you don't want to mess around with the image map, take a look at <code>simple.html</code>. This file shows how to use standard HTML buttons. Not as cool as the image, but much easier: <pre class="code"> <input type="button" value="on" onClick="button('N010e03fc')" > <input type="button" value="off" onClick="button('N010ef906')" > ... </pre> <img alt="Simple button arrangement" height="189" src="http://static.righto.com/images/irweb-simple.png" width="326"> <h3>The hardware</h3> The Arduino does the work of converting the hex code into an IR signal. The IR library uses digital PWM pin 3 as output, which must be connected to your IR emitter. I use a 100 ohm resistor to limit current. Wiring it up is trivial. <br> <img alt="Schematic of IR connection to Arduino" height="163" src="http://static.righto.com/images/irweb-schematic.png" width="124"> <p> I used a Tivo IR blaster that I had lying around, but a plain IR LED will work too. The following picture shows an IR blaster attached to my sterero. Note that the blaster needs to be positioned about the stereo's IR receiver; it may be easier to see the receiver with a flashlight. <br> <img alt="IR blaster attached to stereo" height="294" src="http://static.righto.com/images/irweb-hk-emitter.jpg" width="600"> <h3>Putting it all together</h3> To summarize the steps: <ul> <li>Download the <a href="http://static.righto.com/files/IRwebremote_files.zip">files</a> and unpack them. <li>Get the <a href="http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html">infrared library</a> and install it. <li>Aim the IR source at the device(s) to control, and connect it to the Arduino. (You may want to use a visible LED for testing.) <li>Connect the Arduino to the computer's USB port. <li>Compile and install <code>IRwebremote.pde</code> using the Arduino IDE. <li>Create HTML files for your remote controls. (This is the hard step.) <li>Run the Python server: <code>python server.py</code> <li>Go to <code>http://localhost:8080</code> and control the devices. </ul> This project has multiple pieces and requires customization, so it's not a plug-and-play project. I only recommend trying this if you know what you're doing. Good luck! <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'><span class='post-comment-link'> <a class='comment-link' href='https://www.blogger.com/comment/fullpage/post/6264947694886887540/1341619272327259710' onclick=''> 41 comments: </a> </span> <span class='post-icons'> <span class='item-action'> <a href='https://www.blogger.com/email-post.g?blogID=6264947694886887540&postID=1341619272327259710' title='Email Post'> <img alt='' class='icon-action' height='13' src='http://img1.blogblog.com/img/icon18_email.gif' width='18'/> </a> </span> <span class='item-control blog-admin pid-1138732533'> <a href='https://www.blogger.com/post-edit.g?blogID=6264947694886887540&postID=1341619272327259710&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <span class='post-backlinks post-comment-link'> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=1341619272327259710&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=1341619272327259710&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=1341619272327259710&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=1341619272327259710&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=6264947694886887540&postID=1341619272327259710&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'><span class='post-labels'> Labels: <a href='http://www.righto.com/search/label/arduino' rel='tag'>arduino</a>, <a href='http://www.righto.com/search/label/ir' rel='tag'>ir</a> </span> </div> <div class='post-footer-line post-footer-line-3'></div> </div> </div> </div> </div></div> </div> <div class='blog-pager' id='blog-pager'> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='http://www.righto.com/search/label/ir?updated-max=2009-11-17T23:29:00-08:00&max-results=20&start=14&by-date=false' id='Blog1_blog-pager-older-link' title='Older Posts'>Older Posts</a> </span> <a class='home-link' href='http://www.righto.com/'>Home</a> </div> <div class='clear'></div> </div></div> </div> </div> <div class='column-left-outer'> <div class='column-left-inner'> <aside> </aside> </div> </div> <div class='column-right-outer'> <div class='column-right-inner'> <aside> <div class='sidebar section' id='sidebar-right-1'><div class='widget HTML' data-version='1' id='HTML2'> <div class='widget-content'> <style> @import url('https://fonts.googleapis.com/css?family=Montserrat:300,400,500,700'); .form-preview { display: flex; flex-direction: column; justify-content: center; margin-top: 30px; padding: clamp(17px, 5%, 40px) clamp(17px, 7%, 50px); max-width: 350px; min-height: 200px; border-radius: 6px; box-shadow: 0 5px 25px rgba(34, 60, 47, 0.25); } .form-preview, .form-preview *{ box-sizing: border-box; } .form-preview .preview-heading { width: 100%; } .form-preview .preview-heading h5{ margin-top: 0; margin-bottom: 0; } .form-preview .preview-input-field { margin-top: 20px; width: 100%; } .form-preview .preview-input-field input { width: 100%; height: 40px; border-radius: 6px; border: 2px solid #e9e8e8; background-color: #fff; outline: none; } .form-preview .preview-input-field input::placeholder, .form-preview .preview-input-field input { opacity: 0.5; color: #000; font-family: "Montserrat"; font-size: 14px; font-weight: 500; line-height: 20px; text-align: center; } .form-preview .preview-submit-button { margin-top: 10px; width: 100%; } .form-preview .preview-submit-button button { width: 100%; height: 40px; border: 0; border-radius: 6px; line-height: 0px; } .form-preview .preview-submit-button button:hover { cursor: pointer; } </style><form data-v-4c58e686="" action="https://api.follow.it/subscription-form/U3NBTmZKVkI1YVpCa000a0RCZHFiQ3FYMko1cWRTZTN6K3hJdWM2QWxJbE1uVXdXUHZZVzJVQzVLZGh5Y0RCVXB2d2JSTzBobGhuY0FsZnlHbVdFZ2VTN2Q4Vy84RnIxUTgzVlcrbXNIR0Y0aW93d3REM2J6VS9RL0gxWURnV1d8ZWN0YStwUWdWWUFiOTIyWDVGWjdYYVdGZEVNcC9qODZacjlwWXRIcEJQRT0=/8" method="post"><div data-v-4c58e686="" class="form-preview" style="background-color: rgb(255, 255, 255); border-style: solid; border-width: 1px; border-color: rgb(204, 204, 204); position: relative;"><div data-v-4c58e686="" class="preview-heading"><h5 data-v-4c58e686="" style="font-family: Montserrat; font-weight: bold; color: rgb(0, 0, 0); font-size: 12px; text-align: center;">Get new posts by email:</h5></div> <div data-v-4c58e686="" class="preview-input-field"><input data-v-4c58e686="" type="email" name="email" placeholder="Enter your email" spellcheck="false" /></div> <div data-v-4c58e686="" class="preview-submit-button"><button data-v-4c58e686="" type="submit" style="font-family: Montserrat; font-weight: bold; color: rgb(255, 255, 255); font-size: 12px; text-align: center; background-color: rgb(0, 0, 0);">Subscribe</button></div></div></form> </div> <div class='clear'></div> </div><div class='widget HTML' data-version='1' id='HTML3'> <h2 class='title'>About the site</h2> <div class='widget-content'> <a href="https://www.righto.com/p/index.html">Contact info and site index</a> </div> <div class='clear'></div> </div><div class='widget PopularPosts' data-version='1' id='PopularPosts1'> <h2>Popular Posts</h2> <div class='widget-content popular-posts'> <ul> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2024/11/antenna-diodes-in-pentium-processor.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_tnX-SU2YCjwCQ1owq7XJUKhb9J0HCdJfJNnZ0RiSqgX1mjUEjfi9wV4apZ1xjZRz6ADaTEqkSUX6kujRcwcP0erTiFCWM2bxBNsw0BJ5-xHzHxQrrCJvSJpwJ63egrOqS_r34=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2024/11/antenna-diodes-in-pentium-processor.html'>Antenna diodes in the Pentium processor</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2012/05/apple-iphone-charger-teardown-quality.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_sg_V5A_KEJb7V-79ol7cG0zAFRBpJ8R8T1A8Z5_XZ6W5H6pk8eqdZsUlSe1YGsDDEZcjzUrfiMO6rM_-BnZmzCqsQFvwqsZI17pwa5M4HktK6j7ZPmxV7viDXq4XxNzzSBmXdaUQHKggudAIwcL8Y4GMY=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2012/05/apple-iphone-charger-teardown-quality.html'>Apple iPhone charger teardown: quality in a tiny expensive package</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2024/05/blog-post.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_vyCuHJmQiaWqZxsZF3l_-alKTRNjaWTwuh9yiAmHOKxOYcxz_FlR8ct76HkkaJUqDJOIsonl6rNxvR81S2GTDD4bzcExpkPjbAUUT7OdI_Ou_hed5Oq5cmhNHoW28abNvz-F-msk83JZkTl7JRoZDW=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2024/05/blog-post.html'>Inside a vintage aerospace navigation computer of uncertain purpose</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2014/09/mining-bitcoin-with-pencil-and-paper.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_u0r4Z74aYFftkgUSaL3MS_N4q0Xm18Mthi4Axucorfuz3HS5RZFeo_ld0Ti91aFtsMAGBnuL9OeqbaoBHLeLqm32FlRiCxv7vCrZgFnLoU53RNUigtWbHwBiKbRekb25LD=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2014/09/mining-bitcoin-with-pencil-and-paper.html'>Mining Bitcoin with pencil and paper: 0.67 hashes per day</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_s5akObr_y2CymBoJ7yT0EE2mCpjXdMyNiTKPi2AgNmU9ugQUW0Jr_1vslIgs6pQq0Hp7mPoR4uUe9LDd5VucWuh5SlrNtq0m1Zt9eJRGKnDqU=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html'>A Multi-Protocol Infrared Remote Library for the Arduino</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2024/08/pentium-navajo-fairchild-shiprock.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_sZ9CA7CD3_u8-4zVHOlh55UhnVOAq9oJnuX3MWLauln1_s2fYR-K4ydMwBbxMPhj_DB6LP895xJCyYF1KBKorki9Xh62zuzfi8tZdJUOAEZpjX6vjSQlW6AxKnk3AfWKkVb7mq=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2024/08/pentium-navajo-fairchild-shiprock.html'>The Pentium as a Navajo weaving</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2013/06/teardown-and-exploration-of-magsafe.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_u9Ex3RleuANxEvj0dIbbzQJHZeA25MtKSF1_FHO7TS153_BH9IG4a5YthT1-qzs-_aJI_Lg6N8jm1NcH-ltO1swUfGC8vQZYJl7uLe5Yrl7tMSqp4j4ijLMTKPn7n1gkXHI4K-soJMljhldOo=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2013/06/teardown-and-exploration-of-magsafe.html'>Teardown and exploration of Apple's Magsafe connector</a></div> </div> <div style='clear: both;'></div> </li> <li> <div class='item-thumbnail-only'> <div class='item-thumbnail'> <a href='http://www.righto.com/2023/01/inside-globus-ink-mechanical-navigation.html' target='_blank'> <img alt='' border='0' src='https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_uWQoBp0ZmNRMKQKfqBBiOYgLuJ1sXr3pX6q3Hok_tFhHakCnL2_j6mUC2ejpPe8OfI9zYFbotiu3ixCkfLaISGbiDEZEmt972ay6j6zLyoKhH4wxT4ihLvnBDzJP8B64D365g=w72-h72-p-k-no-nu'/> </a> </div> <div class='item-title'><a href='http://www.righto.com/2023/01/inside-globus-ink-mechanical-navigation.html'>Inside the Globus INK: a mechanical navigation computer for Soviet spaceflight</a></div> </div> <div style='clear: both;'></div> </li> </ul> <div class='clear'></div> </div> </div><div class='widget BlogSearch' data-version='1' id='BlogSearch1'> <h2 class='title'>Search This Blog</h2> <div class='widget-content'> <div id='BlogSearch1_form'> <form action='http://www.righto.com/search' class='gsc-search-box' target='_top'> <table cellpadding='0' cellspacing='0' class='gsc-search-box'> <tbody> <tr> <td class='gsc-input'> <input autocomplete='off' class='gsc-input' name='q' size='10' title='search' type='text' value=''/> </td> <td class='gsc-search-button'> <input class='gsc-search-button' title='search' type='submit' value='Search'/> </td> </tr> </tbody> </table> </form> </div> </div> <div class='clear'></div> </div><div class='widget Label' data-version='1' id='Label1'> <h2>Labels</h2> <div class='widget-content cloud-label-widget-content'> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/386'>386</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/6502'>6502</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/8008'>8008</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/8085'>8085</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/8086'>8086</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/8087'>8087</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/8088'>8088</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/aerospace'>aerospace</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/alto'>alto</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/analog'>analog</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/Apollo'>Apollo</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/apple'>apple</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/arc'>arc</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/arduino'>arduino</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/arm'>arm</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/beaglebone'>beaglebone</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/bitcoin'>bitcoin</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/c%23'>c#</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/cadc'>cadc</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/calculator'>calculator</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/chips'>chips</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/css'>css</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/datapoint'>datapoint</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/dx7'>dx7</a> </span> <span class='label-size label-size-5'> <a dir='ltr' href='http://www.righto.com/search/label/electronics'>electronics</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/f%23'>f#</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/fairchild'>fairchild</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/fpga'>fpga</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/fractals'>fractals</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/genome'>genome</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/globus'>globus</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/haskell'>haskell</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/HP'>HP</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/html5'>html5</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/ibm'>ibm</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/ibm1401'>ibm1401</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/ibm360'>ibm360</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/intel'>intel</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/ipv6'>ipv6</a> </span> <span class='label-size label-size-3'> <span dir='ltr'>ir</span> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/java'>java</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/javascript'>javascript</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/math'>math</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/microcode'>microcode</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/oscilloscope'>oscilloscope</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/Pentium'>Pentium</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/photo'>photo</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/power%20supply'>power supply</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/random'>random</a> </span> <span class='label-size label-size-5'> <a dir='ltr' href='http://www.righto.com/search/label/reverse-engineering'>reverse-engineering</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/sheevaplug'>sheevaplug</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/snark'>snark</a> </span> <span class='label-size label-size-3'> <a dir='ltr' href='http://www.righto.com/search/label/space'>space</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/spanish'>spanish</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/synth'>synth</a> </span> <span class='label-size label-size-4'> <a dir='ltr' href='http://www.righto.com/search/label/teardown'>teardown</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/theory'>theory</a> </span> <span class='label-size label-size-1'> <a dir='ltr' href='http://www.righto.com/search/label/unicode'>unicode</a> </span> <span class='label-size label-size-2'> <a dir='ltr' href='http://www.righto.com/search/label/Z-80'>Z-80</a> </span> <div class='clear'></div> </div> </div><div class='widget BlogArchive' data-version='1' id='BlogArchive1'> <h2>Blog Archive</h2> <div class='widget-content'> <div id='ArchiveList'> <div id='BlogArchive1_ArchiveList'> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> ▼  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/'> 2024 </a> <span class='post-count' dir='ltr'>(20)</span> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> ▼  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='posts'> <li><a href='http://www.righto.com/2024/11/antenna-diodes-in-pentium-processor.html'>Antenna diodes in the Pentium processor</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/09/'> September </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2024/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/'> 2023 </a> <span class='post-count' dir='ltr'>(35)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/12/'> December </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/02/'> February </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2023/01/'> January </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/'> 2022 </a> <span class='post-count' dir='ltr'>(18)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/04/'> April </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2022/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/'> 2021 </a> <span class='post-count' dir='ltr'>(26)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/12/'> December </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/02/'> February </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2021/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/'> 2020 </a> <span class='post-count' dir='ltr'>(33)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/08/'> August </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/05/'> May </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/03/'> March </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2020/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/'> 2019 </a> <span class='post-count' dir='ltr'>(18)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/09/'> September </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/07/'> July </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2019/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/'> 2018 </a> <span class='post-count' dir='ltr'>(17)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2018/01/'> January </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/'> 2017 </a> <span class='post-count' dir='ltr'>(21)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/12/'> December </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2017/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/'> 2016 </a> <span class='post-count' dir='ltr'>(34)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/10/'> October </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/09/'> September </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/06/'> June </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/02/'> February </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2016/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/'> 2015 </a> <span class='post-count' dir='ltr'>(12)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2015/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/'> 2014 </a> <span class='post-count' dir='ltr'>(13)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/09/'> September </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2014/02/'> February </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/'> 2013 </a> <span class='post-count' dir='ltr'>(24)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/08/'> August </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/07/'> July </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2013/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/'> 2012 </a> <span class='post-count' dir='ltr'>(10)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/11/'> November </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2012/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/'> 2011 </a> <span class='post-count' dir='ltr'>(11)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2011/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/'> 2010 </a> <span class='post-count' dir='ltr'>(22)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/11/'> November </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/04/'> April </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2010/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/'> 2009 </a> <span class='post-count' dir='ltr'>(22)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/11/'> November </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/08/'> August </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2009/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/'> 2008 </a> <span class='post-count' dir='ltr'>(27)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/05/'> May </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/04/'> April </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/03/'> March </a> <span class='post-count' dir='ltr'>(10)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='http://www.righto.com/2008/02/'> February </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> </li> </ul> </div> </div> <div class='clear'></div> </div> </div></div> </aside> </div> </div> </div> <div style='clear: both'></div> <!-- columns --> </div> <!-- main --> </div> </div> <div class='main-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <footer> <div class='footer-outer'> <div class='footer-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left footer-fauxborder-left'> <div class='fauxborder-right footer-fauxborder-right'></div> <div class='region-inner footer-inner'> <div class='foot no-items section' id='footer-1'></div> <table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'> <tbody> <tr> <td class='first columns-cell'> <div class='foot no-items section' id='footer-2-1'></div> </td> <td class='columns-cell'> <div class='foot no-items section' id='footer-2-2'></div> </td> </tr> </tbody> </table> <!-- outside of the include in order to lock Attribution widget --> <div class='foot section' id='footer-3'><div class='widget Attribution' data-version='1' id='Attribution1'> <div class='widget-content' style='text-align: center;'> Powered by <a href='https://www.blogger.com' target='_blank'>Blogger</a>. </div> <div class='clear'></div> </div></div> </div> </div> <div class='footer-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </footer> <!-- content --> </div> </div> <div class='content-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <script type='text/javascript'> window.setTimeout(function() { document.body.className = document.body.className.replace('loading', ''); }, 10); </script> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/984859869-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY5mFZC6nqkrUvjyg82CRj0gD55jBg:1733018304734';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d6264947694886887540','//www.righto.com/search/label/ir','6264947694886887540'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '6264947694886887540', 'title': 'Ken Shirriff\x27s blog', 'url': 'http://www.righto.com/search/label/ir', 'canonicalUrl': 'http://www.righto.com/search/label/ir', 'homepageUrl': 'http://www.righto.com/', 'searchUrl': 'http://www.righto.com/search', 'canonicalHomepageUrl': 'http://www.righto.com/', 'blogspotFaviconUrl': 'http://www.righto.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': true, 'httpsEnabled': false, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': 'UA-3782444-1', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Ken Shirriff\x26#39;s blog - Atom\x22 href\x3d\x22http://www.righto.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Ken Shirriff\x26#39;s blog - RSS\x22 href\x3d\x22http://www.righto.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Ken Shirriff\x26#39;s blog - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/6264947694886887540/posts/default\x22 /\x3e\n', 'meTag': '\x3clink rel\x3d\x22me\x22 href\x3d\x22https://www.blogger.com/profile/08097301407311055124\x22 /\x3e\n', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/2fafd358a4bcb2b4', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'index', 'searchLabel': 'ir', 'pageName': 'ir', 'pageTitle': 'Ken Shirriff\x27s blog: ir'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'custom', 'localizedName': 'Custom', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': true}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Ken Shirriff\x27s blog', 'description': 'Computer history, restoring vintage computers, IC reverse engineering, and whatever', 'url': 'http://www.righto.com/search/label/ir', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': false, 'isSearch': true, 'isLabelSearch': true, 'search': {'label': 'ir', 'resultsMessage': 'Showing posts with the label ir', 'resultsMessageHtml': 'Showing posts with the label \x3cspan class\x3d\x27search-label\x27\x3eir\x3c/span\x3e'}}}]); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'navMessage': 'Showing posts with label \x3cb\x3eir\x3c/b\x3e. \x3ca href\x3d\x22http://www.righto.com/\x22\x3eShow all posts\x3c/a\x3e'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML2', 'sidebar-right-1', document.getElementById('HTML2'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML3', 'sidebar-right-1', document.getElementById('HTML3'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_PopularPostsView', new _WidgetInfo('PopularPosts1', 'sidebar-right-1', document.getElementById('PopularPosts1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogSearchView', new _WidgetInfo('BlogSearch1', 'sidebar-right-1', document.getElementById('BlogSearch1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_LabelView', new _WidgetInfo('Label1', 'sidebar-right-1', document.getElementById('Label1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar-right-1', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_AttributionView', new _WidgetInfo('Attribution1', 'footer-3', document.getElementById('Attribution1'), {}, 'displayModeFull')); </script> </body> </html>