Sunday, November 25, 2018

Making an UV image setter for PCBs

This is going to be a quick one. I wanted to do one of these for a long time but somehow it eluded me for quite some time (too long if you ask me)

The problem

I need to make a PCB for a small circuit at home. Conveniently. After I'm done designing the circuit it usually is late and the sun doesn't shine no more. I want to be able to use the photoresist dry film (foil) and I want it to be fast!

The solution

I used to use a 500W halogen, then an energy-saving fluorescent lamp but all of those things were just cumbersome. Finally I have decided to make use of UV emitting diodes.

See the following picture of a ready-made product:

The device is powered by a 3 cell LiPo battery (I have a bunch of them for my flying toys). The time it takes to properly develop the foil is ABSOLUTELY SHORTEST FROM ALL THE LIGHT SOURCES I USED BEFORE!!!

The 500W halogen needed circa 30 minutes in the setup I used. The energy-saving light bulb needed 12.5 minutes. This little toy does the same and more in 90 seconds!!!

The making

Making such a toy is extremely simple. You just cut as many pieces to length as much space you have in the housing of your choosing (I used the Z23 housing where I have cut a full-size hole in one of the parts).

Next you cut a piece of paper that fits inside the housing. Once you do that take the pieces of strips and glue them on to the piece of paper in a similar way that you see on the picture above. The point here is to make the as evenly spaced as possible.

Then you solder them to form a strip (plus with plus, minus with minus). On one end you solder any kind of connector (I went for the small JST one because I have a lot of them). Then just make a hole on the side where the leads with the connector are coming out.

Finally place that paper with glued strips inside, apply power and enjoy!

Happy PCBing!

Friday, November 23, 2018

The Flame Wars - story of my life

Flame wars have been with us for God knows how long. Christianity vs all other religions, Islam vs everyone else, socialism vs capitalism, Atari vs Commodore, Amiga vs PC, Macintosh vs the World, Linux vs everyone else. Fighting for our believes seems to be at the core of our nature. We just can’t help thinking that what we think is best must be the best - because we deemed it to be the case.

Developers are a particular strain of oddities: Whatever technology we seem to work with at the time seems to be either the evil incarnated or the impersonation of God - depending on the current hype among our friends that we trust know better. Very seldom it is the case we grow big enough balls to actually go over the fence, dig into the dirt and figure out for ourselves if the grass on the other end is really so gray as we deem it to be.

It has been an eye opening experience every time I took a turn in my career when it came to the tools I worked with.

I started in the 7th heaven owning an Atari 800XE and 3 games I could barely hold still while loading a game from a tape storage. For that reason I started to learn what the keyboard and TV set has to offer beyond playing Mr Robot and Forth Apocalypse and I discovered that, in point of fact, Basic was a part of the package.

Soon after that I became a sworn 6502/C64 freak at the age of 14. I know. I betrayed. I was the outcast. But I was doing ora-dycpys going over side borders while playing ripped tunes and waving Dedal logos. And I did it all in machine language - not even assembly! All I have had was the Final Replay 2 cartridge but for reasons I cannot fathom it was the best thing that ever happened for me. I was able to see the results of my work upon issuing a single sys command. And it looked great!

At that time Amiga was “the better game machine for me”. I mean, with all due respect, I still think that the playability of Giana Sisters, the Mario clone for Commodore computers, was way better on C64 than it was on any platform (even XBox!). Having said that I was kind of socially pressed into wanting the A500 with 512Kb of Slow RAM extension to be able to play Pinball Dreams and IK4+. But playing games was never my thing. After I saw how much Giana Sisters sucked by comparison I started looking for things to do with my shiny new computer. Pascal was there, but the animation example I saw was visually so bad that I couldn’t stand watching it. The C example didn’t even compile so I thought it was a waste of time to get interested in it. But the good old low level language, Motorola 68k assembler, was quite a nice fit for me after having a few years of experience in programming registers on its older uncle. Man, those plasma screens I loved so much! I was staring at it for hours! I was finally home!!!

At that time I remember reading a quite far reaching article about code quality. A couple of demo scene Gods discussed if it makes sense to write good quality code or if it is more important to just code it in the fastest way possible, win the compo at a demo party and move on to the next one. A question I sure hope the industry has answered so far to everyone’s satisfaction.

Being bored writing sinus scrolls, 3D animations and plasmas I started looking into this promised land Amos was said to be. With its Amal animation language targeting Amiga’s coprocessors it was told to be even better than asm itself. I remember it being the first IDE having an integrated debugger, forward function declaration and (upon pressing F9) code folding. Man! I missed that for years afterwards!

Then one day everything changed. My beloved A1200 was (again, upon the pressure of friends) exchanged to a 486SX with 50MB hard-drive. It was running DOS, Norton Commander, it looked bad (compared to A1200’s workbench) and what I had no idea then it was the first computer running an OS that was not Unix-like. Apparently, for what seems to be forever, I have fallen into the Redmond dream that I was unable to wake up from.

I remember a few years after that trying to install RedHat Linux from a 23 floppy disks installation - and failing miserably. I thought that those “Linux” guys must be insane to be using something like that. I was a sworn DOS enthusiast! I discovered Windows 3.1 and the only thing it was good for was multitasking to run the BBS software and at the same time to be able to code in Turbo Pascal that I fell in love with in the meantime. Pascal wasn’t fast enough though to write intros/demos so me and my friend resorted to “db 66” asm instructions to speed up double buffering.

Not long after that I learned that programming isn’t really something lots of people do particularly well - me included. That was when I discovered The Almighty Internet. Suddenly the knowledge that I craved for so much for so long became within my reach. But it was so overwhelming!!! Just going through some examples that I found on swagger took me a lot of time. Those were the times when I first saw Qnix - a windowing system-enabled one floppy-disk, Unix-like, free to use real time operating system. So Unix did have some appeal after all, I thought. I went even deeper when I learned about the Linux Router Project - a one-floppy-disk Linux distribution that did IP routing and masquerading out of the box. I knew Linux was the one - but it was so different than Windows and Dos Navigator that I grew so accustomed to!! All the things were different. That was just a hassle I was not ready to go through.

Fast forward a few years and the Turbo Pascal I worked in became Delphi and my professional career was booming! I was moving to a different country, founding my second business - I was on the roll! To have everything in check instead of buying Windows XP I decided to try out this “SUSE Liunux” as it was promised to “just install and work” on my PC. Well, it did. But it was soooo different than Windows XP and… Delphi didn’t run there. I was still deep in the Redmond dream.

I don’t remember when it really happened but it must have been when I received the Ubuntu 7 something CD for free. It really delivered on the promise to be approachable enough for everyone - this time me included. But Delphi still didn’t run there. By accident that was the time I went to a seminar in Warsaw where the successor of Delphi 7 was announced and I realized that this is the end of what I was able to get out of the platform. So I started looking…

At that time I worked in a corporation that offered me an option to learn Java and .NET. C# looked like a natural choice (being coordinated by the creator of Delphi himself) but for reasons I cannot fathom till this day I decided to go with Java. The first years were a disaster! Nothing was like it should have been. Java developers spoke of things I had no idea even had names (like refactoring, unit testing, clean code, design patterns) although upon deeper investigation it looked like we spoke about those same things - just naming them differently.

I fell in love with Groovy and Maven (I know - I’m different that way). I use both of those tools till this day with great proficiency. I think that Maven was the best thing that ever happened to Java. It made it approachable for mere mortals and freed us from Ant hell. Groovy on the other hand was for me the Pascal equivalent on the JVM. It had the concept of properties that I missed so much ever since I left Delphi behind. But at the same time I unwillingly became independent of the environment I worked in. Linux, Windows, OSX - I didn’t care anymore. So I realized one of my long-lived dreams and switched fully to Ubuntu - the Linux platform for the rest of us :) It was a natural step because all production servers were running Linux so using SSH that was not (and still isn’t) present on Windows felt so natural. And so, Windows became “the OS I sometimes run”. I do remember the day when I installed Linux exclusively without dual-boot. It felt weird - but good.

Since then I moved from Java to frontend development. Something I thought I had some idea of but was proven sooooooo wrong. Learned that what you see is not really what you will get (as in I finally learned what the hell everyone else was talking about in relation to Internet Explorer 6). But I love every bit of it. It gives out of the box tooling that on other platforms you need to pay good money for. To some extent I am even happy I learned about frontend development through the Ember.js perspective. It was the worst thing after getting struck by Java Server Faces but it made me explore the domain to see if there’s something that can substitute this horrible piece of machinery. So I learned about React and fell in love with it, I also learned about Angular and how it makes development more like I was used to from my times in Java and ended falling completely in love with Vue.js.

Then I decided to move to a company that thinks very little of frontend development but is really big on Sitecore. If you don’t know what Sitecore is think Wordpress on .NET that you can pay for because you think it is better than X or Y. This meant for me taking a round trip to the .NET world and the C# language.

At each step after a few months of digging in I felt my passion for software development giving away field to understanding of capabilities. Every week/month/year I meet sworn enemies of technology X than can give me 5, 10 sometimes even 20 reasons for not using the other, legacy, frameworks, languages, platforms. The truth however is that everything has its reason for existence. Yes, even jQuery and goto. I just wish I learned that years ago. The only thing that really counts is writing code for other developers to read (regardless of the platform/language) and questioning the status quo if it makes your life harder.

So going from 6502, through M68k, Amos/Amal, Pascal, Delphi, Java, JS and the browser and now .NET and Sitecore I learned only one thing: developing software is easy. But doing it right is hard. And if you don’t use whatever means necessary to help you out then sinking in the pool of your own blood and excrements is as obvious as the fact that sun’s rising in the east. The rule for me now is to first learn for myself if a piece of tech is useful in a context - not “in general”. And as a rule it has its exception for me: JSF. Everything else I learned over the years made me a better programmer, person, husband and father.

Happy years!

Wednesday, October 31, 2018

Creating PCBs

I have been working lately on perfecting a formula for preparing PCBs. If you're like me and like your designs tried out faster than a few days read on.

Assumptions

I am assuming you either are using the applications and materials that I used or you are happy to realize the same functions in the application you are using. I will be using Linux, KiCAD, a PDF viewer for printing and chemicals available in Poland, where I live.

Preparing the printout

The following assumes you can use KiCAD. KiCAD's printing functionality is basically broken. The quality of printouts is so low you can't do anything with it. The following mitigates that by using Plot.

When creating designs that contain through-hole components make sure to check the size of pads. By default they are tiny-tiny small and can easily break when heat is applied. To change the parameters of a pad right-click on, select Properties and set the Hole shape to Oval, Size X and Size Y to at least 2. With that there is probably enough space to solder.

  1. Create your design
  2. Select File / Plot
  3. Set Plot format to PDF
  4. Select the copper layers
  5. Select Mirrored plot and Negative plot
  6. Set Drill marks to Actual size
  7. Click Plot
  8. Open the created PDF and print it on a Canson calcque
  9. Use Density Toner to even the traces on the layout. Density Toner is basically rectified gasoline which melts the toner making it evenly black in all spots. This prevents the printout to leak UV rays through

Depending on your printer (I use OKI C332 laser printer) it is important to set the printout density to maximum. That black toner is all that will block the UV rays from the light-sensitive material!

Preparint the PCB

  1. Cut out a piece of laminat to the size of your project. You don't need any excess - that's a waste I don't like
  2. Cut out the printed layout to the size of your PCB. Again, I do that precisely which then makes aligning things easy
  3. Cut out a piece of light-sensitive foil with additional 5-10mm. That excess is needed for the board to be exactly covered form side to side
  4. Clean the PCB. I mean like really, really well. I use a special sanding block for cleaning PCBs that I bought ages ago but a very fine sanding paper will do just fine. Don't overdo it - you don't want the copper layer to get too thin!
  5. Wipe the board with a clean tissue so that any dust is removed from the surface
  6. Peal the cover off of the foil on the inner-side. I do that with a piece of tape - works every time with absolutely no hassle
  7. Place the foil on the PCB - the side that had the outer foil removed
  8. Make sure there are no air bubbles or dust bubbles between the foil and PCB
  9. Put the PCB between a folded sheet of paper (PCB towards the fold!) to form a sandwitch
  10. Run the sandwitch through laminator at least 3 times. Make sure the laminator is properly heated!
  11. Remove paper from sandwitch leaving only PCB. Beware not to peal of the foil from PCB
  12. Put the printed layout toner-down on the PCB
  13. Spray the PCB with layout on it with Transparent and remove all air bubbles
  14. Cover the PCB with a plexi and make sure there are no air bubbles. If there are then you either have to litle Transparent or the field is not even.
  15. Place a 32W energy saving bulb 22cm from the PCB.
  16. Turn on the light source for 12-13 minutes
  17. Remove the PCB and put it in a dark place for 10 minutes (necessary for the chemical process to finish)
  18. Remove the outer protective foil - watch out not to break the layout!
  19. Use foil developer for 2 minutes. While developing use a soft brush to remove the disolved foil. Do NOT exceed 2 minutes!
  20. Wash the PCB under warm running water and using hands delicately remove any remaining pieces of foil.
  21. Put the PCB under light for 5 minutes. That way if there are any parts of the foil lefy they will turn blue and you'll know you have to start again
  22. Put the PCB in a dark place for 5 minutes for the chemical process of hardening the foil to settle
  23. Use B327 to remove non-covered parts of the copper; Don't keep it too long.
  24. Once all the parts are disolved put the PCB under running water and wash excessively
  25. Pour acetone on the board using surface tension to flow the liquid from one side to another. Do that until the foil peels of from the traces
  26. Wash under running water

That's it! With luck the PCB can have extremely small traces (requires good printer which the C332 is not) and very delicate handling especially when washing out the unexposed foil. I stick to 0,25mm traces and above but even that can sometimes go wrong. 0,5mm traces are guaranteed to be 100% successful.

Important remarks

Don't rush things! With the exception of exposing the foil for too long and developing the foil for too long take your time! Rushing things is the worst you can do. This process requires you to be gentle with the board, precise and methodical. Rushing things will only get you to broken traces.

That is it! Happy etching!

Wednesday, September 19, 2018

POI 10, tests and coverage

The problem

You're using POI 10 with @poi/plugin-karma and want to get coverage of your unit tests. The way to do it is to specify:

  plugins: [
    require('@poi/plugin-karma')({
      coverage: true,
    })
  ]

and theoretically you should be all set. Only that it won't work:

TypeError: Cannot read property 'preLoaders' of undefined

I've looked everywhere and it seems that it is, unfortunately, not a known problem. What is even worse the GitHub repo with POI sources, version 10, is GONE! I mean I understand everything but removing history of an opensource project - that is a bit too much for me. SHAME ON YOU, EGOIST!

The solution

The problem is that @poi/plugin-karma taps directly to options of the vue-loader whist seems to be undefined at that point. The quick and dirty solution is to add those options:

  plugins: [
    require('@poi/plugin-karma')({
      coverage: true,
      chainWebpack (config) {
        config.module.rule('vue').use('vue-loader').options({})
      }
    })
  ]

I need to dig more into the matter why vue-loader isn't configured there and why the hell when testing a Vue.js SFC still causes errors but for now for testing just javascript code the above solution works

Happy coding

Friday, September 14, 2018

Replacing strings in proxied response using Apache mod_substitute

This is another quicky but it took me forever to finally figure it out - maybe someone will have that same problem...

The problem

You're working on a site that uses Apache2 proxy to merge your local frontend development environment with a remote site providing the content. That is easy to setup:

ProxyRequests Off
ProxyPreserveHost Off

ProxyPass "/path-to-a-resource" "http://localhost:3000/path-to-local-resource"
ProxyPass / http://remote-host/
ProxyPassReverse / http://remote-host/

Now all is nice and dandy until all you want to do is just to merge the remote site with local resources on localhost. It starts to get interesting when you want to modify the content sent by upstream server. Why? Well... let's say links in that sent HTML are absolute and you'd like them to be relative. There's a ton of options that are available once you can do that!

The solution

To be able to substitute strings in the response sent by upstream server there are 3 things that need to happen:

  • Enable the mod_substitute ($ sudo a2enmod substitute)
  • Enable filtering using mod_substitute
  • Specify replacement rules

The second part is what gave me a headache Today. Basically you need to understand 2 things: when Apache does the substitution it needs to have the full page received to be able to perform the substitution. That doesn't happen automatically. And then once the substitution is done Apache needs to put it all back together and send it to the browser. It's all done using the following for HMTL files only:

AddOutputFilterByType INFLATE;SUBSTITUTE;DEFLATE text/html

And last but not least: we need some substitutions to see the effect. For the purpose of demonstration we'll replace all class attributes with TEST:

Substitute "s|class|TEST|i"

That's it! It's easy as pie when you know the deal :) I know I'll be using it more and more in the future!

Happy coding!

Friday, July 6, 2018

Handling new POI's publicPath

Today I wasted over 3 hours frantically looking for explanation why the hell POI's publicPath setting thinks I am an idiot and it knows better what I want. So this is a quick post to let you know what you should do if you really want to change the output.publicPath in a POI-managed project.

The problem

Imagine you're working on some project that has pre-existing sources and their location is (surprisingly) not in the root of your server. That's the case every single time when you're working on existing apps trying to induce some build system on them to bundle up the scripts and stylesheets.

Usually, for those cases Webpack has a special configuration option output.publicPath that handles everything for you and life's good. POI, on the other hand, has that option exposed at the top level - but with a twist: it only works in final build and not in development mode.

The problem is, however, that if you'd like to work against an existing server that produces HTML and other artifacts you need to comply with that structure regardless of the mode. Unfortunately, POI fucking knows better! And here's the relevant point in POI's code that does it:


function getPublicPath(command, publicPath) {
  if (command === 'build' && typeof publicPath === 'string') {
    return /\/$/.test(publicPath) || publicPath === ''
      ? publicPath
      : publicPath + '/'
  }
  return '/'
}

module.exports = getPublicPath

I have no idea what was going through EGOIST's head at the time of writing but it must have been something really, really strong. Not good for opensource as it breaks the fundamental rule of least surrprise.

The fix

Instead of setting the publicPath in poi.config.js or setting it via command-line parameter override it in the resulting Webpack configuration like so:

module.exports = {
  configureWebpack(config, context) {
    // we're not setting publicPath as the general configuration option
    // because some sick bastard decided this will only have an effect
    // in production mode and we need it everywhere. Talk about predictability...
    config.output.publicPath = '/path/where/everything/lives/'
    return config
  },

With that life's good again (even thought it was so damn frustrating Today)

The architecture

Working on projects where the content is delivered from some sort of CMS or other app that has a fat backend isn't easy. It usually boils down to having everything running locally, even if we don't need it. There is, however, a better way of doing it! Use some reverse proxy to route traffic to your browser from 2 different sources: the backend and the frontend in development mode. Here's an example configuration with Apache2 but you can do much much more than that:

<VirtualHost :80>
    ServerName my-app.local

    # Make sure no caching is induced so that refresh always brings the latest version
    # run "sudo a2enmod headers" to enable headers module
    Header set Cache-Control no-cache

    # run "sudo a2enmod proxy_http" to enable http proxy
    ProxyRequests     off
    ProxyPreserveHost off

    # Serve all theme files from local development server
    ProxyPassMatch    "^\/path\/where\/everything\/lives\/(.*)$" "http://localhost:10001/path/where/everything/lives/$1"

    # Required by Hot Reload (run "sudo a2enmod proxy_wstunnel" to enable ws proxy)
    ProxyPassMatch    "^/(.+).hot-update.js$" "http://localhost:10001/$1.hot-update.js"
    ProxyPassMatch    "^/(.+).hot-update.json$" "http://localhost:10001/$1.hot-update.json"
    ProxyPassMatch    "^/sockjs-node/(.+)/websocket" "ws://localhost:10001/sockjs-node/$1/websocket"
    ProxyPassMatch    "^/sockjs-node/(.+)$" "http://localhost:10001/sockjs-node/$1"

    # Serve everything else from remote server
    ProxyPass         / http://dev-machine.somedomain.com/
    ProxyPassReverse  / http://dev-machine.somedomain.com/

</VirtualHost :80>

Also, don't forget to set NameVitualHost *:80 or the name-based virtual hosting just won't work. Now with that in place add the following entry to your /etc/hosts file:

127.0.0.1   my-app.local

and you're all set.

You can of course fiddle with it, add SSL support if your backend server requires it, but the point here is that it is possible and you can work without installing heavy backend to work on frontend!

Happy coding!

Saturday, June 23, 2018

Scaffolding a new Vue.js component

I've been working for the past few months on a travel portal rewriting parts of it from old jQuery code to Vue.js - and learning a lot of stuff in the process. One thing that I learned the hard way is that scaffolding that's built in into Vetur is just not for me. It is too simple.

The naming convention we have for our component files is for them to have the same name as the file they exist in. So basically TestMe.vue becomes

<template>
  <div class="test-me">
    ...content
  </div>
</template>

<script>
import Vue from 'vue'
import Component from 'component'

@Component({})
export default class TestMe extends Vue {
}
</script>

<style lang="scss" scoped>
.test-me {
}
</style>

Makes sense?

The problem is that having to type this in every time I create a new component (and the number of those grows like creazy!) is tedious. So I finally got to it and created a snipped that works for me:

That's it! You type "sfc", press [Tab] and the component is ready to be worked on by magic of the VS Code templating engine.

The first thing that'll be edited is the name of the exported class. If it is OK then just press [Tab] to move to the name of the CSS class. Edit it if you must then press [Tab] again and you'll be able to select the processor for styles. The next thing that you get to customize is if the styles should be scoped. Once on it either press [Tab] to go with scoped styles or [Delete] and then [Tab] to go without scoped styles. Finally you arrive at the Hello, world! text where the editing of your component begins.

Have a nice day!