čtvrtek 14. října 2021

mpv: disable screensaver

By default mpv tries to disable screensaver during the playback. It uses Screen Saver extension (XSS) on X11 and idle-inhibit on Wayland for it. Unfortunately, a lot of desktop environments (DEs) don't support XSS. For them mpv had a hack. It called 'xdg-screensaver reset' in 10 second intervals. This hack was removed in the mpv-0.33.0. Usually, the screensaver can be inhibited through the D-Bus, but mpv upstream don't want to add support for it. It seems they did it mostly because they don't like GNOME. Although I don't like it I understand it - which sane developer likes GNOME :) From the mpv manual page:
GNOME is one of the worst offenders, and ignores even the now widely supported idle-inhibit protocol. (This is either due to a combination of malice and incompetence, but since implementing this protocol would only take a few lines of code, it is most likely the former. You will also notice how GNOME advocates react offended whenever their sabotage is pointed out, which indicates either hypocrisy, or even worse ignorance.) Such incompatible desktop environments (i.e. which ignore standards) typically require using a DBus API. This is ridiculous in several ways. The immediate practical problem is that it would require adding a quite unwieldy dependency for a DBus library, somehow integrating its main‐ loop into mpv, and other generally unacceptable things.
Unfortunately, non GNOME DEs like e.g. Xfce are also affected. Fortunately, another hack exists - the Lua script. Put the following Lua script under your ~/.config/mpv/scripts directory and name it e.g. stop-screensaver.lua:
local timeout_sec = 60

function timeout_fn()
  mp.commandv("run", "/usr/bin/bash", "-c", "/usr/bin/xdg-screensaver reset &>/dev/null")
end

mp.add_periodic_timer(timeout_sec, timeout_fn)
This script will periodically calls the 'xdg-screensaver reset', similarly as the original mpv hack did. You may need customize the timeout - I used 60 seconds, because my screensaver timout is much higher - and maybe the paths to the bash and xdg-screensaver. This script was tested on Fedora 33.

neděle 10. května 2020

Wireless headphones Thomson WHP3001BJ doesn’t charge

I got these headphones from second hand and out of warranty, but it seems the model is still manufactured (year 2020). It's old good analog technology - simple, reliable and budget friendly. It will probably not satisfy you if you are Hi-Fi purist, but for occasional TV watching or for parents it‘s quite OK. It comes with a base which can be used as a stand and it should charge the two AAA batteries in the headphones. But unfortunately in my case the charging didn’t work.

At first I checked the contacts on the base and on the headphones - both seemed OK. Then I measured voltage on the charging pins of the base, it was also OK. So I connected variable resistor to the charging pins to verify the charging procedure. It seems it’s simple constant voltage charging (I didn’t expect anything else in this price range). It can do max cca. 100 mA charging current and the charging LED indicator goes out when the charging current lowers bellow cca. 25 mA. So it didn’t stop the charging and the batteries are charged all the time when connected to the base. This means two things: the charging of fully discharged batteries can take pretty long (10 - 20 hours or it may be even not possible to charge old batteries at all) and the life of the batteries will be probably slightly reduced by the low current which flows into the batteries all the time. This is interesting observation, but it didn’t help me with my problem.

Next, I disassembled the headphones. The power supply PCB is pretty simple, just the power switch, one diode and some condenser filters. By checking the PCB the problem was clear. Despite of being so simple, the power supply wiring seemed a bit over-engineered. There are second contacts for the battery GND (the "-" contact) that are offset from the battery end. These contacts are not apparent without disassembling the headphones. After a bit of thinking I realized that it’s probably ugly protection from insertion of non-rechargeable batteries. It seems you need specially modified rechargeable batteries with protracted GND strip. If you insert unmodified non-rechargeable batteries (1.5 V), the second GND pins will not connect and it will not charge. Also the diode will lover the voltage by cca. 0.6 V, so the resulting voltage will be 2 x 1.5 V - 0.6 V= 2.4 V, which is the same voltage as if powered by the re-chargeable NiMH batteries (1.2 V), i.e. 2 x 1.2 V = 2.4 V. The problem is that if you insert unmodified rechargeable batteries it will not charge them and the voltage will be lowered by cca. 0.6 V which will shorten the operational time. Also with the modified batteries for the charging to begin the headphones has to be switched off.

battery mod

To be 100% sure, I tried to google the original manual on the internet. Luckily it is still there (year 2020), but there is written nothing about the special batteries. There is just a small picture of the batteries where the GND strips are visible. Fortunately, after more research it seems they added the problem to the FAQ section on their web pages - lessons learned: google first then fix problems :). They describe the reason behind it as: "To prevent a user of the wireless headphones from inadvertently inserting non rechargeable standard batteries and from trying to charge them". And they also describe how to modify the batteries: "Cut off the heatshrinking sleeve which covers the rechargeable battery on the side of the negative terminal at a length of about one centimetre and remove it." Personally, I can’t imagine myself trying to insert non-rechargeable batteries there - fortunately I am still sane enough :). It’s also quite unhandy for me to modify the rechargeable batteries each time they need to be replaced, so I simply modified the PCB - I added two white wires shorting the additional GND contacts and added label to the battery compartment stating "do not insert non-rechargeable batteries" - just in case my sanity would worsen during time :). If I would have any need to use non-rechargeable batteries in the future (which is unlikely), I will just cut the two added wires and everything will work as before.

headphones mod

neděle 22. října 2017

How to recompile Fedora kernel with the custom patch

I has been asked how to recompile Fedora kernel with the custom patch, so here is the tutorial:

At first install the needed packages:

# dnf install fedpkg dnf-plugins-core

Install build requirements for the kernel package:

# dnf builddep kernel

Clone the kernel dist-git module for the desired Fedora version, i.e. if you want to recompile the kernel for the Fedora 26, add the '-b f26' or respective version (--anonymous is used for the anonymous checkout, i.e. read only checkout):

$ fedpkg co --anonymous -b f26 kernel

Change the working directory to the cloned dist-git module:

$ cd kernel

Copy the desired patch (e.g. my.patch) to the working directory:

$ cp DIR/my.patch .

Make sure your my.patch has been generated by the 'git format-patch' if not, you need to manually add the header containing lines From:, Subject:, so proceed the following step just only if such header is not presented in your patch (of course edit the strings as needed):

$ echo "From: Joe Hacker <joe.hacker@hacker.org>" > header
$ echo "Subject: My patch" >> header
$ echo >> header
$ cat header my.patch > patch
$ mv patch my.patch

Edit the kernel.spec, locate the string '# END OF PATCH DEFINITIONS', and add the following string just before it:

Patch9999: my.patch

where make sure that the number 9999 is not used by any previous Patch keyword. If it's already used, keep increasing the number until you will find the highest unused number and use it with your patch. Save the spec file.

Recompile the kernel:

$ fedpkg local

Install/re-install the newly builds kernel RPMs from the ARCH directory, i.e. if you compiled the kernel for the x86_64, the ARCH directory is x86_64.

Reverted patch

In case you have upstream kernel patch you need to revert (let's say upstream.patch, do the previous steps up-to the installation of the my.patch, then unpack the kernel sources:

$ fedpkg prep

Make the reverted patch of the upstream.patch (replace the DIR in commands below by directory where you store your patches):

$ pushd kernel-*/linux-*
$ git commit -am Flush
$ cp DIR/upstream.patch .
$ patch -p1 -R < upstream.patch
$ git commit -am "Upstream reverted patch"
$ git format-patch --stdout HEAD~1 > DIR/upstream-reverted.patch
$ popd

Then install the upstream-reverted.patch instead of the my.patch and proceed with the compilation as described above.

úterý 27. prosince 2016

Fix Xvid playback in Media Foundation in Windows 10 after Xvid codec installation

Currently there are two frameworks/APIs for media playback in Windows 10. Older DirectShow and newer Media Foundation (MF). The latter is used by e.g. Universal Windows Platform (UWP) applications/apps (formerly Metro applications/apps). With 64 bit OS both APIs are there twice - for 32 bits and 64 bits. This means four places where things could break.

One breakage I have recently encountered is with the free and open-source (FOSS) Xvid codec/software. When this software (version 1.3.4 build 20150621) is installed it breaks Xvid (MPEG-4 ASP with FourCC set to XVID) videos playback in MF. This is painful because the default application for video playback in Windows 10 is UWP based app called zunevideo (or TwinUI, or Movies & TV). The problem manifests as a black screen during Xvid playback in the zunevideo. Unfortunately the zunevideo doesn't show any error or message what's wrong and what's worse the uninstallation of the Xvid codec/software doesn't fix the problem.

Upon analysis of the problem it seems that the Xvid doesn't support MF, but the Xvid installer removes mappings of XVID to MS codec and doesn't return it after uninstallation. I reported the problem to Xvid upstream. To fix the problem the following registry edits which re-adds mappings of xvid/XVID to MP4V can be used:

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\MediaFoundation\MapVideo4cc]
"58564944"=dword:5634504d

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\MediaFoundation\MapVideo4cc]
"78766964"=dword:5634504d

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WOW6432Node\MediaFoundation\MapVideo4cc]
"58564944"=dword:5634504d

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WOW6432Node\MediaFoundation\MapVideo4cc]
"78766964"=dword:5634504d

The first line maps FourCC "58564944" ("XVID" in ASCII) to FourCC 0x5634504d ("MP4V" in ASCII Little-Endian). The second line do the same for the same FourCC, but in lower case ("xvid" in ASCII). The last two lines do the same as the first two lines, but for 32 bits. This fixes the Xvid playback in MF for me.

středa 9. března 2016

Remote web monitoring of 3D printers through Pronterface

I have recently dug into Pronterface code and realized that there is simple RPC server built-in. It listens on localhost and it's really cool feature for remote monitoring, so I hacked KISS (Keep It Simple and Stupid) PHP code that allows querying the RPC server through the web. The code can query multiple running Pronterfaces and it's no problem to monitor multiple 3D printers which are connected to the same host. Running instances of Pronterface are automatically detected. It also queries all connected V4L compatible webcameras, which means that you can check progress of printers visually. With the current code you can check temperatures (bed, extruder), Z position, status of the current print task including task/file name, ETA, finished percentage.

The code with instructions is available from github: https://github.com/yarda/printrun-webmon/. Feel free to pull request patches.

pátek 18. září 2015

How to get Chinese 2.4 TFT LCD ILI9341 based Arduino Uno shield working

These Chinese Arduino Uno TFT LCD shields are neat and very cheap, so I couldn't resist and got one from Banggood. As with nearly everything Chinese, there are several versions and revisions around and it's usually surprise which one you will recieve. It seems my shield came with ILI9341 controller although there is written ILI9340 on the board (I didn't disassemble it, but I assume it according to the shield behaviour). I tried to get it working with Adafruit TFTLCD-Library, but it ended with "Unknown LCD driver chip: C0C0" and white screen. So I dug a bit deep into this problem. It quickly turned out that the chip needs a bit longer delay for reset to start responding. For my shield it seems that additional 5 milliseconds are enough. Then it correctly identified itself as ILI9341. But it still didn't display anything, there was only the whitescreen.

I read both ILI9340 and ILI9341 datasheets and found out that my chip has extended registers which are not handled by the original code. I verified content of these registers with the datasheet and it revealed that the "Pump ratio control" register is set to 0x0 after the reset. According to the datasheet this is 'reserved' value and after the reset the content of this register should be set to 0x20 (which means 2xVCI). Maybe my chip revision is newer than my datasheet or maybe this is some HW glitch but this again validated the basic rule known to embedded developers: "never ever rely on the default values after the reset". So I added initialization for the extended registers. I also improved chip select (CS) handling in the code which allows sharing of the data ports with other peripherals. I did some other minor improvements and bug fixes to the code. All of the changes should be harmless to older HW. Even the initialization of the extended registers should work on chips without extended registers, because according to the datasheet, such initialization should be handled as NOP commands. I pull requested the changes to Adafruit, there is the direct link to the related commit. It seems the shield has different orientation of the display than the Adafruit library expects, thus you need to uncomment #define ILI9341_MIRROR_X 1 and comment #define ILI9341_MIRROR_Y 1 in Adafruit_TFTLCD.h to fix the orientation.

Regarding the touchscreen it's classic 4 wire resistive digitizer which can be handled by e.g. Adafruit TouchScreen library. The only thing that you need to setup is which pins the touchscreen is connected to. Unfortunately it is not written on the kit, but it's possible to locate the connections visually and with the multimeter. The wiring of my shield is following:

A1Y+
A2X-
D6X+
D7Y-

Unfortunately my shield came with broken electrode, so my touchscreen didn't work, but I checked the correct functionality of the code on my friend's shield. I was refunded by Banggood without problems, so I ordered another shield and will keep this broken shield for projects that do not require touchscreen. You can see the detail of the broken electrode here:

There is picture of the working shield kindly lent me by my friend:

I downloaded the code for this simple painting application somewhere on the internet and modified it to work with my shield. The modified code is available for download. There was no licensing information in the original code, so hopefully the license status of this code is OK (free/public domain). If not, please let me know. In the application you can draw by your stylus/finger, select colors on the side and clear the display by tapping on the opposite display side.

Update 2015/10/07
I received replacement display and the shipment was pretty fast. This time there is written ILI9341 on the PCB. It again proved that the development runs pretty fast in China and they usually finish new iteration sooner than you receive your previous order. The display works correctly now. But it seems the digitizer X/Y pins are reversed in comparison with the previous display. I am not sure whether it is wanted feature of the new PCB or bug, but it doesn't matter. The digitizer wiring is now following:

A1X-
A2Y+
D6Y-
D7X+

středa 15. července 2015

Fix Internet Explorer dowloading .EXE files as _EXE

I encountered it on Windows 8.1 Pro 64 bit, but the following observations may apply to other versions as well. It seems to be quite common issue, but I wasn't able to find any resolution for it on the Internet not counting disabling of the IE Protected Mode (PM) or creation of new user profile. Disabling of the PM is not good way to go, because it needlessly increases number of potential attack vectors. Creation of new user profile is easy fix for single user, but pain in case there are dozens user accounts facing this issue. That's why I dug deeper into it.

I quickly realised that this problem is mostly faced by users whose profile have been moved/copied to different drive. At first I compared registry dumps for user not facing the problem (let's call her/him "good user") and user facing the problem (let's call her/him "bad user"). Initially I thought that this obviously over-engineered PM feature stores drives UUIDs in registry hives, but the comparison of registry hives didn't reveal anything supporting this assumption.

Next I moved to Process Monitor to observe what's going there. I noticed a lot of "access denied" return codes from the CreateFile calls, all of them ending somewhere in the PM InetCache under %LOCALAPPDATA%\Packages\windows_ie_ac_001\AC. This also caused a bit delay when the download was initiated. Then after some delay, the Internet Explorer showed dialog box that it cannot download the file. If "retry" button was clicked, it used some different, probably backup directory and the file was saved with _exe suffix instead of .exe.

I checked ACL of the InetCache path, but it seemed OK. Even so I tried to give full access to everyone for this directory and sub-directories (it is generally not good idea, but I wonder what will happen). But it didn't help. Really strange, so I tried comparing ACLs of "good user" with "bad user". It revealed that there is SID of otherwise non-existent user S-1-15-2-1430448594-2639229838-973813799-439329657-1197984847-4069167804-1277922394 with full access rights on the path. I always enjoy such hacks :). I used the following command to fix the problem (I ran it multiple times with %LOCALAPPDATA% replaced by the user LOCALAPPDATA path, e.g. C:\users\user1\AppData\Local):

icacls %LOCALAPPDATA%\Packages\windows_ie_ac_001\AC /grant
"*S-1-15-2-1430448594-2639229838-973813799-439329657-1197984847-4069167804-1277922394":(OI)(CI)F /c

Unfortunately there still persisted some user accounts that weren't fixed by this command. I rechecked one such account with the Process Monitor and it revealed that Internet Explorer created its InetCache on virtualised path which broke the PM. It seems that for correct PM function it's not enough if Users group or the group user is member of have full access to user profile, but it requires the user to be explicitly listed on the ACL of the profile directory and it's subdirectories. So I finally used the following command to fix the rest of affected user accounts (again ran multiple times):

icacls %USERPROFILE% /grant %USERNAME%:(OI)(CI)F /c /t

Later I realized that in my case the problem was probably caused by relocation script used for moving of user profiles. This script called robocopy command without the /copyall parameter. But there can be probably more sources of this problem (e.g. filesystem / ACL corruption caused by machine crash or installation of buggy drivers/SW, etc.).