Category Archives: Tech Stuff

Some christmas leds

By   December 1, 2015

Working on a sort of secret-santa gift for members of my truck club, I decided to do something with the WS2812B RGB LED’s. There’s a metric buttload of blog articles about these so I thought I would try to add something.

From what I can see, people are spending a lot of time dealing with timing. Nodemcu can do it but not if WIFI is enabled; or at least reliably anyway.. Since I’d had some success with the hardware SPI on the ESP8266 talking to a thermocouple amplifier, I thought I would try to get the SPI hardware to do my bitbanging for me. Turns out it’s actually quite trivial and ‘just worked’. Thanks to Joost Damad for the pattern which saved me the effort of figuring it out myself. Isn’t the internet amazing? Whenever you get a bright idea, turns out someone’s already done it.

First initialize the hardware SPI interface per David Ogilvy’s blog:

bool
ICACHE_FLASH_ATTR
ws2812b_init(void)
{
        if (initialized || sysCfg.board_id != BOARD_ID_PHROB_WS2812B)
                return true;
        spi_init_gpio(SPI_DEV, SPI_CLK_USE_DIV);
        spi_clock(SPI_DEV, SPI_CLK_PREDIV, SPI_CLK_CNTDIV);
        spi_tx_byte_order(SPI_DEV, SPI_BYTE_ORDER_HIGH_TO_LOW);
        spi_rx_byte_order(SPI_DEV, SPI_BYTE_ORDER_HIGH_TO_LOW);
        SET_PERI_REG_MASK(SPI_USER(SPI_DEV), SPI_CS_SETUP|SPI_CS_HOLD);
        CLEAR_PERI_REG_MASK(SPI_USER(SPI_DEV), SPI_FLASH_MODE);
        initialized = 1;
        pcfg.stringlen = 16;
        pcfg.ms_delay = 500;
        os_timer_setfn(&PatternTimer, PatternTimerHandler, NULL);
        return true;
}

Then simply load the bit in question into the SPI data register:

ws2812b_send_zero(void)
{

        int xtemp;
        xtemp = spi_transaction(1, 8, 0x80, 0, 0, 0, 0, 0, 0);
}

ws2812b_send_one(void)
{
        int xtemp;
        xtemp = spi_transaction(1, 8, 0xe0, 0, 0, 0, 0, 0, 0);
}

and that’s it. To send an RGB sequence for a single LED:

static inline void
ws2812b_send_color(uint8_t c)
{
        uint8_t bit=0x80;
        while(bit) {
                if (c&bit)
                        ws2812b_send_one();
                else
                        ws2812b_send_zero();
                bit>>=1;
        }
}

void
ws2812b_send_rgb(uint8_t r, uint8_t g, uint8_t b)
{
        ws2812b_send_color(g);
        ws2812b_send_color(r);
        ws2812b_send_color(b);
}

I haven’t really put any effort into optimizing this. I suppose it might be possible to pre-generate a pattern and blow the whole thing out the SPI but I wasn’t in the mood. What I’ve got works fairly well.

Here it is in action

Code is available here

How to reboot a DLink router from a script

By   November 7, 2015

I have a Dlink DIR-615 that periodically drops its connection to the outside world. It appears to coincide with my wireless provider going down but the DLink never recovers. I don’t know why; but whatever.

I was going to use a relay Phrob to just power cycle it but figured I’d explore doing a soft reboot since that appears to bring the connection back up. Because the HTTP foo is not strong within me, I searched and found this article which gave me the basic steps required to login to a DLink and reboot it. It didn’t work and I didn’t need to append a “A” to the password; but after some futzing and looking at the POST headers in Google Chrome, I eventually reached this script that I put in cron:

#!/bin/sh
# Check whether we can see google's DNS, if not, login to the router and reboot it.
ADDR=192.168.34.3
ADMIN_PASS="Zm9vCg=="

ping() {
        echo Pinging;
        ping -q -c 1 -n 8.8.8.8 >/dev/null && exit 0
}

login() {
        curl -o - -X POST -d "html_response_page=login.asp&login_name=YWRtaW4A&login_pass=$ADMIN_PASS&graph_id=5190c&&log_pass=$ADMIN_PASS&graph_code=&login=Login" http://$ADDR/login.cgi | grep index.asp
}

reboot() {
        echo "Rebooting ... " ;
        curl -X POST -d  "html_response_page=reboot.asp" http://$ADDR/reboot.cgi
}

ping || (login && reboot)

In order to encode your $ADMIN_PASS, you need to:

$ echo -n MYPASSWORD | base64

The ADMIN_PASS=”Zm9vCg==” above is what you’d get if your admin password was “foo”.

This works on my DIR-615, Hardware Version E3 and Firmware Version 5.10. Hope it helps someone.

tftpd and xinetd on Ubuntu

By   May 10, 2015

I’ve been doing embedded for a long time but I’ve been doing unix admin stuff for way longer. I’ve probably been using inetd and tftp for 25 years. I’m always shocked at the ability for tftp to take up a couple hours of time the first time you want to get it running on a host.

When doing embedded, I typically like to point tftpboot at my compiler output directory which saves a copy step. Sometimes you forget to copy and you can’t figure out why your printf()s aren’t showing up (because you’re still running an old version).

Anyway, on Ubuntu, you typically install xinetd and tftpd…

sudo apt-get install xinetd tftpd

Then you want to create /etc/xinetd.d/tftpd :

service tftp
{
        disable         = no
        socket_type     = dgram
        protocol        = udp
        wait            = yes
        user            = hpeyerl
        server          = /usr/sbin/in.tftpd
        server_args     = -s /home/hpeyerl/trunk/firmware/esp8266
}

Then poke xinetd:

$ sudo pkill -1 xinetd

I always like to debug by using tcpdump:

06:11:42.796755 IP (tos 0x0, ttl 255, id 4, offset 0, flags [none], proto UDP (17), length 56)
    192.168.37.249.69 > 192.168.37.30.69:  28 RRQ "/images/antares.rom" octet
    0x0000:  4500 0038 0004 0000 ff11 ef48 c0a8 25f9  E..8.......H..%.
    0x0010:  c0a8 251e 0045 0045 0024 c8b6 0001 2f69  ..%..E.E.$..../i
    0x0020:  6d61 6765 732f 616e 7461 7265 732e 726f  mages/antares.ro
    0x0030:  6d00 6f63 7465 7400                      m.octet.
06:11:42.799663 IP (tos 0x0, ttl 64, id 8086, offset 0, flags [DF], proto UDP (17), length 49)
    192.168.37.30.42622 > 192.168.37.249.69:  21 ERROR EACCESS "Access violation"
    0x0000:  4500 0031 1f96 4000 4011 4ebe c0a8 251e  E..1..@.@.N...%.
    0x0010:  c0a8 25f9 a67e 0045 001d cc96 0005 0002  ..%..~.E........
    0x0020:  4163 6365 7373 2076 696f 6c61 7469 6f6e  Access.violation
    0x0030:  00                                       .

Sometimes syslog is helpful:

May 10 06:03:57 pm001 in.tftpd[4564]: connect from 192.168.37.30 (192.168.37.30)
May 10 06:03:57 pm001 tftpd[4565]: tftpd: trying to get file: antares.rom
May 10 06:03:57 pm001 tftpd[4565]: tftpd: serving file from /srv/tftp

The key there is “/srv/tftp”… Since there’s no mention of /srv/tftp in your xinetd.d config file, something else must be happening…

So, here are some gotchas that will consume some debug time:

  • If you’re testing this by using tftp on the same host as tftpd, you won’t see anything in tcpdump because the packets are short-cutting through your localhost interface.
  • On Ubuntu, there is also an /etc/inetd.conf which is your culprit:
#:BOOT: TFTP service is provided primarily for booting.  Most sites
#       run this only on machines acting as "boot servers."
tftp           dgram   udp     wait    nobody  /usr/sbin/tcpd  /usr/sbin/in.tftpd /srv/tftp
  • tftpd is very picky about permissions. You might be tempted to make every element in your path 777, I don’t need to tell you this is a bad idea.

How to auto start Wifi hotspot on Android 4.4.4

By   October 24, 2014

How to auto start Wifi hotspot on Android 4.4.4

I got a broken Nexus-7 and wanted to use it as a router up at DebtRidge. I wanted it to come up as a wifi hotspot automatically when booted. This means the ‘hostapd’ daemon needs to be started automatically. So here’s what I did.

  • Unlock the bootloader
  • Root the tablet and install SuperSU
  • install busybox
  • install init.d

The above is outside the scope of this article. There’s already lots of fine articles that tell you how to do all that.

Once you can get a terminal prompt or adb shell and su, you can proceed.

  • setup the Wifi hotspot in Settings. This will generate a file called /data/misc/wifi/hostapd.conf. It looks something like this:
interface=wlan0
driver=nl80211
ctrl_interface=/data/misc/wifi/hostapd
ssid=drgate
channel=6
ieee80211n=1
hw_mode=g
ignore_broadcast_ssid=0
wpa=2
rsn_pairwise=CCMP
wpa_psk=115dfdf3a3c63c3692b5cfaf0ad73234e89a1e7b70037fd5cfcdcd2d608a6bc9

Since init.d is run in /data/install-recovery-2.sh, it runs too early in the boot process for hostapd to start. Another issue is that hostapd won’t run if Wifi is enabled. However, if Wifi hasn’t been enabled, the wlan driver isn’t loaded and hostapd isn’t able to bind to wlan0 because it doesn’t exist. So I had to find a way to load the wifi drivers so that hostapd would come up.

I discovered that I can run “svc wifi enable” to install the drivers and bring up the wlan0 interface. Then “svc wifi disable” would bring down the wlan0 interface but leave the drivers installed. At this point, hostapd was perfectly happy.

So to bring this all together, I needed a script that could be launched at boot time that would delay the starting to hostapd until later in the boot process. Here’s what I did.

su
mount -o rw,remount /system
cd /system/etc/init.d
cat > 50hostapd
#!/system/bin/sh
/data/start_hostapd.sh &
^D
chmod 755 50hostapd

Now install the following script as /data/start_hostapd.sh:

#!/system/bin/sh
while true; do
    su -c svc wifi enable
    sleep 1
    netcfg | grep wlan0 && break
    sleep 10
done
su -c svc wifi disable
sleep 2
/system/bin/hostapd -e /data/misc/wifi/entropy.bin /data/misc/wifi/hostapd.conf &

Then:

chmod 755 /data/start_hostapd.sh

and you should be good to go.

root@deb:/ # ps | grep hostapd
wifi      1282  1     2416   1000  c0138fe4 b6ee46d8 S /system/bin/hostapd