CS32 Blue Pill clone connection problems

Recently I’ve been doing some experiments with the popular “Blue Pill” microcontroller model STM32F103C8T6, made by STMicroelectronics. The microcontroller (MCU) uses the ARM Cortex-M3 F103 chip, a low cost, low power but high capability chip, with a whole load of input/output pins.

Instead of using the original, I stupidly decided to get a much cheaper Chinese clone, with model number CS32F103C8T6 – note the difference in the first two letters. I ran into some weird connection issues, which did not appear with an original MCU. Read more

ImageMagick: Convert image to PDF without losing quality

If you’re a nerd like me, you probably like using ImageMagick’s convert command line tool to manipulate images or convert them to PDF. It’s fast, powerful and is able to work on tons of images at a time. You could probably do the same in Photoshop or some Adobe product, but come on… what’s the fun in that!

But with great power comes great responsibility… and great confusion. How many times have you had to trawl through Stackoverflow just to use this command properly? I’ve spent hours – days, even – trying out the 290 (!) different options, just to find the combination that works.

Something I do quite regularly is to convert images to PDF. To make them look nice, I’ll also add some margins and centre them on the page. Not too complicated, right?

It turns out that doing this in ImageMagick without losing image quality involves quite a bit of (pun not intended) magic. You’ll need to set the page size, calculate a density, and use an offset to centre the image manually. Frustratingly, there isn’t a simple way to centre an image.

Just as you’d expect of a nerd, I’ve created a script to do this for me. Behold, the imaginatively-named img_in_pdf script:


#!/bin/bash
# Converts input images to one-page PDF files each, without changing image data.
# The image is centered on a A4 page with a 5% border.
# Adapted from https://unix.stackexchange.com/a/220114
#
# Usage: [command] image1.jpg image2.png ...
# Output: PDF files named after the images e.g. image1.pdf

# bc function to calculate maximum of two floats
bc_functions="
define max(a,b) {
  if (a>b) {
    return(a)
  } else {
    return(b)
  }
};";

# Do the calculation in string $1 and echo the result.
function calc {
  # Define bc functions so we can use it for the calc.
  echo "$bc_functions $1" | bc -l;
}

for file in "$@"; do \
  # Determine image dimensions in pixels.
  img_size_x=$(identify -format "%w" "$file");
  img_size_y=$(identify -format "%h" "$file");

  # Calculate image density (in dpi) needed to fit the image and a 5% 
  # border all around on an A4 page (8.27x11.69"). Factor 1.1 creates 
  # 2*5% borders, see https://unix.stackexchange.com/a/220114 for details.
  min_density_x=$(calc "$img_size_x / 8.27 * 1.1");
  min_density_y=$(calc "$img_size_y / 11.69 * 1.1");
  # Use the higher density to prevent any dimension exceeding the required fit.
  density=$(calc "max($min_density_x,$min_density_y)");

  # Calculate canvas dimensions in pixels.
  # (Canvas is an A4 page (8.27x11.69") with the calculated density.)
  page_size_x=$(calc "8.27 * $density");
  page_size_y=$(calc "11.69 * $density");

  offset_x=$(calc "($page_size_x - $img_size_x) / 2 * 72 / $density");
  offset_y=$(calc "($page_size_y - $img_size_y) / 2 * 72 / $density");

  # Center image on a larger canvas (with a size given by "-extent").
  convert "$file" \
    -page ${page_size_x}x${page_size_y}+${offset_x}+${offset_y} \
    -units PixelsPerInch -density $density \
    -format pdf -compress jpeg \
    "${file/.jpg/.pdf}";
done;

 

What this script does, quite simply, is:

  • Get the dimensions of the image.
  • Calculate the resulting page dimensions if we add 5% margins to all sides of the image.
  • Determine the density (i.e. how many dots per inch or DPI) the image should be set to, so that it would fit into an A4 canvas with the required margins.
  • Use the density to calculate the page size in pixels.
  • Use the density to calculate the image offset, i.e. how far from the bottom left corner it should be, so that the image would  look “centred”. In this sense, the PDF rendering mechanism doesn’t actually centre it. It just displaces it so it looks centred.
  • Run the convert command with the calculated parameters to generate a PDF from the image.

Mathematical calculations are done using the Linux bc tool.

To use the script, download it from the Github repository and make it executable using chmod u+x. You can then execute it like this:

./img_in_pdf.sh image1.jpg image2.png ...

Hope you find this useful!

PHP development environment with Docker Compose

I’m a professional PHP/Drupal developer and some people have asked me about my development stack. Here’s how you can use Docker to create a PHP development environment on your Mac. Say bye to MAMP!

First you’ll need a Mac laptop. While this is possible on Linux or Windows, I haven’t tried those so your mileage may vary (a lot).

We will be setting up an example development website with PHP and MySQL, using Docker Compose and PHPFarm. This will allow you to test with different PHP versions.

Install Docker and Docker Compose

Install Docker. You can get the free edition called Docker Community Edition (CE).

Install Docker Compose. This will allow you to create multiple containers, containing PHP and MySQL, and connect them into an application.

Create folder structure

I’ve created a folder structure which I find especially useful for development. You can clone it from github.com/eugenesia/docker-php-dev using

~$ git clone git@github.com:eugenesia/docker-php-dev.git ~/docker-php-dev

Configure Docker Compose

You need to create configuration files for Docker Compose to set up your example website.

Go into the cloned folder docker-php-dev/docker , and copy the file default.docker-compose.yml into docker-compose.yml.

~$ cd ~/docker-php-dev/docker
~/docker-php-dev/docker$ cp default.docker-compose.yml docker-compose.yml

docker-compose.yml contains the default configuration for a simple PHP example site. You can modify it later.

This is all the configuration you need (for now).

Run Docker Compose containers

It’s time to start running Docker!

Make sure you have Docker running. On your Mac, click on Docker in your Applications folder.

Then go to your terminal, and in the docker folder, run:

~/docker-php-dev/docker$ docker-compose up -d
Creating network "docker_default" with the default driver
Creating docker_web_1 ...
Creating docker_mysql_1 ...
Creating docker_web_1
Creating docker_mysql_1 ... done

If you now run docker ps, you’ll see what actually happened:

~/docker-php-dev/docker$ docker ps
CONTAINER ID  IMAGE                     COMMAND                 CREATED             STATUS             PORTS                                                               NAMES
fdd6c8068daf  mysql:5.7                 "docker-entrypoint..."  About a minute ago  Up About a minute  0.0.0.0:3307->3306/tcp                                              docker_mysql_1
7edd09b729a4  eugenesia/phpfarm:jessie  "/bin/bash /run.sh"     About a minute ago  Up About a minute  0.0.0.0:8051-8056->8051-8056/tcp, 0.0.0.0:8070-8071->8070-8071/tcp  docker_web_1

Your two containers docker_web_1 (with PHP and Apache) and docker_mysql_1 (with MySQL database server) are now running and connected with each other.

They are accessible through ports 8051-8056, and 8070-8071. These correspond to the different PHP versions provided by PHPFarm.

Go to your web browser and browse to localhost:8056/example.php to see the example page. Voila!

Because we are using PHPFarm, a setup which runs multiple versions of PHP, you can access the page using different ports, corresponding to the different PHP versions:

Shutting down

To shutdown your containers, do this:

~/docker-php-dev/docker$ docker-compose down
Stopping docker_web_1 ... done
Stopping docker_mysql_1 ... done
Removing docker_web_1 ... done
Removing docker_mysql_1 ... done
Removing network docker_default

Customise project name

You may have noticed that your project name has been set to docker, resulting in your containers being named docker_*. Wouldn’t it be nicer if they were named myproj_*, especially if you were running containers for several different projects at the same time?

To fix this, shutdown your containers using the docker-compose down command as above.

Then go to the docker/ folder and copy the default.env file to .env, to set the environment variables for Docker Compose:

~/docker-php-dev/docker$ cp default.env .env

Change your project name to whatever you like in the .env file:

# docker-php-env/docker/.env
# Docker-compose environment variables.
# Rename this file .env and customise to your liking.
# Reference: https://docs.docker.com/compose/reference/envvars/

# Set the project name otherwise it will default to folder name of
# docker-compose.yml
COMPOSE_PROJECT_NAME=myproj

Bring your containers up again using the docker-compose up -d command as before. This time, they should be named using your project name as a prefix.

What’s next?

Developing a full-fledged PHP site is beyond the scope of this tutorial. But here are a few pointers to get you started:

  • Your docroot and code files are at docker-php-env/data/php/
  • To SSH into the container, do
    $ # docker_web_1 is your container name shown in "docker ps"
    $ docker exec -it docker_web_1 bash
    
  • To customise the PHPFarm Docker image, see the repository github.com/eugenesia/docker-phpfarm

Drupal: Pass arguments to a Views block

In Drupal, it is possible to pass arguments to a Views block. You need to use the “Contextual Filters” option in the View. See screenshot.

Here are some other ways but these are possibly outdated (from 2011): http://drupal.stackexchange.com/questions/17900/how-do-i-pass-some-parameters-to-a-block

Installing Drupal 7’s Coder and PHP Codesniffer on MAMP

If you need to check coding standards for your Drupal 7 custom module, there is no better way than using the Coder module with PHP CodeSniffer. Unfortunately if you are using MAMP, and using the PHP executable provided by MAMP, the installation becomes a little more complicated.

Here’s how to install the required modules.

Install Coder

Coder module should be installed in the global Drush directory, rather than in a website’s directory. The Drush directory should be  ~/.drush .

$ cd ~/.drush
$ drush dl coder
$ # Refresh Drush cache to access new commands.
$ drush cc drush

Use MAMP’s PHP for Drush

Assume you are running MAMP’s PHP for Drush. This is done by setting the environment variable DRUSH_PHP to MAMP’s PHP executable with the correct version. This is done by adding in ~/.bashrc or ~/.bash_profile :

# In ~/.bashrc
# Use the path leading to the version of PHP you want to use in MAMP.
export DRUSH_PHP=/Applications/MAMP/bin/php/php5.6.7/bin/php

Installing PHP CodeSniffer

PHP CodeSniffer is a PEAR module.

Go to MAMP’s PHP directory and run the pear executable there, for example:

$ cd /Applications/MAMP/bin/php/php5.6.7/bin
$ # Coder 7.x is only compatible with PHP CodeSniffer 1.x and not the latest PHP CodeSniffer 2.x
$ # See https://www.drupal.org/node/2342611
$ # Install the latest 1.x version of PHP CodeSniffer.
$ ./pear install PHP_CodeSniffer-1.5.6

Then add Drupal coding standards to the PHP CodeSniffer directory:

$ cd /Applications/MAMP/bin/php/php5.6.7/lib/php/PHP/CodeSniffer/Standards
$ # Symlink to Drupal coding standards provided by Coder.
$ ln -s ~/.drush/coder/coder_sniffer/Drupal Drupal

Set up phpcs command

Coder makes use of the phpcs command to use PHP CodeSniffer. Make sure you can run phpcs on the command line, by setting an alias in ~/.bashrc or ~/.bash_profile .

# In ~/.bashrc
# alias phpcs=/Applications/MAMP/bin/php/php5.6.7/bin/phpcs

Test the installation

Test it by using the drush drupalcs command on a PHP file or a module file, for example:

$ # Check code standards for test PHP file.
$ drush drupalcs /Applications/MAMP/htdocs/test.php
$ # Check code standards for a custom module.
$ drush drupalcs /Applications/MAMP/htdocs/public_html/sites/all/modules/custom/mymodule/mymodule.php

All done!

See also: Other methods of installation

There are other ways to install PHP CodeSniffer but they may not work for this configuration which uses MAMP’s PHP.

In particular, the command drush install-php-code-sniffer may not work for you even if you installed Coder through Drush.

The code for this command is in the function drush_coder_review_install_php_code_sniffer() in the file ~/.drush/coder/coder_review/coder_review.drush.inc .

Bare bones Drupal 7 custom module

How to create a bare bones Drupal 7 custom module:

  1. Create a module folder in /sites/all/modules/custom/[modname]
  2. Create a [modname].info file. See: https://www.drupal.org/node/1075072
  3. Create a [modname].module file, and create a hook function.

Done!