Do-It-Yourself: Hot plate for phone screen repairs

I needed a quick (DIY) solution to create a hot plate (a.k.a. Screen Repair Separator Machine Heating Plate) for repairing the screen of my wifes mobile phone. It is a cheap phone so I needed a cheap solution to create hot plate alternative.

After staring at the kitchen oven (too hot, even on the lowest setting), I got this brief mental lapse… What about a take-out (Dutch Chinees food) container filled to the top with hot water.

Standard take-out container for Chinese food in the Netherlands.

It is easy to control the temperature, by mixing 100 degrees kettle water with tap water (assumed to be ambient temperature):
1 part 100 degrees + 1 parts 20 degrees: (100+20) / 2 = 60 degrees
2 parts 100 degrees + 1 part 20 degrees: (100+100+20) / 3 = 73 degrees

Shucking a 8TB WD Elements vs 8TB WD Red

Shucking a hard drive is the practice of removing a hard drive from it’s (external) USB exclose. This may sound like a stupid thing to do, but this can save you some money (150 euro vs 220 euro) 🤑

The scary side of shucking is that you never really know what you will get, it is a little like a surprise egg for nerds. This time we got lucky, the WD80EMAZ is actually a helium filled HGST Ultrastar, modified to run at 5400 RPM (instead of 7200 RPM).

The shucked drive ( WD80EMAZ ) runs 5-6 degrees cooler than my original 8TB WD Red drives (WD80EFAX) 😎

Hard drive temperatures WD80EFAX (8TB WD Red) vs WD80EMAZ (Shunked 8TB WD Elements).

Update: I have multiple shucked drives in use WD80EMAZ (WD Elements with the blue text on the box) and WD80EDAZ (WD Elements with the orange text on the box). All drives have 256MB cache and are running without issues in a Synology NAS. The WD80EDAZ drives will run a lot hotter 😐

C# – XBox 360 Controller library with a sample application

Created an easy to use XBox 360 Controller library in C# (with a sample application) using the SharpDX.XInput managed .NET wrapper of the DirectX API.

 https://github.com/okmer/XBoxController

Screenshot of the sample application.
Screenshot of the sample application.

A BUG in SharpDX.XInput ci-ci217, resulting in issues with the  left Thumb Stick, Left Trigger, and Right Trigger! Please stick to SharpDX.XInput v4.1.0-ci184 for now.

using System;
 
using Com.Okmer.GameController;
 
namespace XBoxSampleConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            XBoxController controller = new XBoxController();
 
            Console.WriteLine("XBox 360 Controller (Press ENTER to exit...)");
 
            //Connection
            controller.Connection.ValueChanged += (s, e) => Console.WriteLine($"Connection state: {e.Value}");
 
            //Battery
            controller.Battery.ValueChanged += (s, e) => Console.WriteLine($"Battery level: {e.Value}");
 
            //Buttons A, B, X, Y
            controller.A.ValueChanged += (s, e) => Console.WriteLine($"A state: {e.Value}");
            controller.B.ValueChanged += (s, e) => Console.WriteLine($"B state: {e.Value}");
            controller.X.ValueChanged += (s, e) => Console.WriteLine($"X state: {e.Value}");
            controller.Y.ValueChanged += (s, e) => Console.WriteLine($"Y state: {e.Value}");
 
            //Buttons Start, Back
            controller.Start.ValueChanged += (s, e) => Console.WriteLine($"Start state: {e.Value}");
            controller.Back.ValueChanged += (s, e) => Console.WriteLine($"Back state: {e.Value}");
 
            //Buttons D-Pad Up, Down, Left, Right
            controller.Up.ValueChanged += (s, e) => Console.WriteLine($"Up state: {e.Value}");
            controller.Down.ValueChanged += (s, e) => Console.WriteLine($"Down state: {e.Value}");
            controller.Left.ValueChanged += (s, e) => Console.WriteLine($"Left state: {e.Value}");
            controller.Right.ValueChanged += (s, e) => Console.WriteLine($"Right state: {e.Value}");
 
            //Buttons Shoulder Left, Right
            controller.LeftShoulder.ValueChanged += (s, e) => Console.WriteLine($"Left shoulder state: {e.Value}");
            controller.RightShoulder.ValueChanged += (s, e) => Console.WriteLine($"Right shoulder state: {e.Value}");
 
            //Buttons Thumb Left, Right
            controller.LeftThumbclick.ValueChanged += (s, e) => Console.WriteLine($"Left thumb state: {e.Value}");
            controller.RightThumbclick.ValueChanged += (s, e) => Console.WriteLine($"Right thumb state: {e.Value}");
 
            //Trigger Position Left, Right 
            controller.LeftTrigger.ValueChanged += (s, e) => Console.WriteLine($"Left trigger position: {e.Value}");
            controller.RightTrigger.ValueChanged += (s, e) => Console.WriteLine($"Right trigger position: {e.Value}");
 
            //Thumb Positions Left, Right
            controller.LeftThumbstick.ValueChanged += (s, e) => Console.WriteLine($"Left thumb X: {e.Value.X}, Y: {e.Value.Y}");
            controller.RightThumbstick.ValueChanged += (s, e) => Console.WriteLine($"Right thumb X: {e.Value.X}, Y: {e.Value.Y}");
 
            //Rumble Left, Right
            controller.LeftRumble.ValueChanged += (s, e) => Console.WriteLine($"Left rumble speed: {e.Value}");
            controller.RightRumble.ValueChanged += (s, e) => Console.WriteLine($"Right rumble speed: {e.Value}");
 
            //Rumble 0.25f speed for 500 milliseconds when the A or B button is pushed
            controller.A.ValueChanged += (s, e) => controller.LeftRumble.Rumble(0.25f, 500);
            controller.B.ValueChanged += (s, e) => controller.RightRumble.Rumble(0.25f, 500);
 
            //Rumble at 1.0f speed for 1000 milliseconds when the X or Y button is pushed
            controller.X.ValueChanged += (s, e) => controller.LeftRumble.Rumble(1.0f, 1000);
            controller.Y.ValueChanged += (s, e) => controller.RightRumble.Rumble(1.0f, 1000);
 
            //Rumble at the speed of the trigger position
            controller.LeftTrigger.ValueChanged += (s, e) => controller.LeftRumble.Rumble(e.Value);
            controller.RightTrigger.ValueChanged += (s, e) => controller.RightRumble.Rumble(e.Value);
 
            //Wait on ENTER to exit...
            Console.ReadLine();
        }
    }
}

EvilDir, create an EVIL named directory in Windows

A little “fun” Qt5 console application to create a directory (a.k.a. folder) ending with a space character (” “). This directory can not be removed with standard Windows tools, including most console applications.

#include <QCoreApplication>
#include <QDir>

int main(int argc, char *argv[])
{
  QCoreApplication a(argc, argv);

  QString evil_dir_name("Remko is a little Evil !!! ");

  for(int i=1; i<a.arguments().count(); i++)
  {
    if(a.arguments().at(i).compare("-d", Qt::CaseInsensitive) != 0)
    {
      evil_dir_name = a.arguments().at(i);
      evil_dir_name.append(" ");
      break;
    }
  }

  if(a.arguments().contains("-d"))
  {
    if(QDir(evil_dir_name).exists())
    {
      QDir().rmdir(evil_dir_name);
    }
  }
  else
  {
    QDir().mkdir(evil_dir_name);
  }
 
  return 0;
}

Reduce size (static) executables

This little (cross-platform) executable compression tool Ultimate Packer for eXecutables (UPX) can greatly reduce the size of (static build) executables. The executable filesize will be reduced to the size of a ZIP file containing the same executable.

The tool is very easy to use, just drag-and-drop your executable onto the upx.exe to use the default (fast) compression option of the tool, or type “upx <filename>” in the command-line. Adding the (much slower) “–utra-brute” command-line argument will reduce the filesize even further.

A static build Qt5.1.1 MinGW compiled application with a filesize of 12.972.032 bytes (12.3MB):

DEFAULT: 12.972.032 bytes (12.3MB) is reduced to 5.218.816 bytes (4.97 MB) using the (fast) default settings.

ULTRA-BRUTE: 12.972.032 bytes (12.3MB) is reduced to 4.488.704 bytes (4.28 MB) using the (much slower) “–ultra-brute” argument.

Qt 5.1.1 static build with MinGW

This is a small step-by-step howto compile a static Qt5.1.1 framework from source, using the MinGW 4.8.1 development environment.

Download MinGW Installer:
http://sourceforge.net/projects/mingwbuilds/files/mingw-builds-install/

Download Qt5 Source Zip:
http://download.qt-project.org/official_releases/qt/5.1/5.1.1/single/qt-everywhere-opensource-src-5.1.1.zip

Patch mkspecs (line 69):
<Qt5.1.x>\qtbase\mkspecs\win32-g++\qmake.conf

QMAKE_LFLAGS = -static -static-libgcc

Patch mkspecs (line 28) optional (reduce file size static builds):

QMAKE_CFLAGS = -ffunction-sections -fdata-sections ...

Patch Makefile.win32 (line 50):
<Qt5.1.x>\qtbase\qmake\Makefile.win32

LFLAGS = -static-libgcc ...

Patch for MinGW 4.8.1 (older MinGW 4.6.x works with-out patch):
https://codereview.qt-project.org/#change,63747

Replace file with patched version:
<Qt5.1.x>\qtbase\src\corelib\ioqfilesystemengine_win.cpp
https://codereview.qt-project.org/#patch,sidebyside,63747,3,src/corelib/io/qfilesystemengine_win.cpp

Patch for MinGW 4.8.1 (older MinGW 4.6.x works with-out patch):
https://codereview.qt-project.org/#change,64330,patchset=1

Replace file with patched version:
<Qt5.1.x>\qtbase\src\plugins\platforms\windows\qwindowstheme.cpp
https://codereview.qt-project.org/#patch,sidebyside,64330,1,src/plugins/platforms/windows/qwindowstheme.cpp

Python (needed by the qtjsbackend to fix the v8 error):
http://www.python.org/download/releases/

Add Python to Path:

set PATH=%PATH%;C:\Python33

Add MinGW to Path:

set PATH=%PATH%;C:\MinGWx32\mingw32\bin

Configure in <Qt5.1.x>\:

configure -platform win32-g++ -release -static -opensource -no-opengl -qt-zlib -qt-libpng -qt-libjpeg -nomake examples

Build with MinGW make in <Qt5.1.x>\:

mingw32-make -j

Build with Qt Creator:

Tools->Options
Build & Run
Compilers -> Add MinGW used to build Qt5.1.x -> Add->MinGW -> Browse to <MinGW>\bin\g++.exe (Apply)
Qt Versions -> Add Qt5.1.x static MinGW build -> Add -> browse to <Qt5.1.x>\qtbase\bin\qmake.exe (Apply)
Kits -> Add Qt5.1.x static with MinGW compiler -> Add -> compiler:MinGW & qtVersion:Qt5.1.xStaticMinGW & qtmkspecs:win32-g++

Ready to build !!!