Debian Bullseye Bug Remedy Script

@Sineos kindly posted a process for identifying whether or not your system is affected by the Debian 11 Bullseye bug:

The process works well but requires a fair amount of precision as well as copy and pasting so I came up with a bash script that automates the various actions.

The script is to be run right after the SD card is formatted with the rPi OS but before Klipper is installed. To execute the script, run the follow command from the SSH shell:

curl -sSL https://raw.githubusercontent.com/mykepredko/rPi_scripts/main/debianFix.sh | bash

EDIT:
The original curl statement was pointing to the wrong file. Apologies and thanx to @Sineos for finding that.

I’ve tested it on the Raspberry Pi OS LITE (32-BIT) on the 4B and CM4 and I’m hoping people with other SBCs and operating systems will give it a try. At some point I’ll reconfigure one of my printers to again use a CB1 and see what happens there.

The process the script follows is:

  1. The command apt-cache policy udev is executed and the output is checked to see if the installed udev is “247.3-7+deb11u2” - if it isn’t, then the script exits. if the installed udev is “247.3-7+deb11u2” then the following steps are executed.
  2. Next the backport link (deb http://ftp.debian.org/debian bullseye-backports main non-free contrib) is added to the end of the sources.list file in the system.
  3. The command sudo apt update is run. If there are “NO_PUBKEY” key errors returned then the next step executes, else execution skips to 6.
  4. The two error “NO_PUBKEY” keys are added to the system using the sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys [key] command.
  5. sudo apt update is run again to ensure that all the required actions take place successfully.
  6. The command sudo apt install udev -t bullseye-backports is executed.
  7. The user is prompted to execute sudo reboot.

Please feel free to review the script. I am not doing anything nefarious in the script (or at least not intentionally) but I’m not a bash script guru and any comments or warnings from experts would be appreciated.

4 Likes

Nice work @mykepredko
Indeed, I did think about it as well. If done as a script, we should extend the checks and make it less depending on the RPi version, since users might have different Linux flavors installed.

Maybe something along the lines of:

#!/bin/bash

is_udev_version_deb11u2() {
    # Check if udev is installed
    if dpkg -l | grep -q '^ii\s*udev'; then
        # Check the version
        udev_version=$(dpkg -l | grep '^ii\s*udev' | awk '{print $3}')
        if [[ "$udev_version" == *deb11u2* ]]; then
            return 0  # true
        fi
    fi
    return 1  # false
}

contains_bullseye_backports() {
    # Check in /etc/apt/sources.list
    if grep -q "bullseye-backports" /etc/apt/sources.list; then
        return 0  # true
    fi

    # Check in files within /etc/apt/sources.list.d/
    for file in /etc/apt/sources.list.d/*; do
        if grep -q "bullseye-backports" "$file"; then
            return 0  # true
        fi
    done

    return 1  # false
}

download_bullseye_backports_key() {
    local key_url="http://ftp.debian.org/debian/dists/bullseye-backports/Release.gpg"
    wget -O /usr/share/keyrings/debian11-backports-archive-keyring.gpg "$key_url"
}

add_bullseye_backports_to_sources() {
    local repo_string="deb [signed-by=/usr/share/keyrings/debian11-backports-archive-keyring.gpg] http://ftp.debian.org/debian bullseye-backports main non-free contrib"
    echo "$repo_string" | tee -a /etc/apt/sources.list.d/bullseye-backports.list > /dev/null
}

# Update the system first
apt update
apt upgrade -y

# Check for buggy udev version and remedy it
if is_udev_version_deb11u2; then
    if contains_bullseye_backports; then
        echo "Backports already available. Installing udev from backports."
        apt install udev -t bullseye-backports -y
    else
        echo "Setting up bullseye-backports repository..."
        download_bullseye_backports_key
        add_bullseye_backports_to_sources
        apt update
        echo "Backports installed. Installing udev from backports."
        apt install udev -t bullseye-backports -y
    fi
else
    echo "System seems OK. No need to install new udev. Exiting"
fi

This is largely untested, I just typed it more or less freestyle, so it might be some pseudo-code. I would need to find a RPi and set up a test.

Edit:

  • I think the buggy version deb11u2 only
  • Since the apt key is officially deprecated, I tried to do it “correct” this time. This is more involved than the apt method, that’s why I chose not to use it in the original fix. But as I said: Untested

Edit 2:
The link in your original post is pointing to another file but through tedious research and work, I was able to find the right one :wink:

Edit 3:
The way it is setup, it needs to be called with sudo

Thanx - I know it could have been done better.

Now, when I researched this, it seems that the problem is a) pretty pervasive and b) binary. Pervasive in that it’s in quite a few *nix distributions and binary as if it’s not there, it’s not a problem.

Regardless, I’d be interested in finding out what happens when people using hosts other than an rPi run the script.

I’ll go through the various methods in a few hours and report back.

Rather than return “0” for true and “1” for false, how about using the true and false Linux commands? I always find that the statement “return 0 # true” causes my head to spin and is distracting from being able to naturally follow the logic.

https://www.ibm.com/docs/en/aix/7.2?topic=t-true-false-command

When I’ve looked at the script I wrote operates, it seems that apt upgrade -y executes in KIAUH.

Also, in your code, you’re not handling the NO_PUBKEY condition - is this deliberate?

I was going by Debian bug report for the test and it seems to indicate that you need to look for deb11u1:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1050333

Is there an authoritative one out there?

I’ll try your dpkg check on a newly imaged SD Card (all the ones I have right now have run my script and the value is different).

Thanx for the catch - I’ve edited the original post

Sorry, what needs to be?

In shell scripts, the logic generally is

  • return 0 for true
  • return anything not 0 for false
  • working with true and false in a boolean sense can be tricky in shell and has ugly caveats

Hmm. Seems inconclusive: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1035094
The Debian Bug Report you quoted seems to be a different issue.

The if could be modified to check for both. Would likely do no harm:

if [[ "$udev_version" == *deb11u1* ]] || [[ "$udev_version" == *deb11u2* ]]; then
  • The apt key method is deprecated. It still works but is no longer recommended
  • The function download_bullseye_backports_key will get the key and put it into /usr/share/keyrings/debian11-backports-archive-keyring.gpg
  • The function add_bullseye_backports_to_sources will add
    deb [signed-by=/usr/share/keyrings/debian11-backports-archive-keyring.gpg] http://ftp.debian.org/debian bullseye-backports main non-free contrib
    
    which then uses this downloaded key explicitly.
  • Adding the backports will only happen if not already present. If you use, e.g. a pristine Debian or Armbian, backports are present by default. This is done with the function contains_bullseye_backports

The entire script as proposed above needs root rights to run, so it needs to be called with sudo

We could also add a check if the script is called with proper rights, e.g.

...

is_root_user() {
   if [ "$(id -u)" -ne 0 ]; then
        echo "This script must be run as root. Please use sudo or run as the root user."
        exit 1
    fi
}

# Check for root rights
is_root_user

# Update the system first
apt update
apt upgrade -y

# Check for buggy udev version and remedy it
...

Edit:

I would not rely on the fact that KIAUH is run first. If the script runs it, we make sure that we have a defined starting point and the user is not surprised when running the upgrade later.

I have turned the instructions Debian Bullseye Bug causing Klipper to no longer find the printer board - #8 into a shell script: https://raw.githubusercontent.com/Sineos/useful_bits/main/Linux/fix_debian_udev.sh

It will:

  • Check if it is executed on Debian 11
  • Check if the installed udev contains the buggy version string
  • Check if run as root or under root rights
  • Update the system to the latest versions via apt update and apt upgrade
  • If Debian 11 AND buggy udev AND root is found, it will:
    • Check if the Debian 11 backports repository is already present → If not, download the repository signing key and install the repository
    • Install the fixed udev from the backports repository

Run it via

curl -sf -L https://raw.githubusercontent.com/Sineos/useful_bits/main/Linux/fix_debian_udev.sh | sudo bash

Above command will run the script as root
Only do this if you trust me or if you have verified the script beforehand.

Any tests would be appreciated. I did test it on various different OS versions, like MainsailOS, Pi OS lite etc.

2 Likes

To end off this thread, I’ve done a fairly extensive experiment to try and figure out what is the best approach to get to the ultimate goal which is to have an OS/firmware controller installation that can be updated without physically accessing the controller.

In terms of updating a controller, I believe the optimum (maybe only) way to do this is with a Katapult (formerly “CanBoot”) installation with a CAN network specified. I know that some people don’t like using a CAN bus interface to their toolheads but this approach will work even if there are no CAN devices attached to the controller. I suspect, but have not tested, that this approach will work with a controller with an unused UART in place of the CAN interface.

Some of the results surprised me and, thanks to @Sineos pointing out the “MainsailOS”, I have a better Raspberry PI OS option to load. I’m going to try and present as much information as possible so that other people can replicate my tests on different hardware combinations. I’d be interested in hearing people’s results with controllers like the Raspberry Pi Zero.

This is a long post, so rather than slog through it, I suggest you scroll down to the “Observations” and “Conclusions” at the end before reading through the procedure information.

Apparatus

In this experiment, I used the following host systems:

  • Raspberry Pi 4B connected to an Octopus controller via USB. The Octopus has a fan connected to the “FAN0” Port
  • Raspberry Pi CM4 connected to a Manta M8P controller via the board’s internal USB. The Manta has a fan connected to the “FAN0” Port.
  • BTT CB1 attached to a “RPI 4B adapter board” and connected to an Octopus via USB

For Firmware installation I used:

  • Raspberry Pi Installer

For all other installations the host network connection was used and specified using SSH. I used a Linux Ubuntu Terminal for SSH access to the hosts.

Test Procedure

Tests were run on different host/controller combination in terms of using the standard (“Lite” in the case of the Raspberry PIs) Operating Systems with these different update approaches:

  • “Vanilla” or no updates
  • “Update/Upgrade” which consisted of running sudo apt update followed by sudo apt upgrade -y
  • “Myke Script” which is running the script presented at the start of this thread
  • “Sineos Script” which was the script presented in the previous post to this thread

The following procedure was used on each of the host/controller combinations for each of the test configurations:

  1. Load Selected Operating System into the host for the test using Raspberry Pi Installer. The options are:
    1.1. 32-Bit Raspberry Pi OS Lite (for the Raspberry Pi 4B and CM4)
    1.2. 64-Bit Raspberry Pi OS Lite (for the Raspberry Pi 4B and CM4)
    1.3. CB1 Operating System provided by BTT
    1.4. 32-Bit MainsailOS Operating System (for the Raspberry Pi 4B and CM4)
    1.5. 64-Bit MainsailOS Operating System (for the Raspberry Pi 4B and CM4)
  2. Login using SSH into the host
    2.1. When MainsailOS is used, check to see that the Mainsail web page was available
  3. When testing the CB1 host, execute the sudo nmcli dev wifi connect [NetworkName] password "[Password]" from an Ethernet connection to ensure CB1 wifi is working. Reboot the CB1 and login again after executing this command
  4. Run and record the results of apt-cache policy udev This is compared to after the updates to see if any changes were made
  5. Perform the specified update procedure:
    5.1. For “Vanilla” do nothing (this includes doing the reboot specified for the other approaches)
    5.2. For “Update” execute sudo apt update followed by sudo apt upgrade -y and then reboot
    5.3. For "Myke Script’ execute curl -sSL https://raw.githubusercontent.com/mykepredko/rPi_scripts/main/debianFix.sh | bash and then reboot
    5.4. For "Sineos Script’ execute curl -sf -L https://raw.githubusercontent.com/Sineos/useful_bits/main/Linux/fix_debian_udev.sh | sudo bash and then reboot
  6. If a reboot was performed in the previous step, then login to the host via SSH
    6.1. Execute apt-cache policy udev again to see what changes were made to the system
    6.2. If the host is running MainsailOS, check to see that the Mainsail web page is available after reboot
  7. If MainsailOS is NOT running, execute the following commands to load Klipper, Moonraker and Mainsail:
    7.1. sudo apt-get install git -y
    7.2. git clone https://github.com/dw-0/kiauh.git
    7.3. ./kiauh/kiauh.sh
    7.4. Install Klipper with Python 3.x and one instance.
    7.5. Install Moonraker
    7.6. Install Mainsail
    7.7. Exit out of KIAUH
  8. Install Katapult and make a firmware image with the commands:
    8.1. git clone https://github.com/Arksine/Katapult
    8.2. pip3 install pyserial
    8.3. cd Katapult
    8.4. make menuconfig
    8.5. For Octopus Select STM32, F446, 12MHz Clock Reference
    8.6. For Manta Select SMT32, G0B1
    8.7. Quit from menuconfig and Save
    8.8. make
  9. Make a Klipper firmware image using the commands:
    9.1. ~/klipper
    9.2. make menuconfig
    9.3. For Octopus Select STM32, F446, 12MHz Clock Reference, USB to CAN bus bridge, CAN bus (on PD0/PD1), 500000 CAN bus speed
    9.4. For Manta Select SMT32, G0B1, USB to CAN bus bridge, CAN bus (on PD12/PD13), 500000 CAN bus speed
    9.5. Quit from menuconfig and Save
    9.6. make
  10. Put controller into DFU mode.
    10.1. For Octopus, insert the jumper on the “BOOT” pins and press reset.
    10.2. For Manta, Press and hold down the “BOOT” button followed by pressing and releasing “RESET” and then releasing “BOOT”
    10.3. Confirm the controller is in DFU mode by using the command lsusb and looking for the entry “ID 0483:df11 STMicroelectronics STM Device in DFU Mode”
  11. Flash the Katapult firmware using the command sudo dfu-util -a 0 -D ~/Katapult/out/katapult.bin --dfuse-address 0x08000000:force:mass-erase:leave -d 0483:df11
    11.1. Check that flash operation is complete using the lsusb command and seeing that the USB port is now labeled “OpenMoko”
  12. Get the MCU serial number using the command ls /dev/serial/by-id/. The returned string with be copy and pasted into the next command.
  13. Flash the Klipper firmware image into the controller using the command python3 ~/Katapult/scripts/flash_can.py -d /dev/serial/by-id/[mcuSerial] where “[mcuSerial]” is the string returned from the previous step.
  14. Setup the CAN0 device:
    14.1. Create the CAN0 file using the command sudo nano /etc/network/interfaces.d/can0
    14.2. Put in the following contents of the file and then Ctr-X and Save:
allow-hotplug can0
iface can0 can static
 bitrate 500000
 up ifconfig $IFACE txqueuelen 256
 pre-up ip link set can0 type can bitrate 500000
 pre-up ip link set can0 txqueuelen 256
  1. Execute sudo reboot to restart the host
  2. Check the operation of the system by carrying out the following tasks:
    16.1. SSH into the host
    16.2. Execute ls /dev/serial/by-id and expect to see “No Such File or Directory”
    16.3. Check to see that Mainsail web page is active
    16.4. Execute flash_can.py -I can0 -q and you should see a "Detected UUID: " with a 12 character hex string following and then “, Application Klipper”

If everything above is good, then the initial programming is complete.

Now, to test if the controller can be updated without accessing, change the Klipper firmware so that the fan on the FAN0 port on the controller runs on firmware startup.

  1. Change the firmware to turn on the FAN0:
    1.1. Execute cd ~/klipper (if not already in the folder)
    1.2. Execute make clean
    1.3. Execute make menuconfig
    1.4. If Octopus, enter PA8 into the “GPIO pins to set at micro-controller startup”
    1.5. If Manta, enter PE0 into the “GPIO pins to set at micro-controller startup”
    1.6. Quit and Save
    1.7. Execute make
  2. Get the controller CAN bus UUID using the command ~/Katapult/scripts/flash_can.py -i can0 -q and save it for copy and pasting in the next step
  3. Setup the Flashing operation with the command python3 ~/Katapult/scripts/flash_can.py -r -u [uuid] where “[uuid]” is the value returned from the previous step
  4. Get the controller serial ID using the command ls /dev/serial/by-id/ and save it for copy and pasting in the next step.
  5. Program the controller with the updated klipper firmware using the command python3 ~/Katapult/scripts/flash_can.py -d /dev/serial/by-id/MCU Serial from previous where “MCU Serial from previous” is the string returned in the previous step.
  6. If everything works correctly, the fan attached to the controller board will start running

After doing all this and the fan is running, I consider the operation a “PASS” .

If anything does not work as expected or return an invalid response then the process is repeated from the start and if the same error is encountered, then the result is a “FAIL”.

If the conditions of the script are not met, then the test was stopped (in the case of my script where I knew nothing would happen) or it was continued but marked as not executing as expected (@sineos’ script which indicated that the udev wasn’t updated, which is what I thought was the point of the script).

Observations

The test results were recorded in this spreadsheet: 2023.09.18 - Raspberry Pi Klipper & Katapult OS Build and Program Results.zip (19.2 KB)

Netting out the results looks like:

  1. The BTT is a real PITA to work with.
    1.1. A big part of the issue is that the image cannot be updated in the Raspberry Pi Imager to specify a WiFi network - editing the configuration file as described in the documentation works about 50% of the time. I found that the nmcli dev wifi connect command works 100% of the time, but needs an Ethernet connection to enter it in.
    1.2. I never did figure out how to change the URL the CB1 appears on the network. “BTT-CB1.hitronhub.home” seems to be the only thing it will appear as which limits the number of devices on a network.
    1.3. I never figured out how to change the primary user from “biqu”. This, along with the locked in “BTT-CB1.hitronhub.home” comes across to me as a huge potential security problem (especially if you don’t change the default password from “biqu”).
    1.4. If anybody knows how to change these preset values, please let me know.
  2. The two scripts (@sineos’s and mine) did not change the system or the test results in the way that I expected.
  3. The host and controller programming process outlined here worked very reliably for all three hosts and two controller boards.

Conclusions

  1. I believe I have a way for doing firmware updates on CAN equipped and Katapult programmed controllers without having to access the hardware.
    1.1. I’m not sure how important this is to other people but unless I have a printer designed that the controller can be easily accessed (which I’ve never seen on any commercial printers with the exeception of the Prusa i3) I’m not going to do firmware updates unless it’s deemed really important
    1.2. Klipper’s printer.cfg file eliminates probably 90% of the need for accessing a printer’s controller, being able to update the Klipper firmware this way picks up the last 10%
  2. When I look at the results, I feel like the most reliable option is to use MainsailOS along with sudo apt update and sudo apt ugrade -y
    2.1. The scripts we came up with don’t seem to add to the effectiveness of the overall system
  3. While long, the programming process outlined here was very reliable and repeatable. I believe that there are some real opportunities here for automating the process which will make Klipper more accessible to users that are not programmers and find the host setup and controller firmware programming to be overwhelming. Automating this process would greatly reduce the amount of work setting up a new printer and make Klipper more approachable for new users
    3.1. Mainsail OS further reduces the remaining workload and, I think, the resulting process could be very slick.
  4. I am going to reach out to BTT and see if they are receptive to working on the CB1’s OS image. Right now the supply of CM4s still seems to be recovering from the Covid shortages (the rPi 4B seems to have a good supply and reasonable prices) so the CB1 is a reasonable choice - but once the CM4 pipeline fills up and prices go down, I don’t see the CB1 being a viable competitor against the “genuine” article, which is a shame because I like the hardware and think that with a bit of work could be a pretty decent host.

Sorry for all this - it was a lot of work and I think I learned some things that will be useful to others and I am confident that I have a process in which I can update Klipper firmware without the bother of turning my printers upside down (or at least on their sides with pillows).

3 Likes

In depth and to the point. I think more makes of things that work should shine while it is difficult, they should still shine.

And by shine, I basically mean hold virtue. I like fixtures and builds. The only thing that keeps me from building a machine to call my own is lack of “shine” or “virtue.” It is hard these days to make a well-rounded Printer and have it accessible to others (including myself).

For instance, I received some help a while back w/ adding another endstop for my current printer on this forum.

There was no way in “hell” I was goin’ to add another endstop as a cure to my woe. But, it got past me and it worked. Inevitably, simple things sometimes work. Endstops!

Seth

P.S. W/ all the hardware out there and SiP and SoCs, it is never just so to say press the orange button and things are cured. I have really begun to notice this as fact. I am still, after a good six months, trying to get my wiring correct and situated. I could probably get some good connectors, lengthen the wiring, and fasten it. Done but I just would like to say, w/out people assisting umpteen builds pile up and some are lost…

Yeppers1

That build is from a person online at printables. Anyway, here is the link so I do not get anyone upset: Compact PET Filament Machine by mirabatek | Download free STL model | Printables.com

PET!

update

Even as my prints somehow get better in time, somehow, I learn a bit. “No stress, less stress, and things will fall in place slowly…”

3 Likes

Interesting write up. Thanks.

Just to be clear, one should only configure Klipper in USB to CANbus bridge mode if there is an actual functional CANbus with at least 1 additional device attached to it. If these requirements are not met, the Klipper code may appear to work, but will be prone to hard to debug errors. (Eventually some number of canbus messages will go without acknowledgement, fill the available buffers, and cause Linux and/or the micro-controller to pause waiting for those acknowledgements.)

Cheers,
-Kevin

I haven’t seen any unexplained issues but I’ve not had the printers running this way for anything approaching a long period of time (not more than 24 hours). I’ll be on the look out for that and report if anything comes up.

Thanx for the information.

FWIW, if you want to test this, run FIRMWARE_RESTART a bunch of times. The buffers will fill and the “bridge mcu” will appear to go offline.

Cheers,
-Kevin

1 Like

The FIRMWARE_RESTART button in Mainsail?

Is there a command line instruction (like sudo service klipper restart) that can be run repeatedly and monitored to see when the system goes tilt?

I’m not sure - my understanding of the code is that running “canbus bridge mode” without a canbus is likely to result in failure, and it is therefore not something I’ve spent time on.

In retrospect, I suspect running RESTART (on the klipper console interface) many times is likely to induce failures in this non-recommended setup. (As opposed to FIRMWARE_RESTART or system klipper restart.)

-Kevin

“Likely” is an understatement - there seems to be a problem 75% of the time when starting up.

Restarting Klipper from Mainsail results in a system that works about 30% to 40% of the time.

So, while the process I followed here is good for determining whether or not a system can run after running the various tests (manual updates and scripts) it is not a recipe for a working system.

@koconnor is correct (no surprise), Katapult should ONLY be used in a system with connected CAN devices. It should not be used in a system where there are no CAN devices connected to the main controller.

I would not want to state this so sweepingly. I’m running Katapult in pure USB mode on all my boards because it makes updating much easier.
My understanding is that you should not be using USB to CANbus bridge mode without any CAN devices.

2 Likes

Thank you for the correction.

Yes - the restriction is on using Klipper’s “USB to CANbus bridge mode” - it only makes sense to use that mode when there is an actual physical CANbus. I’m not aware of any limitations with Katapult.

Cheers,
-Kevin

1 Like

It’s a late night for me right now, so I may not be understanding the topic, testing, and conclusion in it’s entirety. Please tell me where I have gone wrong (it won’t be the first nor the last time).

  1. This thread is about backport of a bug in Debian Bullseye (Deb 11 - released June 2021)
  2. This issue does not appear in Debian Bookworm (Deb 12 - released June 2023)
  3. Methodology for determining if bug is present in MCU build and remediation steps.
  4. [Off topic - a little but pertinent to discussion] How to update the MCU without “physically updating the controller” (?)

If these are correct assumptions, my 2 cents:
1 & 2 – Debian Bookworm is stable at a point release. I don’t see an issue with telling people to update (if they want) to the latest Debian build. Not only is the latest version stable and supported but there are many updates and fixes that may help with things we didn’t know that needed to be fixed or improved.

3 – Instead of detection and remediation, detail the process for updating Bullseye to Bookworm. (See: How to Upgrade to Debian 12 from Debian 11 for comprehensive instructions) Actually, these instructions could be packaged and “run once” script. This script could be an addition to KIAUH. Hmmmm.

4 – When you say “not physically touching the controller” I am assuming you mean not running a terminal or physically connecting a KVM (keyboard, video, mouse) to a Raspberry Pi MCU, yes? Is this correct? If so, may I recommend setting up your RPi for PXE boot. I know version 4 can do it but I don’t know about version 3 or earlier. You can have PXE set to retrieve a fully installed and operational klipper image from a NAS or a USB storage key attached to your router.

I hope I haven’t confused or muddy this conversation with incorrect assumptions. Thank you for reading.

Correct. Still many distributions use Bullseye, especially the RPi based ones. Upgrading to Bookworm of course is an option, but I’d only recommend it for people who have some Linux experience.

See Debian 11 (Bullseye) udev bug - No board or serial found

I have addressed this to th33exitus already

Nice but all what we do here is targeted at beginners and not people who anyway know what they are doing.

2 Likes

2 posts were split to a new topic: No serial found

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.