Monthly Archives: January 2014

Fail of the day #2: SSD drives out of spec

A while back I got an SSD drive with the question whether it could be repaired. At first glance it looked fine. But wait… the PCB is not level. In fact, it is seriously wobbly. What on earth happened to this SSD??

That PCB should really not have that shape..

That PCB should really not have that shape.

Looking closer at the flash ICs, it turns out several of them have pins that have disconnected from the PCB. Ok – that’s tough but nothing some careful soldering cannot fix.

But after inspecting the rest of the PCB it is clear that some inductors and capacitors have been torn off too. Wow – this drive took a real beating – nothing here to be salvaged except maybe a crystal or inductor. Could possibly be useful in other projects. Well – it goes into the to-be-used-in-future-projects box.

 

That’s only half the story… Quite a while back I came across another pair of PCBs. Another SSD, in fact – broken in two. Probably on purpose to prevent data extraction from the drive, but it gives a good opportunity to have a closer look at what is inside an Intel SSD drive.

2014-01-01_22-51-10

No rescue possible here, no matter how good soldering skills..

All the passive components (capacitors, resistors) are so small they are impossible to hand solder – no point in salvaging them. Most of the other components are held in place with epoxy, making removal impossible (but I will for sure buy Intel SSDs from now on – these things are built to last!).

The PCB seems to have multiple layers. There is for sure at least a ground plane in there, probably 1-2 signal layers too (hard to count them without a microscope).

The one component that might be of interest in other projects (adding memory to OpenWRT based routers comes to mind) is the SDRAM, is a Samsung K4S281632I-UC60 8Mbyte x 16 IC.  On the other hand – hand soldering that one will be… difficult (understatement) and require rebuilding the OpenWRT kernel. Hmm.. Will probably just recycle it.

FAIL of the day #1: Repair of NiMH charger

2014-01-01_16-25-22

When buying some GP branded NiMH rechargeable batteries about a year ago, a “GP PowerBank Travel” charger (model GPPB03GS) was included as a promotion. It’s a nice little charger that runs both off 220 V and 12 V (for use in car, I presume). It can charge 1-4 AA batteries, or 1-2 AAA batteries, with additional trickle charging after full capacity has been reached.

The charger worked well for some months, but one day after charging some batteries overnight the LED blinked red, and when removing the batteries it was clear something had gone wrong. See the melted plastic? Not good.

As this was very much an el-cheapo charger, one should probably not expect much from it. But I was still curious about how the 220V was brought down to more useful voltage levels, and if the internals would live up to safety standards. I was actually quite surprised at how complex and well designed the internals were:

Looking closer, there are three distinct parts of the PCB:

– 220V section, which is shielded with plastic blast shields towards rest of the electronics – nice! This is a classic Switched Mode Power Supply (=SMPS), with an optocoupler feedback loop. Looks like a SMD type TL431 voltage reference – very common in SMPS designs.

– 12V section, with some protection diodes, filter caps etc – but no other major components.

– Charger circuit, using an unknown controller IC. The markings have been shaved off. I just don’t understand why they go through the trouble of doing that… It’s not like this is some super classified product where the design should be kept secret at any cost.

A closer look at the components and PCB around where the plastic had melted does not give any clues of what has gone wrong – in fact nothing visible anywhere on the PCB indicates a catastrophic failure of the charger.

Bringing out the multimeter and measuring the output from both SMPS and 12V section shows that those voltages are all good – most likely the problem is instead in the unknown charging controller IC, or possibly some of the tiny SMD FETs, diodes etc that complement the charging IC.

So… given that this kind of charger cost next to nothing these days, I’ll leave it for dead for now. The SMPS works as it should, so maybe that part can be reused in some other project – I’ll stash it in the “possible-future-use” parts bin.

Using CoffeeScript to create QlikView extensions

I am not a Javascript fan. To be honest, I find it rather abusive. There are probably lots of theoretically sound reasons for designing the Javascript (=JS) syntax the way it is – but that does not make it more readable or easy to learn.

I am however a QlikView (=QV) fan. Or rather: QV is a very powerful data visualisation, exploration and discovery tool, but the main drawbacks is its somewhat dated visualisation options. In a world used to fancy angular.js based dynamic web sites and great looking HighCharts graphs, QV’s visualisation options aren’t quite up there.

QV however has a rather interesting “extension” mechanism. You can create object extensions that add new visualisations to QV, using JS to develop the extensions. Document extensions are used to modify the deeper levels of QV applications – very useful and cool (someone created a document extensions using the accelerometers in iPhones to enable new ways to interacts with QV applications – pretty cool!) but not the focus of this post.

So, we want to create QlikView object extensions. JS is the mandated language. Ouch. We can however use CoffeeScript to remove the bad parts of JS, making the code base smaller and more easy to read and maintain. CoffeeScript is very cool, lots of testimonies to it’s greatness out there (DropBox is using CoffeeScript these days, and have shared some experiences).

Note: You need to install node.js before CoffeeScript. I’ve tried this on both Windows 8.1 and OS X – compiling CoffeeScript works without problems on both platforms.

Tuns out this works quite well. Brian Munz of QlikTech has created a couple of very nice templates to make it easier to create extensions, I’ve taken the liberty of converting one of them to CoffeeScript, to show how easy it is to convert JS to CoffeeScript (and make my own future extension development easier).

The CoffeeScript code can also be found in my repo at GitHub.

The Javascript version first:


var template_path = Qva.Remote + "?public=only&name=Extensions/template_simple/";
function extension_Init()
{
  // Use QlikView's method of loading other files needed by an extension. These files should be added to your extension .zip file (.qar)
  if (typeof jQuery == 'undefined') {
    Qva.LoadScript(template_path + 'jquery.js', extension_Done);
  }
  else {
    extension_Done();
  }
}

function extension_Done(){
  //Add extension
  Qva.AddExtension('template_simple', function(){
    //Load a CSS style sheet
    Qva.LoadCSS(template_path + "style.css");
    var _this = this;
    //add a unique name to the extension in order to prevent conflicts with other extensions.
    //basically, take the object ID and add it to a DIV
    var divName = _this.Layout.ObjectId.replace("\\", "_");
    if(_this.Element.children.length == 0) {//if this div doesn't already exist, create a unique div with the divName
      var ui = document.createElement("div");
      ui.setAttribute("id", divName);
      _this.Element.appendChild(ui);
    } else {
      //if it does exist, empty the div so we can fill it again
      $("#" + divName).empty();
    }

    //create a variable to put the html into
    var html = "";
    //set a variable to the dataset to make things easier
    var td = _this.Data;
    //loop through the data set and add the values to the html variable
    for(var rowIx = 0; rowIx < td.Rows.length; rowIx++) {
      //set the current row to a variable
      var row = td.Rows[rowIx];
      //get the value of the first item in the dataset row
      var val1 = row[0].text;
      //get the value of the second item in the dataset row
      var m = row[1].text;
      //add those values to the html variable
      html += "value 1: " + val1 + " expression value: " + m + "<br />";
    }
    //insert the html from the html variable into the extension.
    $("#" + divName).html(html);
  });
}

//Initiate extension
extension_Init();

Now the CoffeeScript version. A lot more readable, at least to me:

template_path = Qva.Remote + "?public=only&name=Extensions/template_simple_coffeescript/"

extension_Init = ->
  # Use QlikView's method of loading other files needed by an extension. These files should be added to your extension .zip file (.qar)
  if typeof jQuery == 'undefined'
    Qva.LoadScript(template_path + 'jquery.js', extension_Done)
  else
    extension_Done()

extension_Done = ->
  # Add extension
  Qva.AddExtension('template_simple_coffeescript', ->
    _this = this

    # add a unique name to the extension in order to prevent conflicts with other extensions.
    # basically, take the object ID and add it to a DIV
    divName = _this.Layout.ObjectId.replace("\\", "_")
    if _this.Element.children.length == 0
      # if this div doesn't already exist, create a unique div with the divName
      ui = document.createElement("div")
      ui.setAttribute("id", divName)
      _this.Element.appendChild(ui)
    else
      # if it does exist, empty the div so we can fill it again
      $("#" + divName).empty()

    # create a variable to put the html into
    html = ""

    # set a variable to the dataset to make things easier
    td = _this.Data

    # loop through the data set and add the values to the html variable
    for rowIx in [0..(td.Rows.length-1)]

    # set the current row to a variable
    row = td.Rows[rowIx]

    # get the value of the first item in the dataset row
    val1 = row[0].text

    # get the value of the second item in the dataset row
    m = row[1].text

    # add those values to the html variable
    html += "value 1: " + val1 + " expression value: " + m + "<br />"

    # insert the html from the html variable into the extension.
    $("#" + divName).html(html)
  )

# Initiate extension
@extension_Init()

Note that you need to include the –bare option when compiling the CoffeeScript code:


coffee --bare --compile Script.coffee

This will give us the following Javascript file, which is functionally equivalent to the first JS file above:

// Generated by CoffeeScript 1.6.3
var extension_Done, extension_Init, template_path;

template_path = Qva.Remote + "?public=only&name=Extensions/template_simple_coffeescript/";

extension_Init = function() {
  if (typeof jQuery === 'undefined') {
    return Qva.LoadScript(template_path + 'jquery.js', extension_Done);
  } else {
    return extension_Done();
  }
};

extension_Done = function() {
  return Qva.AddExtension('template_simple_coffeescript', function() {
    var divName, html, m, row, rowIx, td, ui, val1, _i, _ref, _this;
    _this = this;
    divName = _this.Layout.ObjectId.replace("\\", "_");
    if (_this.Element.children.length === 0) {
      ui = document.createElement("div");
      ui.setAttribute("id", divName);
      _this.Element.appendChild(ui);
    } else {
      $("#" + divName).empty();
    }

    html = "";
    td = _this.Data;
    for (rowIx = _i = 0, _ref = td.Rows.length - 1; 0 <= _ref ? _i <= _ref : _i >= _ref; rowIx = 0 <= _ref ? ++_i : --_i) {
      row = td.Rows[rowIx];
      val1 = row[0].text;
      m = row[1].text;
      html += "value 1: " + val1 + " expression value: " + m + "<br />";
    }
    return $("#" + divName).html(html);
  });
};

this.extension_Init();