Rusty Engineering Skills

I’ve been involved with IT since leaving college slightly over 30 years ago and for a couple of years before that, when I got swept up in the illegal CB radio craze in my mid to late teens, I used to supplement my pocket money as one of the local ‘rig doctors’, mostly replacing output stage transistors for people who did mad things like trying to use a metal coat hanger or their standard car radio aerial on 27MHZ. Perhaps if the muse takes me one day, I’ll write an article about the little cottage industry myself and one of my CB buddies (who was a BT RF engineer at the time) had going with rig repairs and home brewed accessories.

Computers have almost always (in my lifetime at least!) been so much easier to work on than transceivers, because the fix for most faults is a complete replacement of a self-contained component rather than a board-level repair. Ironically, though, the last 2 major faults that have befallen our main computer at home have required me to get my soldering iron out, which has had a certain nostalgia value about it, not to mention the fact that the second soldering iron episode highlighted just how out of practice I’ve got with the basic fault finding skills that I learned in my teens whilst repairing other peoples CB radios.

The first problem occured during what passed for the summer in 2012. The 22-inch LCD monitor which I’ve had for some time finally gave up the ghost, after a couple of weeks of needing to be switched off and back on again several times in succession in order to get a stable picture. I’d resigned myself to having to buy a replacement and was all set to take it to our local council waste site for proper disposal. Since I know very little about how TVs and computer screens actually work, I thought it might be educational to take it apart and see what was inside it. After removing 12 screws to take the back off and disconnecting the ribbon cable to the LCD panel, I was slightly disappointed to find just 2 fairly bland circuit boards. The smaller of the two had just 3 or 4 VLSI or very large scale integrated circuits on it and virtually no other components, so I assumed that it was the bit that did the job of decoding the digital video signal from the PC and putting it on the 1680×1050 screen. To my surprise, the larger board was quite clearly a switched mode power supply. To my further surprise, the fault was immediately obvious purely based on a visual inspection. There were 5 radial lead electrolytic capacitors at one end of the board, all of the mega-cheap chinese import variety. Each of these was bowed outwards quite significantly at the top, indicating that they had almost reached the point at which the magic smoke would leak out.

Swiftly bringing to bear my noble soldering iron of justice, I soon had the suspect components on the bench in front of me. They were all 100uF 16v, it was 4:20pm on a Sunday afternoon and my local branch of Maplin was still open for another 40 minutes. Ignoring the cries of “What do you mean you’re going to try to fix it?” from my wife, I jumped in the car and headed to the aforementioned purveyors of electrical and electronic components.

Some time later and the princely sum of £2.75 spent, I had a bag of 5 replacement capacitors, a hot soldering iron and a somewhat incredulous wife and mother-in-law, both with slightly worried looks on their faces. Not to be deterred, I spent the next few minutes carefully desoldering the pads where the original components had been mounted, soldering the new capacitors in place and trimming back the leads to make a neat job. I managed to put the monitor back together without having any parts left over and was feeling quite pleased with myself and my out-of-practice engineering skills, announcing that I was ready to test my repair and see if it had ‘done the trick’.

At this point, my wife suggested that if I was planning to put myself at risk of electrocution, it would be best to do so in the back garden rather than clutter up the house with my scorched and blackened corpse. Ever the obedient husband, I took the computer, keyboard and mouse outside along with an extension lead, the newly repaired monitor and a VGA cable. This was all deposited on the patio table and connected together as appropriate. Upon gingerly applying mains power, I was delighted to see the monitor come up as normal on the first go with an absolutely rock-steady picture. After leaving everything running for 15 minutes, the range safety officer (a.k.a my wife) declared herself satisfied that the fire/electrocution risk seemed to be minimal and I was finally allowed to bring the repaired device back into the family home.

I really didn’t think I’d ever have cause to use my soldering iron to fix another computer problem. How wrong I was.

I decided at the end of February 2013 that it was about time to upgrade the home computer to Windows 7. Windows XP was fast approaching its ‘best before’ date and I’d always had a 32-bit version installed, despite having a computer that was 64-bit ready in almost all respects. After much wavering, I decided to take the plunge.

In preparation for the upgrade, I ordered an extra 8GB of memory, to bring the total installed up to 12GB. When this arrived, it also seemed that now was as good a time as any to strip the computer down and give it a good internal spring clean, removing all the dust, cleaning out fan filters, etc, etc.

So it was that I found myself once again out in the back garden, this time with the computer itself in bits around me. It took about 3 hours of careful disassembly, cleaning and dusting before I was happy with the result. During this process, I noticed that one of the front panel mounted USB connectors (that had been playing up for a while) had a loose connection to one of the pins on its associated header plug. Since I already had the machine in bits anyway, I stripped off the whole front panel switch and connector assembly and carefully teased the tiny little pin and attached wire back into place. I also took the opportunity to re-arrange some of the cable routing inside the case, both to make it look neater and to try and improve the airflow from the cooling fans.

I re-assembled everything, slotted in the extra 8G of memory and spent a moment admiring my shiny, new-looking computer before taking it back indoors. I wired everything back up, including mains power, speakers, USB printer, USB wireless adapter, monitor cable and USB wireless mouse/keyboard doo-hickey. Switching the mains back on, I saw the power LED light up on the front panel, the main chassis and CPU fans spun up for about a second and then everything went dead. No reassuring ‘beep’ to indicate that the power-on self-test or POST had completed successfully, nothing displayed on the freshly-repaired monitor, just complete silence and no sign of any activity at all. The machine hadn’t even had time to get to the point (usually after a couple of seconds) where it spins up the hard drive. The front panel power switch wasn’t causing aything to happen when I pressed it, but I found that if I pulled the kettle lead out of the power supply for 30 seconds then plugged it back in, I’d get the same thing as before, CPU and case fan spinning for about 1 second with the power LED lit, nothing else happening and a total shutdown almost straight away.

Okay, not to worry, I’ve had the whole thing in bits, I’ve obviously connected something back up wrong or left something not quite seated correctly. The first suspect was the newly-fitted memory modules. I discovered by trial and error that the machine would only do anything different if I removed all of its 4 memory modules. It still wouldn’t respond to the front panel power switch, but would at least get as far as the POST checks, at which point I’d get 2 short beeps in a row, which is the signal with this BIOS that it has failed to find any useable memory. I began to suspect at this point that all 4 memory modules had failed for some reason, which was disappointing since I didn’t have any spare DDR3 sticks in my spares box that I could test with.

Without boring you with all the details, I spent another hour trying to diagnose the problem without success. When I got the point where I’d disconnected and/or removed every component and external cable apart from the CPU and it still wouldn’t power up, I started to wonder if my spring clean had killed something vital on the motherboard with a dose of static electricity. Utterly despondent at this point, I put everything back together and had one more go at powering it up. Still no good. I sat and had a think about the problem over a cup of coffee, mentally reviewing what has to happen in order to get a modern PC to power up and load its operating system. It struck me that my last test had been to have the power LED header plug and the front panel switch header plug connected to the motherboard and nothing else and yet it would still only respond if I removed the kettle lead from the power supply for 30 seconds and plugged it back in. I was effectively simulating a power cut, in which case the machine was doing exactly what it was set to do in the BIOS, namely to stay powered off when the electrical supply was restored. The fact that pressing the front panel power button had had no effect in any of the tests I had devised had somehow slipped past me un-noticed.

I took the side panel off the computer once more, pulled out the power button header from the motherboard and shorted out the pins with a flat bladed screwdriver. Lo and behold, the computer powered on as normal, only complaining that it couldn’t find an operating system on the hard drive, which was because I’d completely wiped the drive in preparation for the upgrade to Windows 7. The fault appeared to be with either the actual power button itself or the wiring between the button on the front panel and the motherboard.

I quickly removed the whole front panel assembly again and inspected the ribbon cable connecting the small PCB holding the power and reset buttons to the motherboard. Instead of shiny blobs of solder where the 4-strand ribbon cable met the board, the solder on 3 of the 4 pads was dull and grey, classic signs of a ‘dry joint’. I’d obviously disturbed the cable durng the teardown and re-assembly process sufficiently for the poor quality soldering to make its effects known.

So the soldering iron came out again for the second time in 6 months. I removed all 4 ribbon cable strands and cleaned out the pads on the PCB. I trimmed the 4-way ribbon cable back by about 1.5cms and stripped 4 shiny new ends on each strand. After tinning the bare wires with the soldering iron, I re-attached the whole cable to the PCB, freshly soldered and secure. This time, the computer fired up on the first press of the power button and I was finally able to get Windows 7 installed and restore all the documents, pictures, videos and other data from a recent backup.

I’m hoping it will be a long time before I need to get that soldering iron out again, especially if it involves a broken computer or peripheral.

Too Many Computers

Between work and home, including real hardware and VM instances, I find myself hopping backwards and forwards between 5 or 6 different machines at any given time. I also happen to use the PuTTY SSH client quite a lot. I’ve got a bunch of PuTTY shortcuts configured across my little ‘herd’ of computers to give me quick access to the systems that I access most frequently.The problem is, the shortcuts aren’t exactly the same on all of my machines.

I use Windows-based computers with both 32 and 64 bit versions of the OS installed, which means that the PuTTY binary will be in a different location between, for example, a 32-bit Windows XP computer, a 32-bit Windows7 computer and a 64-bit Windows7 computer. This makes synchronisation of my folder of SSH shortcuts across all machines slightly problematical – if I change a shortcut on the 32-bit XP machine, I can’t just copy the changed .lnk file across to one of my 64-bit Windows7 boxes and expect it to work. With this in mind, I wrote a short Python script to deal with this for me. It will recursively scan a folder containing .lnk files and update each one so that it points off to the right place to launch a PuTTY session.

Note that this script depends upon you having Mark Hammonds ‘Python for Windows’ tool kit installed. If you haven’t got this, you can download it from SourceForge. For my script, either copy and paste the code below or scroll down for a direct download link.

This version (v 1.2) incorporates a bug fix which ensures that it only updates shortcuts which refer to ‘putty.exe’, otherwise it can end up overwriting your entire Start menu if you give it the right path.

#!/usr/bin/python
# Check and adjust PuTTY SSH shortcuts
# vim: ai et sw=4 ts=4
#
# Copyright (C)2012 Phil Edwards <phil 'at' linux2000.com>
#
# License: This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or (at your
# option) any later version. This program is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# CHANGELOG:
#
# Ver    Date       Who  Changes
# -----  ---------  ---  ---------------------------------------------------
# 1.0    21SEP2012  PKE  First version
# 1.1    06MAR2013  PKE  Enhanced command line option processing
# 1.2    16MAY2013  PKE  Bug fix - only update shortcuts that contain
#                        putty.exe in the target path

import os
import sys
import time
from optparse import OptionParser
import pythoncom
from win32com.shell import shell

class Win32Shortcut:
    def __init__(self, lnkname):
        self.shortcut = pythoncom.CoCreateInstance(
            shell.CLSID_ShellLink, None,
            pythoncom.CLSCTX_INPROC_SERVER, shell.IID_IShellLink)
        self.shortcut.QueryInterface(pythoncom.IID_IPersistFile).Load(lnkname)

    def __getattr__(self, name):
        return getattr(self.shortcut, name)

class RunTimeOptions:
    def __init__(self):
        self.__me__ = os.path.basename(sys.argv[0])
        self.__version__ = '1.2'
        self.__copyright__ = "Copyright (C)2013 Phil Edwards <phil 'at' linux2000.com> All Rights Reserved"
        self.__summary__ = 'Automatic PuTTY shortcut fixer'
       
        self.puttyPath = None
        self.found = 0
        self.updated = 0
        self.defaultPath = os.environ['appdata'] + "\Microsoft\Internet Explorer\Quick Launch"
       
        if os.path.exists("C:\Program Files (x86)\PuTTY\putty.exe"):
            self.puttyPath = 'C:\Program Files (x86)\PuTTY\putty.exe'

        if os.path.exists("C:\Program Files\PuTTY\putty.exe"):
            self.puttyPath = 'C:\Program Files\PuTTY\putty.exe'
   
        self.getCommandLineOptions()

        self.logMsg(txt = '%s v%s %s' % (self.__me__, self.__version__, self.__summary__))
        self.logMsg(txt = 'command line arguments: [%s]' % ' '.join(sys.argv[1:]))
        self.logMsg(txt = 'Executable found at [%s]' % self.puttyPath)

    def logMsg(self, **kwargs):
        txt = kwargs.get('txt', '')
        dateStamp = kwargs.get('dateStamp', True)
        msgLine = ''

        if txt != '':
            if dateStamp: msgLine += '[' + time.strftime("%Y%m%d-%H%M%S", time.localtime()) + '] '
            if not self.doUpdate: msgLine += 'NOUPDATE: '
            msgLine += txt
            print msgLine

    def debugMsg(self, **kwargs):
        txt = kwargs.get('txt', '')
        dateStamp = kwargs.get('dateStamp', True)
        pause = kwargs.get('pause', False)
        msgLine = ''

        if self.debugMode and txt != '':
            if dateStamp: msgLine += '[' + time.strftime("%Y%m%d-%H%M%S", time.localtime()) + '] '
            msgLine += 'DEBUG: ' + txt
            if pause:
                bull = raw_input(msgLine + ': Press any key to continue : ')
            else:
                print msgLine

    def getCommandLineOptions(self):
        vString = '%%prog (%s) v%s' % (self.__summary__, self.__version__)

        dString = 'Script to examine PuTTY SSH shortcuts found in the folder '
        dString += 'referenced by BASEPATH and update them so that '
        dString += 'they contain the correct path to the PuTTY executable'

        eString = ''
       
        uString = 'usage: %prog [options] BASEPATH'

        parser = OptionParser(version = vString, description = dString,
            epilog = eString, usage = uString)

        parser.add_option('-d', '--dry-run',
            action = 'store_false', dest = 'doupdate', default = True,
            help = 'process as normal, but do not update any files')

        parser.add_option('-x', '--debug',
            action = 'store_true', dest = 'debugmode', default = False,
            help = 'emit debug messages for troubleshooting')

        parser.add_option('-v', '--verbose',
            action = 'store_true', dest = 'verbose', default = False,
            help = 'be more verbose when processing')

        (options, args) = parser.parse_args()
       
        if len(args) == 0:
            self.basePath = self.defaultPath
        elif len(args) == 1:
            self.basePath = args[0]
        else:
            print 'ERROR: ambiguous command line parameters'
            sys.exit(0)

        if self.puttyPath is None:
            print 'ERROR: Unable to locate PuTTY executable'
            sys.exit(0)
           
        if not os.path.exists(self.basePath):
            print 'ERROR: base path does not exist'
            sys.exit(0)

        self.doUpdate = options.doupdate
        self.debugMode = options.debugmode
        self.verbose = options.verbose

        self.debugMsg(txt = 'options = %s' % options)
        self.debugMsg(txt = 'args = %s' % args)

def processItem(my, path):
    my.found += 1
   
    s = Win32Shortcut(path)
    iconPath = s.GetIconLocation()[0]
    itemPath = s.GetPath(0)[0]
    my.debugMsg(txt = 'itemPath is %s' % itemPath, pause = True)

    if itemPath != my.puttyPath and 'putty.exe' in itemPath.lower():
        s.SetPath(my.puttyPath)
        pf = s.QueryInterface (pythoncom.IID_IPersistFile)
        if my.doUpdate: pf.Save(path, 0)
        my.updated += 1
        my.logMsg(txt = '%s updated' % path)
    else:
        if my.verbose:
            my.logMsg(txt = '%s OK' % path)

def processFolder(my, path):
    if not os.path.isdir(path): return
   
    if my.verbose:
        my.logMsg(txt = 'Processing folder [%s]' % path)
       
    flist = os.listdir(path)
    for item in flist:
        newPath = os.path.join(path, item)
        if os.path.isdir(newPath):
            processFolder(my, newPath)
        elif item.endswith('.lnk'):
            processItem(my, os.path.join(path, item))

def main():
    my = RunTimeOptions()

    my.logMsg(txt = 'Processing started')
    processFolder(my, my.basePath)
    my.logMsg(txt = '%s shortcuts found' % my.found)
    my.logMsg(txt = '%s shortcuts updated' % my.updated)
    my.logMsg(txt = 'Processing complete')

if __name__ == '__main__':
    main()
Download1359 downloads