As some of you know I use JLCPCB a lot for my PCBs.

Why not UK?

We do use UK manufacturers for our FireBrick products, but for the small cheap PCBs I make, it is simply not viable. I have tried to get competitive quotes but people in the UK cannot match the prices, or even close, or the time scales. It is a real shame, and would be great if the UK could find any way to compete.


I posted about a weird tracking issue a while back. Thankfully it was a one off.

But things have gone down hill.

Stupid rules

One issue (I don't think I posted) was that they charge a surcharge for "multiple designs" on a PCB, i.e. where cuts or v-cuts allow parts of the board to be broken off, and those have different designs on them. I don't follow the logic at all. But what is even more weird is the logic for this - any tracks or silk screen on break of parts makes it a different part. If just blank, it not and so no surcharge. They can silk screen on it at no extra (e,g. their job number). I even tried to "follow the rules" and had text done in the solder resist (they say explicitly tracks and silkscreen as separate parts, not solder resist), but they would not play. It is a shame, I just wanted a bar code (for the board) on the break of parts of a panel. Pain, but their stupid rules.

Broken search

More recently I found, when uploading, a part was not in stock, a 124k 0402 resistor. For a start, how is that not in stock, but I did the search option and it showed many 0402 parts and I picked one in stock.

What fooled me is the search did not list resistors matching the value I was searching, and I managed to pick a 0.124Ω resistor. My mistake, after a broken search, and I got a UK company to rework for me ("hot tweezers").

Broken component selection

Anyway, my mistake. This time I ordered more boards, same bill of materials I have used dozens of times before, and for this one component, the same as dozens of designs of boards over the last 6 months.

The BOM has an "R" (i.e. resistor) in an "0402" package, with a value of "124k", simple. I don't care the other aspects, it is a potential divide as a reference for the regulator, so really does not matter what 0402 124k resistor it is, hence I have not picked a specific LCSC part number for a specific manufacturer, as that could be out of stock more easily. Like simple resistors and capacitors I simply list the value I want, obviously.

As usual, it picked the parts, and showed them, not actually showing the value, as truncated. But I gate it a value, as I have done so many times before, and obviously expect it to pick a resistor of that value.

Suddenly, this time, it picked a 1.24Ω resistor. So ignored the value I specified! This happened on two orders. One I will have to pay someone to rework, again!

This is bad, I should be able to just say I want an 0402 resistor of a specific value and it pick one. That really is one of the most basic things they can handle in the BOM upload. They used to handle it.

Update: Just to be clear, I have used JLC for years and never had an issue until now, but now it is seriously broken. I re-tested, and even adding Ω to the value does not help. Magically today the 124k is working, but the 1M is suddenly 51kΩ - which makes no sense at all. Previously perfectly fine BOM files now fail randomly. I tried setting specific LCSC parts, which works, except that they are then out of stock of the specific parts and you have to search parts instead of just using a known working BOM.


And now the latest fiasco, and this really is now taking the piss,.

A part I have used on dozens of designs over at least 6 months, and hundreds of boards. A simple LED. Indeed, my Stargate designs actually have over 500 of them on each board!

The design I am ordering is one I have ordered many times, indeed, I just received some I ordered over a week ago, same BOM, same LED (wrong resistor, as above).

But now, for some reason this "is highly sensitive to humidity, and needs baking before soldering, or it will easily got moisture damaged". They suggest checking the datasheet. There is a surcharge!

The datasheet says: "If the moisture absorbent material has fade away or the LEDs have exceeded the storage time, baking treatment should be performed based on the following condition: (60±5)°C for 24 hours."

This suggests they have stored it incorrectly maybe? and want me to pay a surcharge for their bad handling of a component.

Awaiting reply, but they have gone from "quick, easy, cheap", to "pain in the arse, costly rework, and stupid rules and extra cost."

I may have to find someone else!


Hiding passwords

A minor niggle, but some times you want a web form that has passwords.

The classic solution is type=password and send the password as the value. This works, and if the page is all https, then why not, it is secure. It also offers to save the password (something that is really hard to disable these days, and there are reasons to want to do that!).

But what if not https, for, reasons*

Sending a password is not ideal - but if not https, sending one back is also in the clear, but if the threat is purely snooping then it is not too daft to minimised sending it when not needing changing. You minimised the window of capturing it. You also stop someone simply requesting the page to see it, even if they are able to change it.

So a simple fix is to have a rouge value password you use to mean no change such as ********. You can send this and if a returned value is not that then it means a new password has been set.

It bugs me slightly, as it means you cannot have a password of ********.

Well, maybe.

  1. Only send when password set, as always useful to be clear if a password is set or not.
  2. Why not use something more esoteric, such as ✶✶✶✶✶✶✶✶ (unicode 6 pointed stars). Passwords should allow unicode stuff, obviously.
  3. Allow setting the password to the rogue value if not currently set, meaning you sent blank and not the rouge value, so the rouge value coming back means someone set it. This means the only limitation is changing from one password to the rouge value without unsetting it first - not a biggie (if documented).

* such as local control to a microcontroller that has limited capability to do https and limited capability to handle certificates. A problem we would all like to solve cleanly.

** And yes, I mean for those occasions where one cannot store a hash! They exist! WiFi passwords for one. But even when a hash, you need a way to know someone is trying to change the password, and this works for that too.


GPS Logger project

My GPS logger project is pretty much over at last. All working so well, and several customers happy!

Do buy them (here) but they are not live trackers - they are loggers.

I have had an annoying set of issues.

  • power control FET for GPS/SD picked wrong, way too low power.
  • not spotting I had inputs on non RTC GPIOs on the ESP32S3.
  • not realising the STAT signal from the charger is only charging so stops when charged.
  • having a cap on GPS so it could brownout the power when connected.

Even so, all sorted, and quickly, and the whole project sorted from start to finish in a couple of weeks.

I'd like to thank Neil for inspiring the whole project - his blog: RevK's privacy-friendly GPS logger.


Finding a postcode

My GPS logger is going well (available here) and it logs journeys when back on home WiFi.

One of the requirements that someone requested was to list postcodes visited. I think it was a district nurse, and they need this for expense claims.

So, not a hard task, surely, making it find postcode where you are...

Postcodes are odd shapes

Sadly postcodes are not simple, and odd shapes, but the best I could easily do is find nearest postcode based on the centre for each postcode, which is published free by Ordnance Survey.

Notably the Dutch government does the same but with a bounding box which may help identify when there is ambiguity.


The challenge is that this is a small micro controller. I cannot just "install mysql". I need a way to look up postcodes and finding the nearest. I cannot sensibly scan 1.7 million UK postcodes each time I want to log a postcode.

The "trick" is simple, make a grid. I picked 1km squares on the OSGB E/N grid. So not quite 1km but close enough. More on that later. That meant I could make a grid for the whole UK, and for each grid square I can make a list of possible postcodes with there centre.

That was simple enough, well, except...

Converting lat/lon to OSGB

First issue is, on device, converting GPS lat/lon to E/N OSGB. There are simple algorithms for this, I have seen them, but some are way off, and ultimately the "official" way to do it is make a guess and check a huge look up table of surveyed points (I think each 10km).

I did not want to do this on device, so my solution is convert the postcode list to lat/lon. This runs on linux and can use the official look up table, but gives me a postcode database which uses lat/lon.

Searching one cell

The next step was a simplification for search. I make each grid square (now based on lat/lon) have a list of postcodes with centre location to find the closest.

The problem is that, at the edge of a square, the closest may be in the next square. So I scan the edges of the squares, binary dividing to find all "near" postcodes for all points along it, whether in the target square or not. I then have all that are in the target square.

This means for each square I have a list of all postcodes that could be the closest postcode for any point in the square. This means some duplication from square to square but makes the lookup simple.

The whole lots ends up in one file. Look up the grid to find the list of postcodes, and scan the list for the closest. Simple.


Distance of point to line in four dimensions (or more)


I'm writing the blog because searching has not helped me on this. Why do I need to know? well the answer is I am applying a Ramer–Douglas–Peucker algorithm to GPS tracking data.

You can look it up, but it is pretty simple to explain. Imagine you have a set of points starting from A and going to B - in my case it is GPS log data, so points on a map, every second, so lots of points. You want to reduce how many points you have without losing significant information.

Ideally all the intermediate points are on a straight line A to B, and can all be removed leaving just A and B. I practice you allow a tolerance, an allowable deviation from the line. If all of the intermediate points are within that tolerance you can delete them all. If not, you find the most deviant point, call it C. C is effectively a corner point. You apply the algorithm on A to C and C to B recursively.

In the end you have a set of points, which could just be A and B, or A, C, and B, or more. If you join the dots with straight lines you can be sure all of the removed points lay within your tolerance of that line, and so be sure any detail, that is more than the tolerance allowed, has not been missed.

I use this years ago on GPS data.


Point to line

The crux of the algorithm is working our the deviation from the line, what wikipedia helpfully just refers to as perpendicularDistance().

Two dimensions

In two dimensions this is simple, and searching finds an algorithm. I used this on latitude and longitude. But this causes problems.

  • Latitude and longitude are not a flat plane. This is not likely to be a real issue unless tracking a plane (pun intended) or a ship over a long distance.
  • Latitude and longitude are in degrees not metres, so working out your distance is not easy. A degree North is not the same distance as a degree West and changes depending one where you are. You need trigonometry to compensate and convert to distance units.

Three dimensions

Of course, we also have altitude, and so seems sensible to include that - why not. Algorithms for a point to a line in 3D are also easy to find, but there seem to be several different approaches. At least altitude is already in metres.

However, the GPS can provide not just lat/lon/alt, but also ECEF data. This is simple Cartesian X/Y/Z co-ordinates from centre of the Earth. This avoids any need to adjust from degrees, and makes it simple.

Four dimensions

I have to push it one step further, don't I? If you travel in a straight line, but stop for a while, you would remove all points. By including time as a 4th dimension we create a corner when speed changes notably or you stop for a while.

It does mean you have to scale time to a distance, but that can be a simple parameter in the algorithm.

However, there is a snag - finding an algorithm for point to line in four dimensions is not simple. The only ones I could find explain it in vector maths - and even with an A in A-level maths, it was a long time ago and I really did not get on with vector maths. Nobody seems to give me a simple algebraic answer which is driving me mad.

Making it simple

So, back to basics, I am interested in three points, and regardless of how many dimensions that is, they can be said to lie on a flat two dimensional plane. This means working out the deviation is a simple matter of considering a triangle.

So I want to find h. To do this I need distances a, b, and c. But that is easy to find as it is simple Pythagoras, regardless of how many dimensions. For two dimensions it is √((Ax-Bx)²+(Ay-By)²). For three dimensions it is √((Ax-Bx)²+(Ay-By)²+(Az-Bz)²), and so on.

Knowing ab, and c I can use Heron's formula to find area...

  • s = ½(a+b+c)
  • 𝔸 = √(s(s-a)(s-b)(s-c))

Then use the formula for area from base and height

  • 𝔸 = ½hb
  • h = 2𝔸/b
  • h = 2√(s(s-a)(s-b)(s-c))/b

So it can be done with any number of dimensions.


One of the considerations is performance when coding for a microcontroller. They can do integer add/subtract very fast, multiply reasonably fast, division slower, and floating point even slower. As it happens the ESP32 has hardware single precision floating point, which helps.

So can I simplify this?

Thankfully wikipedia helpfully expands Heron's formula to:

  • 𝔸 = ¼√(4a²b²-(a²+b²-c²)²)

Which gives us:

  • h = 2(¼√(4a²b²-(a²+b²-c²)²)/b)
  • h = ½√(4a²b²-(a²+b²-c²)²)/b
  • h² = (4a²b²-(a²+b²-c²)²)/4b²

Working our h² is useful as ultimately I am just comparing this distance so no need to apply a square root. I can square my reference threshold.

Why is this helpful? Well, all of the parameters are a², b², and c². This means that I don't need to use a square root to work out ab, and c in the first place. The whole lot is simple addition, subtraction, multiplication, and just one division.

Turning back

There is another problem with all of the perpendicular distance algorithms, including this one. The all work out a distance of a point to an infinite line which is defined as going through two points.

In this case point C is way off the line A-B, in fact it is c off it, but h is small. If h is within the tolerance  then it would be removed leaving only A-B.

To solve this I can use the fact that if c²-b² is > a² the C must be beyond A and I should use a² as the distance².

Similarly if a²-b² > c² then C is beyond B, meaning I should use c² as the distance².

Fortunately I have a², b², and c² already, so is a simple test.

Of course, what if you have a straight line A-B-C-D and travel A-B-C-B-C-D? No points will be "outside" the A-D range... Well the use of time as a 4th dimension catches that - which means the first case would also have been caught... Even so, this simple test on end points is worth doing I think.

C what I mean...

   inline float dist2 (fix_t * A, fix_t * B)


      float X = x (A) - x (B);

      float Y = y (A) - y (B);

      float Z = z (A) - z (B);

      float T = t (A) - t (B);

      return X * X + Y * Y + Z * Z + T * T;


   float b2 = dist2 (A, B);

   fix_t *m = NULL;

   float best = 0;

   for (fix_t * C = A->next; C && C != B; C = C->next)


      float h2 = 0;

      float a2 = dist2 (A, C);

      if (b2 == 0)

         h2 = a2;               // A/B same, so distance from A



         float c2 = dist2 (B, C);

         if (c2 - b2 >= a2)

            h2 = a2;            // Off end of A

         else if (a2 - b2 >= c2)

            h2 = c2;            // Off end of B


            h2 = (4 * a2 * b2 - (a2 + b2 - c2) * (a2 + b2 - c2)) / (b2 * 4);


      if (m && h2 <= best)


      best = h2;

      m = C;



IBM Model M keyboard

For a very long time my preferred keyboard has been an IBM Model M keyboard. It uses "buckling spring" keys which have good tactile feedback and are clicky and loud...

This has been my preferred keyboard since they really were actual IBM Model M keyboards. These days it is UNICOMP that make them, and as I have moved to Mac as my main machine, and UK Mac keyboard layout.

It works well, I love it.

But it has broken. Some keys get iffy, and this has happened now. It had happened once before, years ago. I assume somehow muck gets in there - but the whole thing is all sealed to a metal plate inside, so not easy to debug or fix. Last time I got a new one.

So, this time, as they have no Mac layout ones, I ordered a PC layout, and sorry, no, I just cannot get used to it. I'd rather have no Z and an iffy S than use a PC layout. Yes, I had to *hit* the Z hard to type that.

As UNICOMP have none of the Mac layout - I am a bit stuck, and, for the first time, in literally decades, looking at another keyboard.

I'll update this post when it arrives. Worrying times when a mad has to change his keyboard. But it may save muting Jitsi when I type.


  1. The keys do not map correctly by default on a Mac, notably ±/§ and ~/` reversed. Annoying, but solvable...
  2. The tools to allow remapping using "VIA" app website did not work! It got stuck after connecting to the keyboard, so I fixed the remapping in the OS.
  3. The keys are too sensitive, so being slightly different spacing I keep hitting adjacent keys just enough to register - but I will get used to the spacing. It is quieter.


Ordering PCBs

Ordering PCBs and assembly is fun :-)

Well, not fun, and to be honest, one of the biggest challenges is the parts selection, what they have in stock or something equivalent, but designing the PCB is definitely fun (well, for me).

I export a gerber files that are the instructions to make the PCB tracking images, and also a BOM (bill of materials) and position file, for placing the parts.

I have done this many many times with several PCB manufacturers, and lately with JLCPCB, which seem to be surprisingly quick and sensibly priced (apart from the odd quirk). I'd love to find a UK company as cheap and easy to use, I'd use them.

The PCB printing has a few design constraints, the gaps between tracks, minimum track width, and so on, which relate to the optics of the process for printing and drilling the board itself. But apart from that the PCB is printed exactly as expected.

Well, until now.

This is what I ordered... (this is an image from their order history page)

And this is what arrived...

It took me ages to debug it - tracking down that the CPU was running way too hot (burned my finger) and not quite right. It turned out it was running on 4.5V not 3.3V. The shorts there short input to output on a regulator circuit and I was testing from 5V USB via a diode. If I had tested 12V it would have made smoke, I expect.

The thing is the order process involves a lot of steps, and each step show the PCB you are making.

  • When uploading the gerber files
  • When selecting assembly and it shows the bare PCB
  • When showing PCB with parts
  • When order complete and preview of PCB
  • When order complete and preview of assembly
  • On gerber viewer on the site from their order confirmation

At every stage they show the circuit correctly, but the final PCB was faulty.

I complained, and they advised: "We have reflected this issue to our engineering team and JLCCAM software team and they have found and fixed the issue just now, and there will be no the same issue next time, so don't worry about it."

They even provided an image of the error:

Next step - refund!

My view is simple.

  • They made an error in printing the PCB.
  • Arguably they made an error with the flying lead test of the PCB not spotting the printing error.
  • They then made the PCB with parts that cost money - either of the above errors not made would have avoided that.
  • It was not, in any way, my fault.
  • I did not get what I paid for.

It is simple. I should not only have a full refund, including shipping cost, but ideally I should be compensated for the hours of debug, the delay in getting working boards, and the cost of disposing of the WEEE (defunct PCBs and part).

I'll be happy for just a full refund, and either they pay for courier to return boards, or I dispose of them (at my cost). As I buy loads from them, I'd even allow for it to be a credit on my account rather than an actual refund.

I have a funny feeling they will try and weasel out of this - and then I may have to ask Amex to intervene. It is for two separate batches of boards (from 4 I ordered, 2 of which were fine) totalling over $470.

Watch this space - I'll update with news.

Update: They do seem to be trying to weasel out of out - that PCB manufacturer is separate from supplying parts and assembly - but the parts they supplied are useless to me as supplied, so not reasonable that I pay for them, surely? Indeed, I have offered to send the parts back to them (at their cost). We'll see how that goes.

They suggested I try and isolate the track, but this is cutting through soldered pads, so when I put the components back it will short again!

Update: They are being counter reasonable. I suggested I could maybe find someone to rework - they suggested I try, and get a quote. I may try and get a quote.

They also think just cleaning solder would be enough to avoid shorting with the component leads when cut like this...

Update: I have decided instead to offer a compromise on basis that on one board I can re-use the SCD41 sensors they have supplied. Pushing their offer $50 more on each set of boards. We'll see.

Update: We have credits now.


As some of you know I use JLCPCB a lot for my PCBs. Why not UK? We do use UK manufacturers for our FireBrick products, but for the small che...