www.technotes.se

In many situations a quick and dirty solution is the fastest way to get things done, as an example bash scripts with functionality being turned on/off using comments. This solution is not very flexible, therefore instead this article describes a bash script which creates a menu of all functions present in the same file. This setup can be much more flexible when the bash script grows. As an example: a Debian system install script which takes a minimal Debian system installation and adds custom settings on top of it, like KDE, building NVIDIA drivers and so on. Sometimes it is wanted to run only a subset of the functions in the install script, maybe it is only needed to recompile the NVIDIA drivers after updating the Kernel.

How it works:

The purpose of this bash script is to generate a menu of all the functions named using a name convention matching “function functionX” listed in the same file. The menu functionality works as follows:

  1. The script gets the file name of itself.
  2. It looks in the same file for all strings matching “function function” and stores all matches in an array.
  3. The user is presented with a menu with an “Execute all” option followed by one option for each function listed in the file matching the string “function function”. Also the menu is converting the function names into something more readable in the menu (it splits on capital letters in the function name, example: functionMySimpleFunction” would read “My Simple Function” in the menu).
  4. The user can select to execute all functions listed in the script or one specific function.

The below helpfunctions are the functions that creates the menu:

function helpFunctionPrintMenu() # <---- This is the main function of the menu functions. Trigger the menu by calling this function.
function helpFunctionSplitStringOnCapitalLetters()
function helpFunctionReadAndCheckInput()
function helpFunctionRunAllFunctions()
function helpFunctionRunSpecificFunction()

Example:

The script scans the file in which it exists for all functions named “function functionX” and creates a menu of them. Below is a set of example functions, replace these with your own functions but remember to declare them using the “function functionX” naming convention. Example: “function functionMyFunction”.

function functionExampleFunction1()
function functionExampleFunction2()

The menu script below would give the following output, shown in the screenshot below:

Get the code

The code can be found below or at the technotes github repository: technotes github page.

Or below:

#!/bin/bash
#
#   Copyright 2013 Christian Andersson, www.technotes.se
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
#
#
#   FEATURES: This script will print a menu of all the functions present
#           in this file that starts with the name functionX.
#           The function names will be converted into a readable format.
#           All function names starting with helpFunction will be ignored.
#           The user is presented with a menu from which the
#           user can chosse to run all functions in this list or a
#           specific function from the list.
#
#   USAGE:  Call the function helpFunctionPrintMenu to list a menu of all
#           the functions present in this file. The user can then choose
#           to run one of these specific functions or all of them. Replace
#           the example functions (functionExampleFunction1 and
#           functionExampleFunction2) with your own functions. Remember to
#           declare the function with the prefix "functionX".

# Get the filename of this script
filename=$(echo $0 |cut -d "/" -f 2)

#Find all functions in this file by greping for the first part of the function name and then removing everything in the function string between ... to ...'('
functionsList=($(grep -v "functionsList" ${filename}|grep "function function" | awk '{gsub("function ", ""); print;}' | cut -d \( -f 1))

#Global variable used to convert the function name into a readable name.
readableFunctionName=""

# Print a menu of functions that the user can select from
function helpFunctionPrintMenu()
{
   if [[ -z ${functionsList} ]]
   then
      printf "ERROR 1: There are no functions declared as \"functionX\", quitting...\n"
      exit 1
   fi

   printf "1 - Excute all\n"

   # For each item in the functionsList array, convert the function name to a readable format then print the menu item
   for index in ${!functionsList[*]}
   do
      readableFunctionName=${functionsList[$index]}
      helpFunctionSplitStringOnCapitalLetters
      # Since exit is defined as menu option 1 and the array index starts at zero add 2 to index
      # The awk part removes 'function ' from the string to make it more readable
      printf "%d - %s\n" $(echo $index + 2 | bc) "$(echo ${readableFunctionName} | awk '{gsub("function ", ""); print;}')"
   done

   # Call the helpFunctionReadAndCheckInput function to get and verify the users input, passing the correct menu item number, hence the $(echo ${index} + 2| bc)
   helpFunctionReadAndCheckInput $(echo ${index} + 2| bc)
}

# Split the function name into a readable format. Example: Input = "funcMyHelpFunction" will give the following output = "func My Help Function"
function helpFunctionSplitStringOnCapitalLetters()
{
   # The awk syntax can be a bit tricky to read therefore I explain the algorithm below
   # 0) Input the function name to awk - $(echo ${readableFunctionName} | awk ...
   # 1) Split all characters into a character array - {split($0, chars, "");
   # 2) Define an empty string variable in which we will store the final string - string = ""
   # 3) Traverse all characters - for(i=1;i<=length(chars);i++)
   # 4) If a char is an uppercase letter - if(match(chars[i], /[A-Z]/))
   # 5)    Then store an space char " " into the string variable
   # 6) Else store the char to the string variable as is
   # Example: Input = "funcMyHelpFunction" will give the following output = "func My Help Function"
   readableFunctionName=$(echo ${readableFunctionName} | awk '{n=split($0, chars, ""); string = ""; for(i=1;i<=n;i++) {if(match(chars[i], /[A-Z]/)) {string = string " " chars[i]; } else { string = string chars[i]; } }  printf("%s\n", string);}')
}

# Verify that the user input is corresponding to a valid option from the menu
function helpFunctionReadAndCheckInput()
{
   numberOfMenuItems=$1
   # Print menu and get input from the user
   printf "Please choose one: "
   read REPLY
   printf "Your have choosen: \'${REPLY}\'\n"
   # If the users input is greater than zero and less than the number of menu items
   if [[ ${REPLY} -gt 0 && ${REPLY} -lt $(echo ${numberOfMenuItems} + 1| bc) ]]
   then
      # If the user entered menu item 1 " Execute all" then run the function helpFunctionRunAllFunctions and run all functions listed in the menu
      if [[ ${REPLY} -eq 1 ]]
      then
         helpFunctionRunAllFunctions
      # If the user entered one of the other menu items then call helpFunctionRunSpecificFunction and run the specific function selected from the menu
      else
         helpFunctionRunSpecificFunction ${REPLY}
      fi
   # If the users input was not listed in the menu then print an error message and quit
   else
      printf "ERROR 2: Your input is not in the menu, quitting...\n"
      exit 2
   fi
}

# Run all functions in the functionsList array
function helpFunctionRunAllFunctions()
{
   # For each item in the functionsList array, run that function
   for index in ${!functionsList[*]}
   do
      ${functionsList[$index]}
   done
}

# Run the function in the functionList array corresponding to the function selected from the menu
function helpFunctionRunSpecificFunction()
{
   selecdtedMenuItem=$1
   # Run the function found in functionsList array at position menuItem -2 since the menu starts at "2" (Execute all menu item = "1") and the array index starts at "0"
   ${functionsList[$(echo $selecdtedMenuItem -2| bc)]}
}

# Example function to demonstrate the functionality. This function will be called since the name of the function starts with function
function functionExampleFunction1()
{
   printf "Running example function \'functionExampleFunction1\'\n"
}

# Example function to demonstrate the functionality. This function will be called since the name of the function starts with function
function functionExampleFunction2()
{
   printf "Running example function \'functionExamplecFuntion2\'\n"
}

# Run the print menu function, which is the starting point of this script
helpFunctionPrintMenu

# Exit this script
exit

References:

Wikipedia page for Bash: Bash (Unix shell).

The technotes github repository: technotes github page.

(0) Comments    Read More   
Jan
07
Posted on 07-01-2013
Filed Under (Arduino, C programming) by Lonezor

At this time around Christmas and New Year it is nice with some lights that make the outdoor darkness less prominent. After bying some off-the-shelf christmas lights I decided to make them shine in different patterns with an Arduino board. Instead of just being switched on all the time like the rest of the neighbourhood something different was needed. This article shows an overview of how this was achieved.

A word of caution
Working with electronics needs to be taken with proper care. The risk of electric shock and/or damage of property needs respect. If you know what you’re doing go ahead and setup a wonderful system or just read this as an interesting sidenote.

LED System Overview

Hardware

To summarize, these are the needed components:

  • Outdoor timer
  • 230V AC outdoor power cable
  • Plastic box to protect the hardware
  • A 230V AC power switch to connect all power supplies
  • Arduino Board (only a couple of GPIO pins are needed so most models are suitable)
  • A relay module with enough specification to handle the LED lights. Controlled from Arduino with digital pins). I ordered a pre-designed relay module kit and soldered it together.
  • Electrical wire for connecting everything DC related.
  • Outdoor LED lights with power supplies.

The components above can be bought at local stores and online embedded electronic stores.

Several segments of lights are needed. In my case I use colored LED lights. Some basic background lights that are always on. Then four segments are used that can be controlled with relays (A, B, C, D). Three green segments and one red. Each segment has 384 LEDs which definitely shine when it is dark outside.

Relay module:

Arduino Board:

Writing program code
Software is needed to control how the segments are going to be animated. It can be made completely random but a semi-random approach was chosen to ensure a certain type of style. The different animations are prioritized based on probabilty. A lookup table defines which animations to use. Each animation step has a
duration that is varied. It has been decided that very rapid animations should not be shown as this is more distracting than nice.

The program will act based on the lookup table. It is possible to add more entries. Four animation steps were chosen mainly due to the number of available segments.

No optimization has been done with respect to performance as it is not needed. The code is compiled in the Arduino IDE and flashed with the same program.

#define NR_OF_LEDS 4
#define LED_NONE  0x00
#define LED_A  0x01
#define LED_B  0x02
#define LED_C  0x04
#define LED_D  0x08
#define LED_RANDOM 0x10

typedef struct {
    unsigned long weight;
    unsigned long length;
    unsigned long active_leds[4];
} led_entry_t;

/* animation sequences. Specifies how the priority (range 0-1000) based on probability. Then animation steps (maximum four steps). The bit fields indicate which LEDs should be visible at different animation phases. */
led_entry_t led_sequences[] = {
 0,   1, { LED_A | LED_B | LED_C, LED_NONE, LED_NONE, LED_NONE },
 150, 1, { LED_A | LED_B | LED_C | LED_D, LED_NONE, LED_NONE, LED_NONE },
 300, 1, { LED_D,  LED_NONE, LED_NONE, LED_NONE },
 500, 3, { LED_A,  LED_A | LED_B,  LED_A | LED_B | LED_C,  LED_NONE },
 650, 4, { LED_A,  LED_A | LED_B,  LED_A | LED_B | LED_C,  LED_A | LED_B | LED_C | LED_D },
 700, 3, { LED_A, LED_B, LED_C, LED_NONE},
 750, 4, { LED_A, LED_B, LED_C, LED_D},
 800, 4, { LED_RANDOM, LED_RANDOM, LED_RANDOM, LED_RANDOM},
};

#define NR_OF_SEQUENCES (sizeof(led_sequences) / sizeof(led_entry_t))
#define LED_A_PIN 2
#define LED_B_PIN 3
#define LED_C_PIN 4
#define LED_D_PIN 5

/* play specified animation. Follow the instructions according to the table */
void display_leds(unsigned long index, unsigned long delay_ms) {
  unsigned long i;
  unsigned long length = led_sequences[index].length;
  unsigned long leds;
    for(i=0; i<length;i++) {
        leds = led_sequences[index].active_leds[i];
        if (leds & LED_RANDOM) {
            leds = random(0xffff);
        }
        if (leds & LED_A) {
            digitalWrite(LED_A_PIN, HIGH);
        } else {
          digitalWrite(LED_A_PIN, LOW);
        }
        if (leds & LED_B) {
            digitalWrite(LED_B_PIN, HIGH);
        } else {
          digitalWrite(LED_B_PIN, LOW);
        }
        if (leds & LED_C) {
           digitalWrite(LED_C_PIN, HIGH);
        } else {
          digitalWrite(LED_C_PIN, LOW);
        }
        if (leds & LED_D) {
           digitalWrite(LED_D_PIN, HIGH);
        } else {
          digitalWrite(LED_D_PIN, LOW);
        }
        if (length > 1) {
            delay_ms += 250;
        } else {
            delay_ms += 10000;
        }
        delay(delay_ms);
    }
}

/* select which animation sequence to run. Priority based on statistical probability */
void run_random_sequence() {
    unsigned long i;
    unsigned long weight   = random(999);
    unsigned long delay_ms = random(5000);
    for(i=0; i<NR_OF_SEQUENCES; i++) {
        if (led_sequences[i].weight >= weight) {
            display_leds(i, delay_ms);
             break;
        }
    }
}

/* Set relay module GPIO pins to output mode (arduino setup) */
void setup() {
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
}

/* repeat forever (arduino loop) */
void loop(){
 run_random_sequence();
}

Installing it outdoors
The LED segments were attached to the balcony edges. Then the wiring were done towards the Arduino. Everything sensitive to water is protected inside a plastic box. Silver tape was added to reduce the risk of water coming into the box. It should be said that the balcony is under another balcony (but this is an area of improvement).

An outdoor 230V cable comes out of the box and is connected to the outdoor electrical outlet together with a timer. The timer is adjusted so that everybody in the neighbourhood can sleep during the night without any lights at all.

(0) Comments    Read More   
Jan
06
Posted on 06-01-2013
Filed Under (Bootable USB stick, Windows) by Lonezor

Gone are the days when every computer had a CD Recorder Drive and a very nice burning program. Now most things are put on USB, in most cases on a regular file system. When an ISO file needs to be handled Windows users usually rely on smaller tools. But when I tried that today several programs were dead ends. Then I found a tools that is simple to use and just works. It is called Rufus.

Screenshot
Rufus


























Homepage & Conclusion
The tool can be found here.

This excellent program is also very fast and released under GPL license. Wonderful!

(0) Comments    Read More