The problem

Analysis

Every button is a simple mechanic thing which shortcuts two leads. Modern electronic devices do not employ high current or voltages through these leads so a simple optocoupler should be a suitable electronically controlled equivalent. On the server side the simplest device we have is a serial port and more particularly, its handshake lines termed DTR and RTS which can be controlled by standard UNIX I/O control calls (ioctls). The RS232 line drivers on the VIA EPIA CL6000 are all gd75232 chips which limit the output current: the driver can deliver about 12mA and won't fry upon a short circuit (umm, don't try this with many lines at the same time). In order to avoid spurious resets we put a charge circuit in between: we'll need a special sequence to arm the reset circuit.
Measurements on the modem revealed that a "power off" pulse must be at least four seconds long. A power on pulse must be at least 0.1 second long. There is a magic sequence of reset button presses while it is setting up the ATM link with the peer which will restore the factory default setting. So, we do not want to generate a reset pulse too often too soon ;-)

Wire the reset button (warning: this will probably void the warranty)

The last picture shows the reset button, bottom PCB view. Voltage across reset button: 3.222V, short circuit current is 0.3mA. One lead has about 0.001V and the other lead 3.224V. The latter is connected to both pin 4 (1!SD) and pin 14 (Vcc) of a 74LVC74A flip-flop. These leads need to be connected to (for example) a TIL111 opto-coupler. It is best to put the optocoupler inside the modem as well:

Circuit which connects the TIL111 opto-coupler to a serial port:

Software (/usr/sbin/st510)

#!/usr/bin/env python
# power on/off an Alcatel Speedtouch 510 modem using some circuitry
# controlled via RTS/DTR

from os import open, O_RDONLY
from sys import argv, stderr, exit
from termios import TIOCMBIS, TIOCMBIC, TIOCM_RTS, TIOCM_DTR
from fcntl import ioctl
from select import select
from struct import pack
from time import sleep

if argv[1:] == ['on']:
	time = 0.02	# >=0.01
elif argv[1:] == ['off']:
	time = 5.0	# >=4.0
else:
	print >>stderr, "Usage: st510 on|off"
	exit(1)

rts = pack('I', TIOCM_RTS)
dtr = pack('I', TIOCM_DTR)
fd = open('/dev/ttyS2', O_RDONLY)
# opening a serial line will assert RTS and DTR but we should not rely on that.
ioctl(fd, TIOCMBIS, rts)

# Charge up the capacitor. This mechanism avoids random resets when
# pulling plugs or powering the system on- and off.
#
#   50 pulses		-
#  250 pulses		10 sec reset possible starting at 3mA
#  500 pulses		15 sec reset possible starting at 4mA
# 1000 pulses - 10.5V	18 sec reset possible starting ar 5mA
#
# 250 pulses will do, 500 works but to stay on the safe side...
for i in range(1000):
	ioctl(fd, TIOCMBIC, dtr)
	select([], [], [], 0.001)
	ioctl(fd, TIOCMBIS, dtr)
	select([], [], [], 0.001)

# Capacitor charged up, DTR is set. fire by clearing RTS
ioctl(fd, TIOCMBIC, rts)
select([], [], [], time)
ioctl(fd, TIOCMBIS, rts)

# if we close fd within 25 seconds then the remaining capacitor charge may generate
# another reset pulse when RTS goes down.
# This could switch the modem back on when we are supposed to switch it off. The other
# way around it gets even worse: when the reset is pressed a number of times while
# the modem has just been switched on it will reload the factory settings (consult the
# manual about the exact reset sequence for this). So, we're anal and wait a full minute.
sleep(60)

How to determine if your modem needs a reset (/usr/sbin/st510-status)

#!/bin/sh
# Determine if our Alcatel speedtouch ADSL modem may need a reset.

ret=1

for ip in `sed -n 's/^nameserver//p' /etc/resolv.conf`
do
	# TTL 1 is eaten by the modem
	# TTL 2 is eaten by its ATM peer which may be affected by a modem reset.
	# try 3,4,5
	x=`traceroute -n -m 5 -f 3 $ip 2>/dev/null | grep -v '\* \* \*'`
	if [ -n "$x" ]
	then
		ret=0
		break
	fi
done
exit $ret

Checking this hourly (/etc/cron.hourly/st510)

(note: I have an "internet" startup script which issues an "st510 on" upon powerup)

#!/bin/sh

st510-status && exit

# try to switch it on -- shouldn't be necessary as /etc/rc.d/init.d/internet
# does this as well at startup (e.g. when power has been restored).
echo "Powering on st510"
st510 on
sleep 100
st510-status && exit
echo "st510 not ok"

# the hard way
echo "Powering off st510"
st510 off
echo "Powering on st510"
st510 on

# nothing else we can do -- we'll come back in an hour

Valid HTML 4.01!