This interface is, in some ways, much easier to work with than the previous ones I’ve dealt with. Less pins to worry about lining up, easier to adapt parts on hand, and so on. That said, it does have its drawbacks, such as possibly requiring different software to update and also a new serial interface board since it doesn’t work with USBASP like the other lights.
Serial USB to TTL CH340 Module device
The one linked specifically works great as-is, so I suggest using that one. There are others out there that may require soldering in a resister or certain diode, but these modules do not need it.
Jumper wires with Dupont connectors
The CH340 linked above comes with some wires that have M-F connectors which can help with some parts of this but for most probes you will likely need F-F.
Flashing kit from Hank (US Source) or another probe with at least three pogo pins in line, such as an HQ ProgKey.
I have used both my HQ ProgKey and Hank’s probe. Both work fine, but the HQ ProgKey can be used on a wide variety of lights thanks to its 4-over-4 layout. I ordered a couple batches of the HQ ProgKey from OshPark and used soldering paste and a reflow plate to attach pogo pins to the ProgKey. For many people that’s probably overkill, but it does work well for updating my non-Hank lights.
Why update? It depends.
Sometimes there are important software bug fixes. For example, the stock TS10 firmware had a couple problems. The aux lights stayed on while the main emitters were on, and it lacked low voltage protection for its single color aux LEDs, so the aux LEDs (especially on high) could drain a battery to dangerously low levels.
There are other reasons to update, such as:
0.1
lumens to 0.01
lumens which is a significant decrease.If using Hank’s kit, with the four pin side up, use the first three pins left to right:
R
/ RX+TX
-
/ GND
+
/ 3V3
If using a custom adapter, wire the pins up similarly:
R
/ RX+TX
-
/ GND
+
/ 3V3
On the CH340 device linked above, the RX
and TX
pins are separate but they
come with a jumper. The RX/TX
wire needs to connect to both pins, which
can be done in a variety of ways. Some people prefer to solder a pin on the
jumper, or solder a wire across both, or connect two wires and splice them into
a single line midway. Personally, I pushed a pogo pin into a Dupont connector
and simply wedged it the opening at the top of the jumper. Pressure from the
neighboring wires keeps it in place and it makes a good enough connection for
this purpose. A similar trick would likely work with a male Dupont connector
end. Soldering is a more reliable and permanent solution, but thus far my
workaround has not
failed.
Unscrew the head from the light and look inside. These lights will have three
pads and they are hopefully labeled properly as either: R - +
/ + - R
.
Align the probe so the pins match the pads.
Unfortunately at the moment there isn’t a way to program with these chips from Android, so use a computer with the right drivers.
This could be Linux, Windows, or macOS. Requirements vary by platform.
Plug the USB device in and let the OS detect it and install drivers.
On Windows:
Locate the port labeled “USB-SERIAL CH340” and note the port listed after
For example COM7
.
If there is a !
and the same port is in the list twice:
On Linux, the device will be /dev/ttyUSB<id>
for example, /dev/ttyUSB0
. If
there are multiple devices, the correct device is likely the highest one or one
with the newest timestamp.
On macOS, the device will be /dev/cu.usbserial-<id>
, the ID will vary by
hardware. If there are multiple devices, the correct device is likely the one
with the newest timestamp.
Get the correct firmware file, or compile one.
Do a firmware check on the light (15+ clicks, note each digit it flashes) and compare the date and IDs returned. Last four digits should be the Anduril model ID. This is mostly for reference in case there is a discrepancy between what the light was running before and what is loaded after.
For the Wurkkos TS10 or Sofirn SP10 Pro, check at https://www.ghart.com/blf/firmware/hex_files/sofirn_anduril2/ for the latest revision for the light in question. As of this writing, the newest files for the Wurkkos TS10 is anduril.2022-07-19.wurkkos-ts10.hex, Sofirn SP10 Pro is anduril.2022-07-23.sofirn-sp10-pro.hex – Those are likely to change over time.
For other lights, check http://toykeeper.net/torches/fsm/anduril2/
There are two ways to update currently, with either avrdude or pymcuprog.
The recently released avrdude 7.0 now supports updating through these interfaces and avrdude may already be familiar for those updating firmware since it is a common way to update other lights that use USBASP boards.
The first thing to try is to ping the device to ensure that avrdude can talk to both the CH340 device and the target chip. Replace the serial port in the following command with the port used by the CH340 device:
.\avrdude.exe -p attiny1616 -c serialupdi -P com7 -n
The output should look like this:
avrdude.exe: UPDI link initialization OK
avrdude.exe: Device is in SLEEP mode
avrdude.exe: NVM type 0: 16-bit, page oriented write
avrdude.exe: Entering NVM programming mode
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.01s
avrdude.exe: Device signature = 0x1e9421 (probably t1616)
avrdude.exe: Leaving NVM programming mode
avrdude.exe done. Thank you.
If there is an error, most likely the probe was not correctly contacting all of the correct pins. Check and correct the probe placement and try again.
A good practice is to read the old firmware in case the new firmware has an undesirable behavior. That way it’s possible to reload the previous firmware to get back to the prior state.
.\avrdude.exe -p attiny1616 -c serialupdi -P com7 -Uflash:r:old-firmware.hex
The output should look like this:
avrdude.exe: UPDI link initialization OK
avrdude.exe: Device is in SLEEP mode
avrdude.exe: NVM type 0: 16-bit, page oriented write
avrdude.exe: Entering NVM programming mode
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.01s
avrdude.exe: Device signature = 0x1e9421 (probably t1616)
avrdude.exe: reading flash memory:
Reading | ################################################## | 100% 4.02s
avrdude.exe: writing output file "old-firmware.hex"
avrdude.exe: Leaving NVM programming mode
avrdude.exe done. Thank you.
Now it is time to write the new firmware. Replace the filename in the following command with the correct firmware filename.
.\avrdude.exe -p attiny1616 -c serialupdi -P com7 -Uflash:w:anduril.2022-07-19.wurkkos-ts10.hex
The output should look like the following:
avrdude.exe: UPDI link initialization OK
avrdude.exe: Device is in SLEEP mode
avrdude.exe: NVM type 0: 16-bit, page oriented write
avrdude.exe: Entering NVM programming mode
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.01s
avrdude.exe: Device signature = 0x1e9421 (probably t1616)
avrdude.exe: NOTE: "flash" memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude.exe: erasing chip
avrdude.exe: reading input file "anduril.2022-07-19.wurkkos-ts10.hex"
avrdude.exe: input file anduril.2022-07-19.wurkkos-ts10.hex auto detected as Intel Hex
avrdude.exe: writing flash (9562 bytes):
Writing | ################################################## | 100% 3.87s
avrdude.exe: 9562 bytes of flash written
avrdude.exe: verifying flash memory against anduril.2022-07-19.wurkkos-ts10.hex:
avrdude.exe: input file anduril.2022-07-19.wurkkos-ts10.hex auto detected as Intel Hex
Reading | ################################################## | 100% 1.85s
avrdude.exe: 9562 bytes of flash verified
avrdude.exe: Leaving NVM programming mode
avrdude.exe done. Thank you.
Now that the firmware is written to the light, skip ahead to the section on performing a factory reset.
If avrdude is not a viable choice, install Python and pymcuprog
.
On Windows, there are two main ways to get Python:
After installing python, open a command prompt and install pymcuprog
by
running pip install pymcuprog
There may be some quirks getting the paths right for pymcuprog
if Python was
installed from the Microsoft Store, since the location for the packages is not
in the path by default.
Try running pymcuprog
from a terminal, PowerShell, or command prompt, if it
prints its usage output, then it’s OK to proceed. Otherwise, check and correct
the path or python issues.
In Explorer, first locate the correct folder. It will be something similar to
C:\Users\<name>\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_<id>\LocalCache\local-packages\Python39\Scripts
– Copy that full path.
The correct path will also be found in the output of
python -c "import sys; print('\n'.join(sys.path))"
it will be the entry similar to the path mentioned previously.
The first thing to try is to ping the device to ensure that pymcuprog
can talk
to both the CH340 device and the target chip. Replace the serial port in the
following command with the port used by the CH340 device:
First, try a ping to see if the device responds to a probe:
pymcuprog ping -d attiny1616 -t uart -u com7
The output should look like the following if it’s successful:
Connecting to SerialUPDI
Pinging device...
Ping response: 1E9421
Done.
If there is an error, most likely the probe was not correctly contacting all of the correct pins. Check and correct the probe placement and try again.
Unlike avrdude, pymcuprog does not automatically erase before writing, so do a manual erase:
pymcuprog erase -d attiny1616 -t uart -u com7
The output should look like the following:
Connecting to SerialUPDI
Pinging device...
Ping response: 1E9421
Chip/Bulk erase:
- Memory type eeprom is conditionally erased (depending upon EESAVE fuse setting)
- Memory type flash is always erased
- Memory type lockbits is always erased
Erased.
Done.
Change to the directory where the firmware file was downloaded, for example:
cd ~\Downloads
Now write the firmware file. Replace the filename with the correct firmware filename that matches the light.
pymcuprog write -d attiny1616 -t uart -u com7 --verify -f anduril.2022-07-19.wurkkos-ts10.hex
The output should look like the following:
Connecting to SerialUPDI
Pinging device...
Ping response: 1E9421
Writing from hex file...
Writing flash...
Verifying flash...
OK
Done.
After writing the firmware, it’s a good idea to do a factory reset. Hold in the power button while reassembling the light and let go of the button when the light goes out.
On some tail switch lights it helps to fully tighten the tube first, then back it off enough that the aux lights (or main emitter) goes out, then hold the button while twisting it back fully closed.
This post was based in part on information from the following threads:
]]>I have tried several different tactics over the years but the best solution I’ve found so far is to use a Raspberry Pi as a dedicated serial console multiplexer (MUX). The title seemed fitting as it takes multiple inputs (serial consoles) and manages a single output (screen) though the user controls the active input in this case.
Raspberry Pi (or equivalent)
Though this post is geared toward using a Raspberry Pi with Raspbian as a serial console server, many of the techniques used are general and could be adapted to a variety of platforms.
USB serial hub with lots of ports
Like this 13-port USB 2.0 hub. Linux doesn’t seem to get along with lots of USB 3.0 ports and there isn’t any compelling reason to use USB 3.0 for serial consoles anyhow.
USB serial devices
Varies by device, some have USB consoles, some have serial ports with 9-pin or RJ45 connectors. Some may require null modem adapters. This is mostly beyond the scope of what I’m trying to cover here. I’m going to assume you can already talk to the devices with USB serial in some way.
Speaking of USB serial, I like these USB serial adapters for devices with regular non-USB serial ports.
GNU screen
GNU screen is capable of talking to serial ports directly, so there is no need
to use a separate terminal emulator program such as minicom
. Though if you
prefer to use a different terminal program in each screen or maybe using
tmux
, similar tactics should work there, too.
Setting up the Pi is out of scope here, I’m going to assume you have a working pi connected to your network.
Using a wired connection is best for real-time interactive work in SSH, but depending on your AP and wireless setup it may still work OK that way.
Connect all of the USB serial devices to the hub and connect the hub to the Pi. To ensure things are probed in the correct and expected order, rebooting the Pi is a useful measure at this point.
From here on, everything is done over SSH connected to the Pi. Use the SSH program of your choice (e.g. OpenSSH, SecureCRT, PuTTY).
Before setting up the consoles let’s take the time to map each port to a consistent and useful name. Rather than having them numbered, we can set it up so that each port is labeled after the device. This makes keeping the screen names and purposes easier to manage over time. If you are lucky and each one has a unique set of properties, then it won’t even matter which order or ports they plug into or what order they probe in.
Look at the connected USB ports:
$ ls -l /dev/ttyUSB*
crw-rw---- 1 root dialout 188, 0 Mar 29 11:36 /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 1 Mar 29 11:42 /dev/ttyUSB1
crw-rw---- 1 root dialout 188, 2 Mar 29 11:53 /dev/ttyUSB2
crw-rw---- 1 root dialout 188, 3 Mar 14 16:08 /dev/ttyUSB3
crw-rw---- 1 root dialout 188, 4 Mar 11 14:04 /dev/ttyUSB4
For each of these, go through the device information and find useful and unique
properties which identify a given device. This will give us enough information
to craft udev
rules to setup the port names. The command probes the entire
stack to reach the device, but the one you are interested in is usually a few
entries into the output and will look similar to what is shown below.
Replace x
in the command with the device number, and repeat the command for
each ttyUSB
device.
$ sudo udevadm info --name=/dev/ttyUSBx --attribute-walk
[...]
looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.1/1-1.1.3/1-1.1.3.2':
[...]
KERNELS=="1-1.1.3.2"
ATTRS{manufacturer}=="Silicon Labs"
ATTRS{idProduct}=="ea60"
ATTRS{devpath}=="1.1.3.2"
[...]
ATTRS{serial}=="xxxxxx01"
[...]
ATTRS{idVendor}=="10c4"
This is an ideal case. The device has a unique vendor ID (idVendor
), product
ID (idProduct
), and serial number (serial
). Not every device will have a
serial number and multiple devices may even have the same serial number, which
complicates matters.
The trickier cases may have to rely on the device path (devpath
) which means
they have to remain plugged into the same USB port.
Create or edit /etc/udev/rules.d/99-usb-serial.rules
and add rules based on
the attributes for each device along with its name.
$ sudo vi /etc/udev/rules.d/99-usb-serial.rules
# These two devices are similar but have unique serial numbers.
SUBSYSTEM=="tty", \
ATTRS{idVendor}=="10c4", \
ATTRS{idProduct}=="ea60", \
ATTRS{serial}=="xxxxxx01", \
SYMLINK+="serial_edge"
SUBSYSTEM=="tty", \
ATTRS{idVendor}=="10c4", \
ATTRS{idProduct}=="ea60", \
ATTRS{serial}=="xxxxxx02", \
SYMLINK+="serial_server"
# These two devices don't have a serial number,
# so we have to use the device path
SUBSYSTEM=="tty", \
ATTRS{idVendor}=="067b", \
ATTRS{idProduct}=="2303", \
ATTRS{devpath}=="1.1.3.7.4", \
SYMLINK+="serial_switch1"
SUBSYSTEM=="tty", \
ATTRS{idVendor}=="067b", \
ATTRS{idProduct}=="2303", \
ATTRS{devpath}=="1.1.3.7.6", \
SYMLINK+="serial_switch2"
# This device has a unique vendor and product ID, but use the serial
# number anyhow in case a similar device is added in the future.
SUBSYSTEM=="tty", \
ATTRS{idVendor}=="0403", \
ATTRS{idProduct}=="6001", \
ATTRS{serial}=="xxxxxx03", \
SYMLINK+="serial_adapter"
Now reload the rules and re-trigger the device detection:
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger --attr-match=subsystem=tty
Now look at the mapped devices with our nice names:
$ ls -ld /dev/serial*
drwxr-xr-x 4 root root 80 Oct 24 15:09 /dev/serial
lrwxrwxrwx 1 root root 7 Oct 24 15:09 /dev/serial1 -> ttyAMA0
lrwxrwxrwx 1 root root 7 Oct 24 15:09 /dev/serial_edge -> ttyUSB2
lrwxrwxrwx 1 root root 7 Oct 24 15:09 /dev/serial_server -> ttyUSB1
lrwxrwxrwx 1 root root 7 Oct 24 15:09 /dev/serial_switch1 -> ttyUSB4
lrwxrwxrwx 1 root root 7 Oct 24 15:09 /dev/serial_switch2 -> ttyUSB3
lrwxrwxrwx 1 root root 7 Oct 24 15:09 /dev/serial_adapter -> ttyUSB0
These will come back on reboot and when devices are unplugged and replugged.
It’s a good idea to reboot at this point to ensure the custom names return as expected.
Ensure that your user can access the serial ports. By default in Raspbian the
user is pi
and it is a member of the dialout
group, and the dialout
group
has permission to access the ttyUSB*
devices. If you use another user, add it
to the dialout
group.
$ sudo usermod -a -G dialout myuser
Alternately, you can run screen
through sudo
, but that is typically
unnecessary with proper permissions and group memberships.
GNU screen allows a user to run multiple concurrent terminal sessions from a single login session. This is much easier to manage than multiple SSH connections to the same server, with the added benefit that screen can “detach” and leave the terminals connected in the background while the user does other things or even logs out. Later, the user can resume the screen session and it is as if they never left.
Many devices will output critical messages to the serial console and if the user isn’t watching the console when they happen, they can be easily missed. Using screen with a large scrollback buffer means the user can monitor these devices and look back at recent output, search it for specific strings, or even write it out to a file.
Create a configuration file for this dedicated instance of screen
:
$ vi .consoles.screenrc
Add in some useful configuration options along with definitions for each of the serial terminals.
# Handy terminal defaults
termcapinfo xterm ti@:te@
termcapinfo xterm-color ti@:te@
termcap xterm 'is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;4;6l'
terminfo xterm 'is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;4;6l'
vbell off
# Status line -- careful the second line is quite long!
hardstatus alwayslastline
hardstatus string '%{gk}[%{G}%H%{g}][%= %{wk}%?%-Lw%?%{=b kR}(%{W}%n*%f %t%?(%u)%?%{=b kR})%{= kw}%?%+Lw%?%?%= %{g}]%{=b C}[%m/%d/%y %C %A]%{W}'
# Misc other defaults
shell -$SHELL
logtstamp on
logtstamp after 1
# No need for the intro screen
startup_message off
# 50000 lines of scrollback per window
defscrollback 50000
# Custom session name
sessionname consoles
# Definitions for each separate screen
screen -t 'Edge' /dev/serial_edge 115200
screen -t 'Server' /dev/serial_server 115200
screen -t 'Switch-1' /dev/serial_switch1 115200
screen -t 'Switch-2' /dev/serial_switch2 115200
screen -t 'Adapter' /dev/serial_adapter 115200
Replace the names, serial devices, and serial port speeds as needed to match your own setup.
When screen is running it will display a nice status bar with screen numbers and
the short names we set above with -t <name>
.
This command starts screen using our custom configuration file:
$ screen -c ~/.consoles.screenrc
This command resumes our specially named session (consoles
) in multi-display
mode.
$ screen -S consoles -x
In multi-display mode the user can remain connected to the screen from multiple separate SSH login sessions simultaneously.
The following commands are entered in screen by pressing Ctrl-A
(Hold the
Ctrl
key and tap the a
key), then release both and press the next key. For
brevity, this will be abbreviated like ^A-d
for pressing Ctrl-A
then d
.
^A-d
- Detach^A-DD
(Shift+D
twice) - Power detach^A-a
- Toggle next/last screen^A-<num>
- Switch to a specific screen number0
-9
^A-n
- Next screen^A-p
- Previous screen^A-<esc>
- Scrollback buffer modehjkl
, or even
the mouse scroll wheel. Type ?<string>
to search backward, /<string>
to
search forward. Press Esc
again to exit.^A-\
- Quit^A-:
- Screen command prompt:hardcopy -h outfile.txt
.^A-?
- HelpWith this in place, you can detach from the screen session and leave it running indefinitely and reattach as needed. This is great for monitoring consoles in case something goes wrong and prints logs or console messages for debugging.
]]>Hat tip to /u/Wily_Wapiti for their post about updating their own SP36 which gave me some extra guidance and encouraging information.
Since I compulsively write documentation as I go, here are my notes in case anyone else needs them.
There are at least three versions of the board around:
The models with flashing pads do not need disassembled the way this guide describes and the update procedure would be different, closer to the procedure for updating the LT1.
Before starting, try to do a version check which is 15+ clicks from off. Write down the result. The last four digits will be a model number which can be looked up in the list in the MODELS file and will definitely tell you what it’s running. If the light is running a version of Anduril before the version check was added, it’s likely the older variant similar to this guide or at least likely has an ATtiny85 and not ATtiny1616. If it outputs a date but no 4-digit model code, it’s almost certainly an older model running Anduril 1.
No matter which model the light is, do a test and a read to save the existing firmware to confirm the correct settings before attempting to write.
Here are the items I used:
Follow the disassembly procedure at https://budgetlightforum.com/comment/1556068#comment-1556068
That post has pictures and directions, but to save a click, here is the general idea:
I used a 5mm Allen wrench with duct tape covering the end going inside the light. The advantage of the Allen wrench is you can lift up on the handle and use the “elbow” of the wrench against the switch hole as a fulcrum rather than relying on pushing down or hammering. I used a T handle and some socket adapters to get extra leverage and it popped out after some work.
Something softer than tape on the end might have been better, I scraped the PCB a little but it was on an empty spot so not critical.
Use the pin guide below, adapted from a BLF post
Here are pictures of how I wired up the connection between the usbasp board and the SOIC8 clip:
I used jumper wires with M-F Dupont connectors so I could leave the original leads on my SOIC8 clip and plug into its ribbon cable connector.
As most of these lights can be updated with a SOIC8 clip, after doing this I crafted a more permanent solution using dupont connector blocks. I used a pick to release the single dupont connectors from the wire ends and inserted them into a 2x4 block for the SOIC8 side and a 2x5 block for the usbasp side. This way I can connect what is now effectively a proper ribbon cable in the future without having to remember or look up the pinouts.
Download the firmware hex file for the SP36 from http://toykeeper.net/torches/fsm/anduril2/ or compile a new one.
sofirn-sp36.hex
and for newer models it
may be sofirn-sp36-t1616.hex
sofirn-sp36.hex
hex file to the device which will be doing the
flashing.avrdude
or similar programs.sp36-old.hex
) and save
it somewhere safe (optional, but a good idea)Slight update, I also have a Sofirn Q8 Pro and BLF LT1. The Q8 Pro does not have flashing pads, the LT1 had pads but they didn’t line up with any adapter I have or could make. But in both cases they only had two phillips head screws holding in the driver board. Remove the screws, the board is loose and it was simple to gently turn it over and use the same SOIC8 clip method on them that worked on the SP36.
Line up the USB port and put the screws back in and reassemble, almost easier than trying to hold an adapter up to the pogo pins while running the update.
Adapted from my post on Reddit.
]]>Before starting, read over the guide for flashing the Sofirn LT1 as the procedure and pin layout is essentially the same. The pin layout on the LT1 is 3 over 3, the PL47G2 is 3 over 4 but one of the pins on the bottom row isn’t used.
I used the flashing kit from Hank (4 over 2 pinout) so as with the LT1 method it requires adapting the connection to the different pin layout plus some method of connecting an extra pin. I used a multimeter lead with a thin probe on one end and alligator clips on the other, clipped to a similar jumper wire to the ones mentioned in the LT1 thread.
Since writing this originally, I ordered some pogo pins and figured out that they can push fit into a dupont connector, so when I updated the light again, I used that instead of a multimeter probe.
Here are the connectors on my flashing kit with the jumper wires in place. The red wire on the right is going to the multimeter lead.
Grab the latest Anduril build from http://toykeeper.net/torches/fsm/anduril2/
If the PL47G2 uses emitters other than Nichia 219, download
ff-pl47g2.hex
If the PL47G2 uses Nichia 219 emitters, use either the pl47-219
variant or
compile a variation of the pl47g2 firmware with the lower FET PWM levels safe
for use with the Nichia emitters.
The pl47-219
firmware disables low aux levels so it’s not ideal for use on
the PL47G2.
See this commit on my fork of Anduril 2
for an example of the necessary changes to make a custom pl47g2-219
variant.
I have also posted a pre-compiled version of the hex file for this
variant.
I used zflasher AVR on Android to perform the update, but there are other ways (like avrdude or similar). I’ll stick to zflasher, though.
Copy the .hex
file somewhere on the phone/tablet accessible to the app (e.g.
Downloads
directory).
Connect the phone/tablet to the flash kit (e.g. using USB C to A Female adapter or OTG cable)
Open the app and set it up as follows:
Line up pogo pins on the flashing kit such that one pin on the row of 4 is NOT touching anything. Should be like so:
X
is an open pad that is not usedP
is a pad touched by a pogo pinN
is a pogo pin not touching a padO
is an open pad which is where the extra lead goes (multimeter for me)In the app, run a test first. If it fails, fix the error and try again. Most likely it wasn’t making contact with all the pins.
If the test succeeds, then write and wait for it to write and verify.
Bonus shot of the cobbled together setup to make it happen, with a guest appearance from a D4Sv2 and SC31 Pro working together as a little task light:
I ordered a couple batches of these HQ ProgKey PCBs from OshPark to make an adapter I could use for these Fireflies lights.
I used some solder paste to reflow pogo pins and connecting pins onto the adapter and then wired it up to match the pin layout.
I had some trouble initially getting it to work, but as it turns out the problem was the usbasp boards I had purchased from Amazon. The adapter works fine with the board from Hank’s flashing kit, so I’ll keep using that for now.
Adapted from my post on Reddit.
]]>A visit to the Monoprice Select Mini Facebook
group or the
subreddit shows a surprising (to
me, at least) number of people with related problems.A common chorus when
discussing the printer is “rewire the bed before you do anything else”. It can
manifest as the bed heater not working or the bed temperature readout being
incorrect, typically reading 999
or 0
.
Since mine had been OK, and I’d owned it less than a month, I figured I had time. I was wrong. After a couple weeks and a non-trivial number of printing hours, the bed wouldn’t preheat. The temperature readout was OK, but it read about room temperature and didn’t move. I canceled the print, went into the printer’s monitor screen and had it preheat the bed. Still nothing. I knew the wires could be the problem so I moved the bed back and forth to see if it would kick in, and it did when I moved it all the way forward. Move the bed back and it stopped. Classic short behavior, so I knew what I was in for. Now I had two choices: One: Send the printer back and get it fixed or repaired, or two: Fix it myself. Option one meant I’d be without the printer for probably a week or two and when it came back it would still have a bad wiring job. Option two means I could have it up and running in a couple days at most, and I could use a better wiring path that wouldn’t be prone to breaking. I opted to fix it myself, but I didn’t have all the parts on hand which is why it took a couple days to fix. While waiting for the parts to arrive I watched some videos on youtube by others who made similar repairs, but I did not want to drill through the case, so I also researched some other options. Once it all arrived it was actually a very straightforward fix, so I documented it all and here it is!
I chose to do a no-drill method using a printed side panel to reroute the wires. I do not want to have to deal with the mess of metal shavings that drilling would cause. The directions below assume this method, plus also rewiring the heater connection. Here are the parts I printed to replace the side panel and help run the wires:
You’ll need these tools to either reroute the wiring or to repair the bed wires
If you need to repair the bed wires, you will also need these:
If you are only rerouting the wires, you’ll want to grab…
If you are repairing the bed wires, you’ll also need…
If you do not need to repair the wires, skip ahead to Rewire part 2.
For me, the bed heated right up to 60C where I wanted it, and my prints are back to sticking like I’m used to!
If you choose to do a method involving drilling or if you choose a different side panel configuration, the last few steps may need to change to route the cables through whatever new path is available.
]]>Occasionally I need to to the same task, or similar tasks, on a group of machines all at once. I don’t have the luxury of a fully automated environment like Puppet setup, so a great tool I’ve been using is called ClusterSSH
ClusterSSH (A.K.A. cssh
) opens up a batch of xterm windows to a group of hosts
you specify, and gives you a master control window with a command prompt. You
can select and type into the host windows individually, but the real fun is with
the command line in cssh’s main window: Any key you press while in the command
line there is sent to every host window.
So whether you need to do a common task, like update the ports tree on FreeBSD,
check drive space, etc, it can really speed things up. This weekend I’ve been
using it to switch a batch of machines over from cvsup to subversion for
/usr/ports
and /usr/src
on FreeBSD, and it’s worked great. In the past I’ve
used it for things like updating ports, making sure a script worked when run
identically on every machine, and for making sure that things like sudo were
installed and functional across a set of systems. I’ve also used it to login to
a group of pfSense machines to see if they could all ping and reach a tcp port
on a certain remote host.
It’s worth checking out if you have any similar needs. If you’re on FreeBSD it’s
in /usr/ports/security/clusterssh
or for other operating systems you can grab
it from http://sourceforge.net/projects/clusterssh/
My FreeBSD desktop workstation has been on 8.x since I built it just over two years ago. When I made it, I bought two 1TB HDDs and setup a RAID-1 volume with gmirror, following what was at the time the recommended instructions from the FreeBSD Handbook After delaying the upgrade to 9.x repeatedly over the last several months I finally decided to give it a try after 9.1-RC1 was announced. Read on for how it went wrong, since FreeBSD 9.x more correctly handles partition integrity checks.
I also used it as an opportunity to switch my /usr/src
tree over to
Subversion instead of CVS
The buildworld and buildkernel went fine (After I re-created my kernel config
file that I accidentally removed when clearing out /usr/src
to move to svn!),
and rather than my usual tactic of doing the installworld
in multi-user mode,
I decided to be cautious and boot the 9.x kernel into single user mode like
we’re supposed to. It’s a good thing I did!
Upon booting, I was greeted with two fun things:
GEOM_PART: integrity check failed (mirror/freebsd0, MBR)
mountroot>
prompt.So I was a little panicy at this point, because I have about 700GB of data on this array. Some Googling around later on my laptop and I found out about 9.x’s stricter integrity checks that don’t play nicely with a whole-disk gmirror made using the handbook’s instructions. As this mailing list post indicates the real solution is to switch to doing a per-slice mirror using GPT rather than the old MBR/glabel way. Since that mailing list post was a little light on details, I kept searching and found an excellent article by Vick Khera (who, incidentally, also contributes on the pfSense mailing list occasionally!) that steps through the whole process in an easy-to-follow manner.
Much of that article was spot on but there were a few differences for me, mostly because of the differences in our setup – his was a server in a datacenter with no local access, and mine was a desktop sitting right in front of me. The differences for me were:
gpart
properly
(9.1-RC1 memstick works great for this) – I initially discovered the
gmirror
issue after trying to single user boot after only doing an
installkernel, so my world+kernel did not match when booting the 9.x kernel.
If I tried gpart
in this state, it did not function.kern.geom.part.check_integrity=0
before I did a kldload
geom_mirror
on 9.x or it wouldn’t touch the mirror, claiming it was corrupt.
I was able to access the mirror fully with this sysctl
set, and it’s
possible I may have been able to function fully indefinitely this way, but
part of me kept thinking it was a ticking time bomb and there was no better
time than now to fix it properly.fstab
at the end.fixit
, you’ll need to mount
a bigger /tmp
than the fixit
system provides. For me I was able to
dump/restore my /tmp
slice, then forcefully unmount the mfs
/tmp
, and
mount the ‘old’ /tmp
as the fixit /tmp
- this allowed the dump/restore on
my 700+GB /usr
to complete without much fussfixit
did make for some slight variances in the
process, mostly pointing dump at the (old) mirror slices directly rather than
mount points and not using L since it wasn’t mounted.The dump/restore phase took several hours for the large /usr
slice, I don’t
have an exact count since I let it run overnight and didn’t note the start time.
There were a couple of ATA errors but it worked past them. (I ordered a spare
disk just in case this is a bad sign.) The next day after the mirror was back
up, the mirror synchronization also took a few hours, but I had left the house
and it was done by the time I returned.
The end result is a much more modern disk layout, and mirrored partitions rather than a completely mirrored disk. It won’t be quite as convenient to rebuild when a disk fails, but I also won’t have to worry about overwriting metadata with real data. I do need to keep a record of my slice ordering and the commands to re-create it somewhere.
Now my desktop is happily running FreeBSD 9.1-PRERELEASE, and is currently busy recompiling all 1132 of its ports. Hopefully when the time comes the transition to 10.x will not be quite so painful.
]]>According to discussions on the FreeBSD-stable list, CVS support for FreeBSD sources is not just dying, it’s practically dead. (I’ll skip over the jokes about Netcraft confirming it…) So I setup an SVN mirror of the FreeBSD base and ports repositories and documented the process a little. I did this mainly because there are a lot of servers in two locations that need frequent access to the base and ports repositories, and there are currently cvsup mirrors running (one at each place) to keep the load off the upstream servers and for faster local access.
Before getting too far into it, here is the most relevant post in the thread on the FreeBSD-stable list that gives a decent summary of what has changed
Copying/Paraphrasing from that link:
RELENG_9
is still alive and will continue for the foreseeable future.cvs
/cvsup
.RELENG_9_1
does not exist (yet?).RELENG_10*
tags on cvsRather than being caught off guard for 10.x, switch now, and you might need to anyhow if you plan on tracking anything but 9-STABLE.
A couple links to more FreeBSD+SVN info
Subversion can be installed from /usr/ports/devel/subversion
- and if you plan
on using Apache to serve your SVN repositories over HTTP, you need to check the
option to build the DAV modules when configuring both Subversion and Apache. If
you already have Subversion and/or Apache installed but didn’t select the DAV
module options, you may need to rebuild the ports.
RELENG_<foo>
it will come from base. All of the branches
and tags are there, they are just worded slightly differently. A few random
examples:# The RELENG_9_0 errata/security branch (9.0-RELEASE-pX)
svn co svn://svn.freebsd.org/base/releng/9.0/
# The RELENG_8 stable branch (8-STABLE)
svn co svn://svn.freebsd.org/base/stable/8/
# FreeBSD 8.3-RELEASE exactly (no errata)
svn co svn://svn.freebsd.org/base/release/8.3.0/
head
here:svn co svn://svn.freebsd.org/ports/head/
However you can get the ports tree at a certain FreeBSD Release by using a tag such as:
svn co svn://svn.freebsd.org/ports/tags/RELEASE_9_0_0/
Now, on to the mirroring part. It’s much faster to start your mirror from a seed file, rather than making it completely download and rebuild the entire repository from scratch.
You can fetch from the seed files as described below, and then bring the
repository up-to-date the rest of the way with svnsync
. The doc tree can be
done the same way, but since I don’t build docs I did not mirror it. I used
ftp2.freebsd.org
in this example, feel free to substitute your favorite local
mirror, provided it has copies of the files.
# mkdir -p /home/freebsd-svn/
# cd /home/freebsd-svn/
# fetch ftp://ftp2.freebsd.org/pub/FreeBSD/development/subversion/svnmirror-base-r238500.tar.xz
# tar xvzf svnmirror-base-r238500.tar.xz
# svnsync sync file:////home/freebsd-svn/base
# cd /home/freebsd-svn/
# fetch ftp://ftp2.freebsd.org/pub/FreeBSD/development/subversion/svnmirror-ports-r301235.tar.xz
# tar xvzf svnmirror-ports-r301235.tar.xz
# svnsync sync file:////home/freebsd-svn/ports
Now that you have updated copies of the repositories, you can setup a cron job to run a script to pull in new changes. The script is simple:
#!/bin/sh
/usr/local/bin/svnsync sync file:////home/freebsd-svn/base
/usr/local/bin/svnsync sync file:////home/freebsd-svn/ports
I added that to a cron job that runs once per hour, but depending on how often you actually update your own servers using it, you could probably dial that back a bit.
Now that you have a local mirror, but how to serve that up to your other machines? Well, one way is via ssh, and another is svnserve, but for various reasons I prefer to do this via HTTP, so I setup Apache with DAV to hand it out. I’ll also explain svnserve later in this post.
First, as I mentioned above, you’ll make sure you compiled both Subversion
(/usr/ports/devel/subversion
) and Apache (/usr/ports/www/apache22
) with the
relevant DAV module options. Then you can setup the Apache config.
In the main httpd.conf file (/usr/local/etc/apache22/httpd.conf
), check that
the DAV modules are loaded. This may already have been done automatically by the
port:
LoadModule dav_svn_module libexec/apache22/mod_dav_svn.so
LoadModule authz_svn_module libexec/apache22/mod_authz_svn.so
Uncomment the line for the extra/httpd-dav.conf
file
Include etc/apache22/extra/httpd-dav.conf
Then save/exit after you’ve made any other changes you want to that file - if you’ve never set Apache up on that server, you’ll probably want to set the server name, admin e-mail, hostname, and point it to a directory that won’t serve up the Apache default files. There are many Apache tutorials out there if you need help with this part.
Now edit /usr/local/etc/apache22/extra/httpd-dav.conf
The first thing I do here is comment out or remove any directives referring to uploading. Then at the end, I add a section that actually allows the SVN bits to be served up:
<Location /freebsd-svn>
DAV svn
SVNParentPath /home/freebsd-svn
Order deny,allow
<LimitExcept GET PROPFIND OPTIONS REPORT>
Deny from all
</LimitExcept>
</Location>
Because you can’t exactly commit to these repositories anyhow, that will deny anyone access that tries to write.
After making those changes, save/exit and restart apache. An apachectl
configtest
would be prudent to ensure the remainder of the config is proper.
Now you should be able to access the repositories over HTTP! Note that you can’t
just browse to http://your-server/freebsd-svn
- you’ll need to use the name of
the SVN repo inside, such as http://your-server/freebsd-svn/base
or
http://your-server/freebsd-svn/ports
To checkout the ports tree to your current directory, use:
svn co http://your-server/freebsd-svn/ports/head/ .
If you don’t want to use HTTP, you can setup svnserve
to use the svn protocol
on port 3690
. It’s pretty simple actually, just edit/etc/rc.conf
and add:
svnserve_enable="YES"
svnserve_flags="-d -R --listen-host 0.0.0.0"
svnserve_data="/home/freebsd-svn"
svnserve_user="root"
svnserve_group="wheel"
The -R
in the flags tells it to be read only. I would suggest adding an svn user and group to run the daemon under, but it will run as root if you configure it to do so manually as I did in the example.
svnserve
does not appear to properly handle dual stack IPv4/IPv6, so you
may need to use the IPv4 IP or a DNS alias without a AAAA when accessing the
repo such as:
svn so svn://x.x.x.x/ports/head/ .
If anyone knows a good way to have it listen on both, I’d love to hear it. I’ll update this post if I get that figured out. That’s another reason I prefer HTTP at the moment.
Accessing over ssh is left as an exercise for the reader. :-)
Here are a couple other handy commands (will add more as I find them or they are suggested):
The default behavior of csup/cvsup was to overwrite your locally changed files. By default Subversion will leave your changes alone and try to merge them. To get the csup style behavior with Subversion, you must revert all local changes first and then update.
svn revert -R /usr/src
svn update
The csup
style behavior is more useful as a consumer applying local patches
and needing to revert to the newest upstream when it’s updated. The svn style
behavior is more useful for developers so they don’t risk losing their work.
This will NOT remove any distfiles or packages from ports, as those have
svn:ignore
set in the properties of the ports repository.
I was hoping to find a way to “adopt” an existing directory into Subversion
rather than deleting and checking out a whole tree again, but so far I haven’t
found a good way to do that cleanly – if anyone knows, I’m all ears. So far
it’s easiest to rm -rf /usr/src
or /usr/ports
when checking out the SVN
copy. I tried using --force
when doing svn co
and it seemed to want to work
but I was left with a giant mess in the end.
Say you want to move from tracking 9-STABLE to tracking 10-STABLE, that’s really easy:
svn sw svn://svn.freebsd.org/base/stable/10
Another practical example, say you start out by grabbing RELENG_9_0 (the security branch):
svn co svn://svn.freebsd.org/base/releng/9.0/
And then the time comes that you want to track 9.1 instead, then you switch like so:
svn sw svn://svn.freebsd.org/base/releng/9.1/
And then you end up with RELENG_9_1, it’s as easy as that. No need to redo the entire checkout.
I always welcome feedback - if you know of a better, easier, or more correct way to do something I’ve described here - I’m more than willing to make corrections.
Much of the information in this post was gleaned from the freebsd-stable thread linked earlier, along with some info from other sources and personal experience.
]]>The other day I found that the Tweetdeck Chrome extension worked on FreeBSD (With Chromium 18.0.1025.142, probably earlier as well). I had been missing a full GUI to monitor some things on Twitter on my FreeBSD box. I have a much larger monitor on my FreeBSD workstation than on my Windows laptop, so I’d rather use the extra screen space there to keep a search column up (For pfSense, mainly).
I encountered two issues though. The first is that Chrome will, for whatever
reason, kick in the monitor’s DPMS power saving mode. I have this disabled in my
.xinitrc
so it was a surprised to see the monitor turn itself off. There is an
open bug for Chromium
about this behavior. Not sure what about Tweetdeck brings it on but it doesn’t
happen unless it’s open, and even then not all the time. Turns out unsetting the
KDE_FULL_SESSION
environment variable before launching Chrome will make it
behave.
Second, to make Tweetdeck live outside of the normal Chrome window I wanted to make an application shortcut. When I attemtped to do so, however, it complained and said it couldn’t determine my desktop environment (I tried this with the previously unset variable retained as well, thinking that was the cause). So I had to manually track down a couple things.
The key to making this work is making a small shell script. I dropped in a
directory under my ~
and called it tweetdeck.sh
. This is what it looks like:
#!/bin/sh
unset KDE_FULL_SESSION
/usr/local/bin/chrome --app-id=hbdpomandigafcibbmofojjchbcdagbl
I had to track down that app id by making a shortcut on a Windows box and then copying the string over. If we didn’t need to unset that environment variable, you wouldn’t need a shell script you could just copy a chrome shortcut and add the app id bit.
So I made a shortcut to that script and it worked, but still looked pretty
boring with the standard icon. So I dug around and found that there are some
good icons that get installed with the extension. The one I used was stashed
away in:
/home/<name>/.config/chromium/Default/Extensions/hbdpomandigafcibbmofojjchbcdagbl/1.3_0/web/assets/logos/48.png
So that’s all the magic. It launches in its own window, completely standalone. If you click a link, it launches a separate instance of Chrome to handle it.
Clearly between the DPMS and Shortcut creation issues Chrome could use some better KDE integration but I won’t hold that against it, the fact that it works so well (or at all) is fine by me.
]]>