Thursday, April 17, 2014

Fixing a bricked TP Link Ethernet-over-Power Adapter

Though I have Wifi coverage throughout my home, for better bandwidth and lower latency/packet loss, I also run a Ethernet over the electric line (230VAC) using the Ethernet-over-Power (EoP) adapters. I have been using this for few years for high-speed connectivity across different rooms without having to lay new Ethernet cables. (eg., my home theatre system connects to my NAS via EoP to play HD videos without jitter over network).

This is the exact model I use:



One of them went dead last year, so I had to buy 2 more to provide enough coverage. They aren't that cheap and aren't available in India directly (though I could import via ebay or amazon). Few months back, another one went dead. When I say dead, it would not power on, when you connect to the power line; no LEDs will glow and will be functionally dead as well. 

This wasn't scaling (I can't keep buying new ones) and I didn't know what was wrong so I can prevent this. As it was anyways dead I decided to break it open and figure out what had happened (maybe just a fuse blown?). That's where it all started.

Unfortunately I don't seem to have photos during the disassembly (not sure why I didn't shoot). This was one of the hardest disassembly ever, for me. It is meant not to be opened. There is one screw at the back (hidden under a sticker). Unscrewing that doesn't do much, although required. The packaging is very rigid, you can't even break it easily. I drilled a small hole on this, using a Bosch drilling machine to peek in a bit :D yes, it was a risky thing to do. The white cover is locked on to the black case with notches in the sides -- I had to peek into the the heat vents to figure this out.  Using a thin screw driver as wedge, I could open the white cover revealing the mother board inside.

It runs of a proper ARM-based Atheros chip, along with a (expected) RealTek chip for Ethernet support. I could only see the top of the board, and most of the board's soldering was not accessible at this point, so I couldn't test any of the circuitry for faulty parts. I had to take the board out. Be careful if you are doing this -- as I figured out later that the board had been glued to the black case below; so it wouldn't come off the case easily. You need to apply force along the sides and take it off. There is no other screw, I can tell you now (this was my biggest scare, that if I miss a screw, the force might break the board).

With quite some struggle and care, I took the board off the case. This is how the back of the board looks:


Arrows in yellow, show the gum that was holding the board to the case. At first, I even thought if this was some sort of leakage from the underlying components.

This is how the top side of the board looks (yellow wire was soldered by me to test the board outside):


The arrow on the left points to the fuse. I tested for continuity and it looked ok. Then started testing  each capacitor. The 3 capacitors at the bottom right were seeming to be faulty (short on DC). I was a bit surprised to see all 3 capacitors being blown -- on further investigation, they were in parallel in the circuit and even one faulty capacitor could project all 3 to be faulty. When I looked at the back side of the board (red-rectangle as in the backside-view picture), I could see some leakage on one of the capacitors. The capacitor also had a slight bulge at its top (no photo). I was more hopeful then. On soldering out the capacitor, off the board, the other two capacitors tested normal -- Good!

This was the faulty capacitor:





Now I need to get a spare cap with the same spec. Ebay India came to rescue. Ordered 10 capacitors 1500uF/10V and were delivered in 3 days.

The above top-side picture actually shows the board with the new capacitor replaced. Packed it in and did one final round of testing before I packed it into its box.


Test success. And here it is the final working version back in action:




And that's how I fixed a TP link EoP adapter for Rs.10 :)

If you have one such dead one, give it a try. It is likely this cap issue.

Sunday, November 10, 2013

Fixing Raspberry Pi filesystem corruption

While Raspberry Pi is a computer in its core, it is treated like an embedded device in most cases -- we can't expect a proper shutdown of Pi in most cases. This results in corruption of the / (root) file system (ext4) due to unclean unmount. 

In case you have been reinstalling Pi on to the sdcard every time this happens, you don't really have to reinstall. In most cases, mount the card via a card reader and run 

sudo fsck.ext4 /dev/xxxx  [xxxx the device file of the root partition]

(I assume linux by default). This should fix the / file system and the card will let your Pi boot now. If this doesn't help, try fixing the /boot partition:

sudo fsck.vfat  /dev/xxxx  [xxxx - the device file of the boot partition]

That said, you don't really have to do this. The clean and guaranteed protection against this problem could be provided by mounting the filesystem as read-only. Thus the filesystem is completely intact and will have no chance of corruption. In most cases, this should be fine (unless you have a reason to persist something on to the root filesystem). If you still need to write something to disk, write it to a different partition so it doesn't prevent Pi from booting if that goes corrupted.

How to mark the / and /boot partitions read-only:

You could do this from Pi itself, or on a different machine. Just edit /etc/fstab and add 'ro' in the flags as shown below:

/dev/mmcblk0p1  /boot       vfat    defaults,ro                0       2
/dev/mmcblk0p2  /           ext4    defaults,ro,noatime        0       1

Now reboot the Pi and it should boot with both these mount points in read-only mode. You could do a mount to verify, it should look something similar to this:

/dev/root on / type ext4 (ro,noatime,data=ordered)
devtmpfs on /dev type devtmpfs (rw,relatime,size=216108k,nr_inodes=54027,mode=755)
tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=44876k,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /run/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=89740k)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620)
/dev/mmcblk0p1 on /boot type vfat (ro,relatime,fmask=0022, dmask=0022, codepage=cp437, iocharset=ascii,shortname=mixed, errors=remount-ro)
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,relatime,size=89740k)

Note: Some services (like apache2) might fail to start, because they can't write to disk. You might have to check individual services to figure out what they are trying to write and resolve it appropriately. For eg., apache2 writes log files /var/log/apache2. It is best to disable logging. If there is not too much logging, you could map the log folder to /tmp (tmpfs -- as shown in mount).

as root:
mkdir /tmp/apache2 
chmod a+wx /tmp/apache2 
cd /var/log
rm -rf apache2
ln -s /tmp/apache2 apache2

There is no worry of file system corruption any more. You could switch off Pi any time. I have been using this setup (in my PowerStrip Project) for many months now, without issues.

Sunday, May 12, 2013

SSH to Raspberry Pi first time without keyboard/monitor

Applies to "wheezy" version, not sure about other versions.
 
Raspberry Pi is mostly used as a remote machine and usually not tied up with any keyboard or a monitor, as in my case. Whenever you reimage a version of Raspberry Pi, connecting through ssh doesn't work.

Raspberry Pi's latest images come with "sshd" enabled by default. However, during first boot, "raspi-config" script (from /etc/profile.d/raspi-config.sh) kicks in and throws up a UI on the screen for the user to respond. This doesn't timeout and doesn't let the boot sequence complete; you would notice that Rsbpi has joined the network, but one cannot ssh to it (as the startup is stuck at this script and sshd is not started yet).

Workaround:
Once you reimage the SD card, mount the ext4 partition just created on the card. This will give access to the root (/) filesystem of the "wheezy" linux. Comment out the following line from /etc/inittab on that / filesystem:

1:2345:respawn:/bin/login -f root tty1
/dev/tty1 2>&1 # RPICFG_TO_DISABLE

This disables auto-login of root and raspi-config doesn't run until an interactive login happens as root. Now you can boot the SD card on Rsbpi and you should be able to ssh to it. 

Worked for me!

Saturday, April 13, 2013

DIY: Raspberry Pi controlled Power Strip - Part 1

This post will cover some behind-the-scene details on what went behind making this power strip. Had been quite busy for a while, so couldn't make it earlier.

There were few questions that I had to answer before I was sure I could build this:
  1. How do I control 220V AC from an electronic circuit, safely? Can I do it right the first time so I don't blow up the raspberry Pi? Being completely a software guy, this was a challenge. This was the first part of the problem I solved as shown in my earlier post on Controlling 220v Bulb using Raspberry Pi.
  2. Can I fit this whole solution seamlessly into an existing power strip so it has a clean form-factor and intuitive to use? Finding one such power strip which had enough space to hold additional circuits was a challenge.
  3. Building software so I can remotely control the power strip over any device. I decided to go the web interface route, so I can do it easily from any device. The software I eventually implemented is based on RESTful APIs, so it would also be easier for me to write an Android app or any other app over this interface.

Controlling 220V AC from Raspberry Pi

 

One of the foremost requirements for choosing Raspberry Pi was that it has programmable GPIO (General Purpose Input / Output) headers, without which any electronic interfacing would be pretty difficult and inefficient. Most micro-controllers (including modern microprocessors do provide GPIO pins) for interfacing with other low-level hardware peripherals. The voltage on a GPIO PIN can be controlled by instructing the micro-controller. Usually a TTL low/high is used to signal 0 or 1. But it is totally up to the interface to decide how to interpret it. Raspberry Pi uses 3V3 TTL, which means a 3.3V for high and 0V for low. Specially when you are using the GPIO pins for input, make sure the voltage doesn't exceed 3.3V. For the power strip, it is only in output mode.

Relay is another important component. It is an electro-magnetic switch that is used to turn on or off the high voltage. Relays require slightly higher voltages (>=12V) to work. When there is enough current flow, an electro-magnetic coil gets magnetized and pulls off a lever to turn on the switch. When the power is switched off, there is no magnetic field, and a mechanical spring pulls it back to its original position. Relay is a mechanical device and might suffer some latency and noise during its operation. It is not meant for high-precision control, but in my case this is good enough.

Since relays work on higher voltages and that it requires substantial current, a relay cannot be driven directly from a Raspberry Pi. It is very common to use a transistor as a switching device to turn on slightly higher voltages and/or when you need more current. This allows us to withdraw very less current (only the base current) from the controlling source (in our case Raspberry Pi) and to use a completely different power source (>=12V) for the controlled device (in our case, a relay). I have plugged in a 12V power adaptor which provides sufficient current to turn on/off the relay.

This is the circuit that drives a single relay: (The core idea of this circuit is a very common circuit that is used to control a relay via a transistor. I have customized it to appeal for the given use case.)


Remember that Raspberry Pi runs off USB power. Model B has a cap of 700mA in the inlet and this current is used for the complete functioning of Raspberry Pi. Any current that we draw out of this, is expensive and we need to be cautious. Specially if you are planning to drive a load (say a LED) directly, without using a different power source. 

WARNING: As I learned, there is no fuse of any sort behind the GPIO headers -- so any incorrect use might blow the micro-controller, thereby making a Raspberry Pi brick. Take extreme precautions and ensure that you are fine with the current you draw/sink from/into the GPIO.

The GPIO18 is just one of the many GPIO pins that could drive this transistor. To turn it on, my code will set a HIGH on that pin, thereby raising the voltage on that pin to 3.3V. With the required V-BE (the base-emitter voltage) at 0.7V to turn on, for the 4.7KOhm base resistor, the transistor will just draw around 0.5mA current from the raspberry Pi. Even when multiple relays are ON, there is no risk of over-drawing current from Raspberry Pi. The Diode D1 provides protection against any reverse current that could occur at the moment the relay is switched off.

Raspberry Pi has a GPIO python library that we can use to control the GPIO pins with ease. By being able to control from python, I didn't have to go through the pain of cross-compiling every time I modified any code.

Snip of code:
#
#initialization
#
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM) # use BCM pin numbering
GPIO.setup(gpio_pin_number, GPIO.OUT) # mark for output

#end of initialization; following could be called multiple times.

GPIO.output(gpio_pin_number, GPIO.HIGH) # output high / 3.3v
GPIO.output(gpio_pin_number, GPIO.LOW) # output low / 0v
#
As simple as that. Based on the command issued remotely, my power strip daemon would choose the right gpio_pin_number and set it to HIGH or LOW appropriately.

This post is getting long :). So, more about the packaging of the relay board, associated software design, in the subsequent posts.

Sunday, February 17, 2013

Home Automation - Raspberry Pi controlled Power Strip

Watch my previous post on a prototype project using Raspberry Pi. Now you would know what was that prototype for.

Yes, I now have built a power strip that is completely controllable by a Raspberry Pi over network. 

The idea of controlling a power strip over network is nothing new, but this is certainly a unique one and I needed this badly.  I have built a power strip with more features than the off-the-shelf ones and they were at least twice as expensive as what it took me to build this one. I can fix any problem in this device from software to a relay to a resistor -- in case any of these is blown. Oh yeah, the happiness of building something yourself is invaluable :)

To me, one of the driving factors for such a device is: We have Tata Sky+ HD at home and we record TV programs left and right. It has almost reached a point that we don't watch live content except news (for the time comfort and sake of skipping ads). Many interesting series do come in the night, for which, we leave the set-top-box (STB) on -- naturally for prolonged time (till morning) even if the recording is just for an hour or so in the midnight. Tata Sky+ HD STB consumes 20+W of power even on standby. I wanted to avoid this waste of power, by having the ability to turn on/off the power sockets using a rather low power device.

Raspberry Pi consumes just around 3.5W and has complete networking support. With abundant GPIO pins, I can use it to control at least 8 different sockets. This is one of the main reasons for me to choose a Raspberry Pi. While I had worked on AVR based micro controllers, but getting a AVR board on the network would have been much more difficult than this. Also the power of Linux, provides numerous software that were of great use to me while building this (python, apache2, flask etc.,)

Some of the key features:
  • Power Sockets are controllable via a web interface, so available from any device on the network.
  • Web service supports REST based interaction for easy integration with any app that I might write in the future (at least for the android phones).
  • Core web and daemon logic on python that avoids cross-compilation work for Rs Pi architecture. Rewrite code easily and just drop it for deployment. This was awesome! God bless interpretors!
  • Ability to control sockets from the Internet once I VPN into my home network. (this should let us do the recording even when we are on vacation; how cool is it that I can turn a socket in Bangalore on or off, from anywhere in the world)
  • Timer support, so I can schedule a On or Off event after a while. Say, I can turn on a socket at midnight 12am, run it for an hour and turn it off! There is a dedicated power daemon that runs in the background to take care of scheduling these requests when its time.
  • The power sockets are still controllable using their dedicated switches, so you don't have to hunt for a browser to turn on the sockets.
Here is the power strip in action:



I have also now installed the power strip for the real purpose I wanted for. See the demo where I turn OFF my Tata Sky+ HD Set Top Box using the mobile.



I have taken photos all the way while I built this power strip. Stay tuned for lot more technical details (electronic circuits, hardware, software) with photos, on what went behind this power strip.

Sneak peek:

 

Thursday, January 31, 2013

Controlling 220v Bulb using Raspberry Pi

I have always had this excitement to control high-voltage devices from electronics. I could never do one because of lack of hardware and/or the scare for dealing with high voltage and getting it right the first time. Finally, I now have a proof of concept project that controls a 220v bulb from a Raspberry Pi. More details, maybe in a later post. Right now, I need to build a better actual project with this :) 

Raspberry Pi runs on Raspbian Wheezy linux and the controlling code is written in Python.

Thursday, December 13, 2012

WDTV Live -- Firmware Hacking Series -- Part 3

Patching custom rootfs onto existing firmware


Once you have the serial cable built as mentioned in my previous post, it is possible to patch the current firmware installation with custom rootfs, without having to upgrade/reinstall the whole firmware with custom one.

These are the high-level steps that we need to do:
  1. Discover the partition table and identify where the rootfs is stored in the flash storage.
  2. Read the rootfs of the current firmware and push it to a different machine.
  3. Modify the rootfs to your needs, on the other machine.
  4. Upload it back to WDTV and write the flash partition appropriately.

Discovering the rootfs partition

~ # mount
rootfs on / type rootfs (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
/dev/sigmblockh on / type cramfs (ro)
none on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
usb on /proc/bus/usb type usbfs (rw)
mdev on /dev type tmpfs (rw)
devpts on /dev/pts type devpts (rw)
none on /tmp type tmpfs (rw)
/dev/loop0 on /tmp/static_config type minix (rw)

Note the highlighted line. /dev/sigmblockh device is the one mounted as / partition. To confirm print the first 100 bytes on the device and you could notice the CRAMFS header.

~ # hexdump -c -n 100 /dev/sigmblockh

0000000   E   = 315   (  \0   @ 021 003 003  \0  \0  \0  \0  \0  \0  \0
0000010   C   o   m   p   r   e   s   s   e   d       R   O   M   F   S
0000020 234 333 016 324  \0  \0  \0  \0   k   &  \0  \0 313 016  \0  \0
0000030   C   o   m   p   r   e   s   s   e   d  \0  \0  \0  \0  \0  \0
0000040 355   A 354 003   D 001  \0   d 300 004  \0  \0 355   A 354 003
0000050 354  \v  \0   d 001 031  \0  \0   b   i   n  \0 377 241 354 003
0000060  \t  \0  \0   d                                                
0000064
~ # 
We still need to know the exact flash disk and the partition to which this device points to.

~ # ls /dev/sigm* -l
brw-rw----    1 root     root     254,   0 Jan  1  2000 /dev/sigmblocka
brw-rw----    1 root     root     254,   1 Jan  1  2000 /dev/sigmblockb
brw-rw----    1 root     root     254,   2 Jan  1  2000 /dev/sigmblockc
brw-rw----    1 root     root     254,   3 Jan  1  2000 /dev/sigmblockd
brw-rw----    1 root     root     254,   4 Jan  1  2000 /dev/sigmblocke
brw-rw----    1 root     root     254,   5 Jan  1  2000 /dev/sigmblockf
brw-rw----    1 root     root     254,   6 Jan  1  2000 /dev/sigmblockg
brw-rw----    1 root     root     254,   7 Jan  1  2000 /dev/sigmblockh
brw-rw----    1 root     root     254,   8 Jan  1  2000 /dev/sigmblocki
brw-rw----    1 root     root     254,   9 Jan  1  2000 /dev/sigmblockj
brw-rw----    1 root     root     254,  10 Jan  1  2000 /dev/sigmblockk
brw-rw----    1 root     root     254,  11 Jan  1  2000 /dev/sigmblockl

The highlighted line shows the major, minor numbers for this device. As you might know, the minor number is the partition number on the disk. In this case, the rootfs is stored in the 7th partition.

To understand where is the 7th partition stored in the flash disk, we need to know the partition information of the internal flash disk. This could be obtained in two different ways. Either by looking at the logs during WDTV boot (via serial port) or by issuing the following command at the terminal (via serial again).

~ # cat /proc/sigminfo 

dev:       size     offset   name        CS
sigmblk0:  0ff80000 00000000 "CS0-Device" 0
sigmblk1:  00080000 00000000 "CS0-Part1"  0
sigmblk2:  00040000 00080000 "CS0-Part2"  0
sigmblk3:  00300000 000c0000 "CS0-Part3"  0
sigmblk4:  00300000 003c0000 "CS0-Part4"  0
sigmblk5:  01000000 006c0000 "CS0-Part5"  0
sigmblk6:  00800000 016c0000 "CS0-Part6"  0
sigmblk7:  05a00000 01ec0000 "CS0-Part7"  0
sigmblk8:  05a00000 078c0000 "CS0-Part8"  0
sigmblk9:  00020000 0d2c0000 "CS0-Part9"  0
sigmblk10: 00020000 0d2e0000 "CS0-Part10" 0
sigmblk11: 00020000 0d300000 "CS0-Part11" 0

We are almost there now. This shows the starting offset (0x01ec0000) and the size (0x05a00000) of the partition. That is a 90MB partition reserved for rootfs ie., the compressed cramfs partition cannot exceed 90MB.

Read rootfs and export to different machine


This is required as we need to patch the rootfs of the installed firmware. Press 0 (via the serial port) and restart WDTV Live. This will prevent loading the firmware and will stop boot at booloader YAMON. 

Follow my inline comments in the script below.
[Gerald] Plugin an Ethernet cable connected to a valid network. 
[Gerald] net init, initializes the interface and runs DHCP client.
YAMON> net init

Ethernet driver for SMP86XX (v1.0)
(MAC 00:90:xx:xx:xx:xx)
em86xx_eth0 - full-duplex mode
em86xx_eth0 - 100 Mbit/s
em86xx_eth0 ethernet start
DHCP was successfully configured.
ipaddr:     192.168.8.104
subnetmask: 255.255.255.0
gateway:    192.168.8.2 
[Gerald] 'nflash read' command is used to read from the flash memory.
[Gerald] Based on the discovery earlier, the following command reads
[Gerald] first 0x1e00000 bytes into memory at 0x8400000.
[Gerald] syntax: nflash read flash_address memory_address size chip_select
[Gerald] chip_select (CS) is available in the partition info at /proc/sigminfo.
[Gerald] Note: Use only 0x84000000 as target. Other addresses didn't let me read
[Gerald] 0x1e00000 bytes at once.Even here, I couldn't read the complete 0x5a00000 
[Gerald] bytes at once.
YAMON> nflash read 0x01ec0000 0x84000000 0x1e00000 0 

[Gerald] Verify if this has indeed read the CRAMFS from flash. 
YAMON> dump 0x84000000 100

84000000: 45 3D CD 28 00 40 11 03 03 00 00 00 00 00 00 00  E=�(.@..........
84000010: 43 6F 6D 70 72 65 73 73 65 64 20 52 4F 4D 46 53  Compressed.ROMFS
84000020: 9C DB 0E D4 00 00 00 00 6B 26 00 00 CB 0E 00 00  .�.�....k&..�...
84000030: 43 6F 6D 70 72 65 73 73 65 64 00 00 00 00 00 00  Compressed......
84000040: ED 41 EC 03 44 01 00 64 C0 04 00 00 ED 41 EC 03  .A..D..d�....A..
84000050: EC 0B 00 64 01 19 00 00 62 69 6E 00 FF A1 EC 03  ...d....bin..�..
84000060: 09 00 00 64                                      ...d 

[Gerald] upload the file to a tftp server of your choice.
[Gerald] syntax: fwrite tftp_path memory_address size 
YAMON> fwrite tftp://192.168.8.101/sigh/sigh.dump.1 0x84000000 0x1e00000

About to binary write tftp://192.168.8.101/sigh/sigh.dump.1

Successfully transferred 0x1e00000 (10'31457280) bytes 

[Gerald] Read the next 0x1e00000 bytes from flash and upload to TFTP
YAMON> nflash read 0x03cc0000 0x84000000 0x1e00000 0

YAMON> fwrite tftp://192.168.8.101/sigh/sigh.dump.2

About to binary write tftp://192.168.8.101/sigh/sigh.dump.2

Successfully transferred 0x1e00000 (10'31457280) bytes

[Gerald] Read the next 0x1e00000 bytes from flash and upload to TFTP 
YAMON> nflash read 0x05ac0000 0x84000000 0x1e00000 0

YAMON> fwrite tftp://192.168.8.101/sigh/sigh.dump.3

About to binary write tftp://192.168.8.101/sigh/sigh.dump.3

Successfully transferred 0x1e00000 (10'31457280) bytes

YAMON> 

Modify the rootfs to your needs


At this point, we have three 30MB files and concatenating them in order, should give a complete cramfs partition. You could now extract the cramfs partition (using modified cramfsck, as mentioned in my earlier post) and make the necessary modification.

I have the following section of script added to the /init script, that gets control to my USB script as root. This lets me run scripts on startup and modify them as required, without having to reflash anything. Don't forget to update the /md5sums.txt file with your updated md5sum.
# Gerald - update - start
if [ -f /tmp/media/usb/wdtv/gerald_init ]; then
    /tmp/media/usb/wdtv/gerald_init &
# Gerald - update - end 
Use the modified mkcramfs (as mentioned in my earlier post) to repack the rootfs into a cramfs filesystem file. Split the file into three 30MB files (note: you may need to append zeros at the end to fill up to 30MB in the third part -- your cramfs filesystem is likely to be < 90MB).

Upload back to WDTV and write the flash partition appropriately


Boot into YAMON. Use 'fread' to read from tftp to memory at 0x84000000. Use 'nflash write' to write the parts into their correct flash locations starting at 0x01ec00000. Once all 3 partitions are written, just reboot. Your new rootfs should be active.

By now, you would no longer be worried about what to do if that doesn't boot. Good luck!