Fixing Raspberry Pi WiFi dropping issue

Many of our Raspberry Pi projects needs remote accessibility. This means you spends lot of time using either VNC or SSH to access the Raspberry Pi. Unfortunately, when wifi connectivity drops and failed to re-connect your whole world stops right? On such situations, physically accessing the RPi and doing the restart is really a pain.



Writing checkwifi.sh


You can just copy paste this script into "/usr/local/bin/checkwifi.sh"

ping -c4 192.168.1.1 > /dev/null
 
if [ $? != 0 ] 
then
  echo "No network connection, restarting wlan0...!"
  /sbin/ifdown 'wlan0'
  sleep 5
  /sbin/ifup --force 'wlan0'
fi

What we are trying to do is, we are restarting the wireless interface. First it tries to ping a given IP with `ping` command.

Then `$?` represents the exit code of the previous command. In our case, previous command is `ping`. If `ping` command fails will output a different exit code(not 0). Then the code part inside the `if` will be executed. It will turn off, wait 5 seconds and re-start the wireless interface `wlan0`.

And make sure you have necessary execute permissions for the script.

sudo chmod 775 /usr/local/bin/checkwifi.sh

Adding a Cron Job


Open up the cron tab editor by `crontab -e` and add the following lines to the bottom of the file.
*/5 * * * * /usr/bin/sudo -H /usr/local/bin/checkwifi.sh >> /dev/null 2>&1

This script will run every 5 minutes with sudo permission. And the script's output is redirected to /dev/null hence won't clog your sys logs.

Done

Everything is done! now restart your RPi and enjoy!

XMPP/Jabber for IoT Devices - Part 2

From the previous post we discussed nuts and bolts of the XMPP(or Jabber) and how we can make use of it in the context of Internet-of-Things(IoT). This blog post will demonstrate a sample implementation on XMPP using unofficial official IoT XEPs(XMPP Extensions). These XMPP extensions are still in "Experimental" state at the time of writing this blog post.

Today we will be using XEP0030(service discovery), XEP0323(IoT sensor data) and XEP325(IoT control) for this sample. We are using SleekXMPP python library as XMPP client which implements these XEPs.

STEP 1:
First we need to setup a XMPP server. If you haven't setup any XMPP server; please follow this blog post which will describe "How to Setting up XMPP Openfire Server and expose via RESTful APIs". Please note that you can use a XMPP Server from any XMPP vendor. Here we use Openfire since it shipped with Apache Open Source license. Once you have setup Openfire server you need to create two user accounts "bob" and "alice". Our user story is that "alice" has a sensor device called "firealarm" and "bob" needs to get sensor information (e.g. temperature) of the "firealarm":D. Please refer the following image.
How Bob can get sensor information from the Alice's Firealarm

STEP 2:
Copy paste below python scripts into two files "xmpp_server.py" and "xmpp_client.py". Or you can directly download both scripts from this zip archive.

STEP 3:
We need to install SleekXMPP library. Enter following to install SleekXMPP from PyPI (Please visit here to get more install options).
pip install sleekxmpp

STEP 4:
Once Openfire server is up and running you can issue following commands;
python xmpp_server.py -j "alice@127.0.0.1"  -p "password" -n "firealarm"
In another terminal;
python xmpp_client.py -j "bob@127.0.0.1"  -p "password" -c "alice@127.0.0.1/firealarm" -q


IoT Server Code(xmpp_server.py)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
import sys
from optparse import OptionParser
import socket

import sleekxmpp

# Python versions before 3.0 do not use UTF-8 encoding
# by default. To ensure that Unicode is handled properly
# throughout SleekXMPP, we will set the default encoding
# ourselves to UTF-8.
if sys.version_info < (3, 0):
    from sleekxmpp.util.misc_ops import setdefaultencoding

    setdefaultencoding('utf8')
else:
    raw_input = input

from sleekxmpp.plugins.xep_0323.device import Device

class IoT_Server(sleekxmpp.ClientXMPP):
    """
    A simple IoT device that can act as server.

    This script can act as a "server" an IoT device that can provide sensor information.

    Setup the command line arguments.

    python xmpp_client.py -j "alice@yourdomain.com" -p "password" -n "device1" {--[debug|quiet]}
    python xmpp_client.py -j "alice@127.0.0.1" -p "password" -n "device1" {--[debug|quiet]}
    """
    def __init__(self, jid, password):
        sleekxmpp.ClientXMPP.__init__(self, jid, password)
        self.add_event_handler("session_start", self.session_start)
        self.add_event_handler("message", self.message)
        self.device = None
        self.releaseMe = False

    def testForRelease(self):
        # todo thread safe
        return self.releaseMe

    def doReleaseMe(self):
        # todo thread safe
        self.releaseMe = True

    def addDevice(self, device):
        self.device = device

    def session_start(self, event):
        self.send_presence()
        self.get_roster()
        # tell your preffered friend that you are alive
        # self.send_message(mto='jocke@jabber.sust.se', mbody=self.boundjid.bare +' is now online use xep_323 stanza to talk to me')

    def message(self, msg):
        if msg['type'] in ('chat', 'normal'):
            logging.debug("got normal chat message" + str(msg))
            ip = socket.gethostbyname(socket.gethostname())
            msg.reply("Hi I am " + self.boundjid.full + " and I am on IP " + ip + " use xep_323 stanza to talk to me").send()
        else:
            logging.debug("got unknown message type %s", str(msg['type']))

class IoT_Device(Device):
    """
    This is the actual device object that you will use to get information from your real hardware
    You will be called in the refresh method when someone is requesting information from you
    """

    def __init__(self, nodeId):
        Device.__init__(self, nodeId)
        logging.debug("=========TheDevice.__init__ called==========")
        self.temperature = 25  # define default temperature value
        self.update_sensor_data()

    def refresh(self, fields):
        """
        the implementation of the refresh method
        """
        logging.debug("=========TheDevice.refresh called===========")
        self.temperature += 1  # increment default temperature value by one
        self.update_sensor_data()

    def update_sensor_data(self):
        logging.debug("=========TheDevice.update_sensor_data called===========")
        self._add_field(name="Temperature", typename="numeric", unit="C")
        self._set_momentary_timestamp(self._get_timestamp())
        self._add_field_momentary_data("Temperature", self.get_temperature(),
                                       flags={"automaticReadout": "true"})

    def get_temperature(self):
        return str(self.temperature)

if __name__ == '__main__':
    #-------------------------------------------------------------------------------------------
    #   Parsing Arguments
    #-------------------------------------------------------------------------------------------
    optp = OptionParser()

    # Output verbosity options.
    optp.add_option('-q', '--quiet', help='set logging to ERROR',
                    action='store_const', dest='loglevel',
                    const=logging.ERROR, default=logging.INFO)
    optp.add_option('-d', '--debug', help='set logging to DEBUG',
                    action='store_const', dest='loglevel',
                    const=logging.DEBUG, default=logging.INFO)

    # JID and password options.
    optp.add_option("-j", "--jid", dest="jid",
                    help="JID to use")
    optp.add_option("-p", "--password", dest="password",
                    help="password to use")

    # IoT device id
    optp.add_option("-n", "--nodeid", dest="nodeid",
                    help="I am a device get ready to be called", default=None)

    opts, args = optp.parse_args()

    # Setup logging.
    logging.basicConfig(level=opts.loglevel,
                        format='%(levelname)-8s %(message)s')

    if opts.jid is None or opts.password is None or opts.nodeid is None:
        optp.print_help()
        exit()

    #-------------------------------------------------------------------------------------------
    #   Starting XMPP with XEP0030, XEP0323, XEP0325
    #-------------------------------------------------------------------------------------------

    # we bounded resource into node_id; because client can always call using static jid
    # opts.jid + "/" + opts.nodeid
    xmpp = IoT_Server(opts.jid + "/" + opts.nodeid, opts.password)
    xmpp.register_plugin('xep_0030')
    xmpp.register_plugin('xep_0323')
    xmpp.register_plugin('xep_0325')

    if opts.nodeid:
        myDevice = IoT_Device(opts.nodeid)
        xmpp['xep_0323'].register_node(nodeId=opts.nodeid, device=myDevice, commTimeout=10)
        while not (xmpp.testForRelease()):
            xmpp.connect()
            xmpp.process(block=True)
            logging.debug("lost connection")

IoT Client Code(xmpp_client.py)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
import sys
from optparse import OptionParser
import socket

import sleekxmpp
from sleekxmpp.exceptions import IqError, IqTimeout

# Python versions before 3.0 do not use UTF-8 encoding
# by default. To ensure that Unicode is handled properly
# throughout SleekXMPP, we will set the default encoding
# ourselves to UTF-8.
if sys.version_info < (3, 0):
    from sleekxmpp.util.misc_ops import setdefaultencoding

    setdefaultencoding('utf8')
else:
    raw_input = input

PRINT_HEADER_LENGTH = 40

class IoT_Client(sleekxmpp.ClientXMPP):
    """
    A simple IoT device that can act as client

    This script can act as a "client" an IoT device or other party that would like to get data from
    another device.

    Setup the command line arguments.

    python xmpp_client.py -j "bob@yourdomain.com" -p "password" -c "alice@yourdomain.com/device1" {--[debug|quiet]}
    python xmpp_client.py -j "bob@127.0.0.1" -p "password" -c "alice@127.0.0.1/device1" {--[debug|quiet]}
    """
    def __init__(self, jid, password, sensorjid):
        sleekxmpp.ClientXMPP.__init__(self, jid, password)
        self.add_event_handler("session_start", self.session_start)
        self.add_event_handler("message", self.message)
        self.device = None
        self.releaseMe = False
        self.target_jid = sensorjid

    def datacallback(self, from_jid, result, nodeId=None, timestamp=None, fields=None,
                     error_msg=None):
        """
        This method will be called when you ask another IoT device for data with the xep_0323
        se script below for the registration of the callback
        """
        logging.debug("we got data %s from %s", str(result), from_jid)
        if (result == "fields"):
            header = 'XEP 302 Sensor Data'
            print('-' * PRINT_HEADER_LENGTH)
            gap = ' '* ((PRINT_HEADER_LENGTH - len(header)) / 2)
            print(gap + header)
            print('-' * PRINT_HEADER_LENGTH)

            logging.debug("RECV:"+str(fields))

            if len(fields) > 0:
                print "Name\t\tType\tValue\tUnit"
            for field in fields:
                print "  - " + field["name"] + "\t" + field["typename"] + "\t" + field["value"] + "\t" + field["unit"]
            print ""
            self.disconnect()

    def testForRelease(self):
        # todo thread safe
        return self.releaseMe

    def doReleaseMe(self):
        # todo thread safe
        self.releaseMe = True

    def addDevice(self, device):
        self.device = device

    def session_start(self, event):
        self.send_presence()
        self.get_roster()
        # tell your preffered friend that you are alive using generic xmpp chat protocol
        # self.send_message(mto='jocke@jabber.sust.se', mbody=self.boundjid.bare +' is now online use xep_323 stanza to talk to me')

        #-------------------------------------------------------------------------------------------
        #   Service Discovery
        #-------------------------------------------------------------------------------------------
        try:
            # By using block=True, the result stanza will be
            # returned. Execution will block until the reply is
            # received. Non-blocking options would be to listen
            # for the disco_info event, or passing a handler
            # function using the callback parameter.
            info = self['xep_0030'].get_info(jid=self.target_jid,
                                             node=None,
                                             block=True)
        except IqError as e:
            logging.error("Entity returned an error: %s" % e.iq['error']['condition'])
        except IqTimeout:
            logging.error("No response received.")
        else:
            header = 'XMPP Service Discovery'
            print('-' * PRINT_HEADER_LENGTH)
            gap = ' '* ((PRINT_HEADER_LENGTH - len(header)) / 2)
            print(gap + header)
            print('-' * PRINT_HEADER_LENGTH)

            print "Device: %s" % self.target_jid

            for feature in info['disco_info']['features']:
                print('  - %s' % feature)

        #-------------------------------------------------------------------------------------------
        #   Requesting data through XEP0323
        #-------------------------------------------------------------------------------------------
        session = self['xep_0323'].request_data(self.boundjid.full, self.target_jid,
                                                self.datacallback, flags={"momentary": "true"})

    def message(self, msg):
        if msg['type'] in ('chat', 'normal'):
            logging.debug("got normal chat message" + str(msg))
            ip = socket.gethostbyname(socket.gethostname())
            msg.reply("Hi I am " + self.boundjid.full + " and I am on IP " + ip + " use xep_323 stanza to talk to me").send()
        else:
            logging.debug("got unknown message type %s", str(msg['type']))

if __name__ == '__main__':
    #-------------------------------------------------------------------------------------------
    #   Parsing Arguments
    #-------------------------------------------------------------------------------------------
    optp = OptionParser()

    # JID and password options.
    optp.add_option("-j", "--jid", dest="jid",
                    help="JID to use")
    optp.add_option("-p", "--password", dest="password",
                    help="password to use")

    # IoT sensor jid
    optp.add_option("-c", "--sensorjid", dest="sensorjid",
                    help="Another device to call for data on", default=None)

    # Output verbosity options.
    optp.add_option('-q', '--quiet', help='set logging to ERROR',
                    action='store_const', dest='loglevel',
                    const=logging.ERROR, default=logging.INFO)
    optp.add_option('-d', '--debug', help='set logging to DEBUG',
                    action='store_const', dest='loglevel',
                    const=logging.DEBUG, default=logging.INFO)

    opts, args = optp.parse_args()

    # Setup logging.
    logging.basicConfig(level=opts.loglevel,
                        format='%(levelname)-8s %(message)s')

    if opts.jid is None or opts.password is None or opts.sensorjid is None:
        optp.print_help()
        exit()

    #-------------------------------------------------------------------------------------------
    #   Starting XMPP with XEP0030, XEP0323, XEP0325
    #-------------------------------------------------------------------------------------------
    xmpp = IoT_Client(opts.jid, opts.password, opts.sensorjid)
    xmpp.register_plugin('xep_0030')
    xmpp.register_plugin('xep_0323')
    xmpp.register_plugin('xep_0325')

    if opts.sensorjid:
        logging.debug("will try to call another device for data")
        xmpp.connect()
        xmpp.process(block=True)
        logging.debug("ready ending")

    else:
        print "noopp didn't happen"

Setting up XMPP Openfire Server and expose via RESTful APIs

In my previous post I explained most of the fundamentals in XMPP. In this post I hope to explain how we can implement XMPP IoT sample.

First we need to setup a XMPP server(or Jabber server). There are many XMPP server implementations available based on different and competitive license and support models. In this example I have chosen Openfire which comes with Apache license which one of well-known corporate friendly open source license.

Installing Openfire Jabber Server


STEP 1:
Goto download link and download Openfire latest version.

STEP 2:
Extract the zip archive file(depends on the platform) and run the setup.

STEP 3:
Go through installation steps and complete the installation.


STEP 4:
In MAC-OSX; I had to do one more additional step since "openfire" ownership was "openfire:247". 

sudo chown -R <your_os_username>:admin /usr/local/openfire
chmod +x /usr/local/openfire/bin/*.sh

Then you can run the server using following command;

cd /usr/local/openfire/bin
./openfire

If everything ran smoothly, terminal should print the following;

Openfire 3.10.2 [Aug 12, 2015 11:13:20 PM]
Admin console listening at http://rasikas-macbook-pro.local:9090

Just copy and paste admin console url on the address bar of a web browser.
STEP 5:
Now setup wizard should be appeared on the web browser. Select "English" as the language and click "continue". On the second screen enter the following;

Domain -> 127.0.0.1 #or enter the IP assigned on ifconfig.
Admin Console Port -> 9090 #http login
Secure Admin Console Port -> 9091 #https login
Property Encryption via -> Blowfish


STEP 6:
On the next step select "Embedded Database" and click "Continue". This is will simplify the database connection process and make use of its HSQLDB internally embedded DB. On the production environment you must select "Standard Database Connection" and configure a separate database.

STEP 7:


For the profile settings; select "Default". this option will keep the user information on the connected database.

STEP 8:
On the next step; enter an "email" and a valid password for the admin account. Click "Continue".

STEP 9:
Once you are done, It will display "Setup Complete!" message. Then click on "Log to the admin console".

STEP 10:
Once you are redirected, enter the username as "admin" and the password will be the same you gave on the previous Step 8. If you are unable to login using provided credentials; please try restarting the server.


Creating a New User

On this step we will create a new user on the open fire using admin console.

STEP 1:
Navigate into "Users/Groups" tab. Select "Create New User" on the left menu pane.



Deploying REST-API plugin to manage users

When integrating with other servers, manually creating each user on the openfire is not scalable or feasible approach. Hence you can use Openfire plugins. REST-API plugin provides functionalities to manage users through HTTP calls. API documentation is available on here.

In order to install plugin, you can just copy "restApi.jar" file into $OPEN-FIRE-HOME/plugins folder. In  OS-X "/usr/local/openfire/plugins". You don't need to restart the server. It will automatically deployed.

To configure REST API, Go to Server -> Server Settings. Then REST API from the left menu pane.

XMPP/Jabber for IoT Devices - Part 1

Recently we implemented XMPP (or Jabber) support into our IoT Device Management Framework. Ideally this provides near realtime communication between multiple devices over multiple networks. The architecture of the Jabber server is conforms to an email server(server.com) where XMPP clients conforms email clients(user@server.com). Many chat clients implements XMPP to communicate between distributed networks near realtime.

Earlier we had the assumption of each device always have an accessible IP address. Based on this assumption we had an HTTP server running on the client-side. The APIs on the IoT Device Framework can call HTTP server on the device and perform actuators and sensor readings.

HTTP server based implementation
HTTP server based implementation


What's wrong with HTTP?
Let me explain why this doesn't work all time. Suppose you need to make your devices controllable through IoT Device Framework APIs over Internet. One option is to provide public IPs into each device. Oh God!, it is not a good solution.

Then other option is NAT. The devices are exposed into Internet over a NAT gateway. Outgoing messages from the device will be modified by NAT gateway so that they appear to be coming from the NAT gateway itself. The NAT gateway will record the changes it makes in its state table so that it can reverse the changes on return packets. NATs will keep the association for as long as the connection is alive. When your API calls returning into NAT gateway, Gateway itself might not be able to find return destination.

How NAT works
How NAT works (photo courtesy of How Stuff Works)
How XMPP handle it?
Let's see how XMPP can handle this. XMPP is the Internet Standard for real time messaging communication and presence. It uses a standard TCP connection. You can use fully-fledged light-weight XMPP pings (XEP-0199) to keep NAT records alive. Need to notice that XMPP can be also implemented over HTTP too(BOSH). Prime advantage of the XMPP is that you can address a device on "user@server.com/mobile" resource addressing scheme instead of IP of the device. XMPP can act

XMPP's basic model of communication is Client -> Server -> Server -> Client, and in support of this it defines a Client to Server protocol and a Server to Server protocol. Both of these protocols use XML encoded protocol directly over TCP. XMPP is a Bi-directional stream and "non-blocking":uses event-driven style. Powerful XMPP extensions such as Pub-Sub(XEP060) are available out-of-the box.
HTTP polling vs XMPP PubSub(source: [1])


How XMPP works?
The major steps for server-to-client communication as follows;
  1. Client and server communicate through port 5222 via a TCP connection.
  2. XMPP informations are contained on XML streams. A XMPP session is opened by <stream> tag and ended by </stream> tag.  All other parts are located between them.
  3. For security purpose, the open stream is followed by moderate Transport Layer Security (TLS)  negotiation and compulsory Simple Authentication and Security Layer (SASL) negotiation.
  4. A new stream will be opened immediately after the SASL negotiation, and it will be more secure and safe.
Please refer this post for more detail explanation.

XMPP Network Architecture
XMPP Network Architecture

The next blog-post will describe how you can configure XMPP client and a server based on unofficial official XMPP IoT devices standard.

Links:
[1] http://www.slideshare.net/igrigorik/event-driven-architecture-meshu-ilya-grigorik

Git Rewrite History, Removing Old Commits From History


"REWRITING History is a BAD PRACTICE and should AVOID as much as possible".
We recently came across this serious issue with "git" repositories. In our word; "WE MESSED UP OUR REPO". Had several reverts to fix it(But revert again is recorded as commit and so on...). Again needed to revert all revert commits. All these things altogether left us one option; which is the rewriting the history.

This post will show you how to re-write, but this will be an issue if lots of people have based their work on the remote master branch and have pulled that branch in their local repo (But if you haven't push the revert commits into remote repository; this would be the ideal solution).

What we are trying to achieve here is...
  1. go back to a past revision
  2. create and switch to a dummy branch
  3. rename dummy branch into the master.

Yep, That's it!

STEP 1:
First we need to rewind back to a specific commit. Below command will move the pointer to a specific commit. The "<SHA1>" is the commit id.

git reset --hard <SHA1>
git status

Should output something similar below. Note that in this example given commit id resulted current branch to move back 10 commits.

On branch master
Your branch is behind 'origin/master' by 10 commits, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working directory clean

STEP 2:
Now create a new branch base on the current pointer and switch into it.
git checkout -b temp
STEP 3:
As the final step we are renaming our "master" branch into another and "temp" into "master".
git branch -m master old-master #rename master branch into old-master
git branch -m temp master #rename temp branch into master
git push -f origin master #do a force push changes

Setting JAVA_HOME on Raspberry Pi

The new Raspbian build comes with Java 1.8 pre-installed. You can check the current java version by issuing following command;

java -version


java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) Client VM (build 25.0-b70, mixed mode)

In order to set environment variable "JAVA_HOME"; you can set it on ~/.bashrc file.

nano ~/.bashrc


then add the following into the end of file and save changes.

export JAVA_HOME="/usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt"
export PATH=$PATH:$JAVA_HOME/bin

Then on you next login you can try out this;

export

which should ideally print;

declare -x JAVA_HOME="/usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt"
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt/bin"

Compiling ARM1176 for QEMU Raspberry Pi Emulation Kernel

This is referred from this forum post and optimized for Mac OSX users. This blog post will show you how to compile a QEMU-ready Linux kernel for the ARM1176JZF-S CPU used by the Raspberry Pi. If you want to skip all of this and just have a kernel you can use, you can download 3.18 kernel here.


1. Preparing the development environment

Installing brew

First you need to have a package manager. HomeBrew is a good choice(for more info. refer this post). Or you can use any other such as "macport".
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Installing libcurses5 library

libncurses5-dev
brew install homebrew/dupes/ncurses
brew link --force ncurses

Installing crosee-compiler tools

You can download pre-compiled cross-compiler tools for MAC OSX from this blog.
After the installation add the binaries to your path.
echo "/usr/local/linaro/arm-linux-gnueabihf-raspbian/bin" >> /etc/paths

2. Preparing the Linux Kernel

Installing Git

Installing any package on homebrew is simple as "brew install <package_name>".
brew install git

Download the source

Download linux source from raspberrypi linux repository.
git clone https://github.com/raspberrypi/linux.git

3. Configure the Kernel

Then we need to configure the kernel accordingly:
cd linux
make ARCH=arm versatile_defconfig
make ARCH=arm menuconfig

Specify the cross-compiler:

General Setup --->
    Cross-compiler tool prefix
        (arm-linux-gnueabihf-)

Note: Do not forget the '-' at the end of this string.
Note: When you select an option make sure you don't see 'M', but '*' (you may need to press space twice).

Select the right CPU options:

System Type --->
    [*] Support ARM V6 processor
    [*] ARM errata: Invalidation of the Instruction Cache operation can fail
    [*] ARM errata: Possible cache data corruption with hit-under-miss enabled

Enable support for hard-float binaries:

Floating point emulation  --->
    [*] VFP-format floating point maths

Enable ARM EABI:

Kernel Features --->
    [*] Use ARM EABI to compile the kernel
    [*] Allow old ABI binaries to run with this kernel

Enable QEMU's disk support:

Bus Support --->
    [*] PCI Support
Device Drivers --->
    SCSI Device Support --->
        [*] SCSI Device Support
        [*] SCSI Disk Support
        [*] SCSI CDROM support
        [*] SCSI low-lever drivers --->
        [*] SYM53C8XX  Version 2 SCSI support

Enable devtmpfs:

    Device Drivers --->
        Generic Driver Options--->
            [*] Maintain a devtmpfs filesystem to mount at /dev
            [*] Automount devtmpfs at /dev, after the kernel mounted the root

Enable the important file systems:

    File systems -->
        <*> Ext3 journalling file system support
         <*> The Extended 4 (ext4) filesystem

Enable tmpfs:

File systems --->
    Pseudo filesystems--->
        [*] Virtual memory file system support (former shm fs)

Enable the event interface:

Device Drivers --->
    Input device support--->
        [*] Event interface

Adding RaspberryPi Logo into Kernel:

Device Drivers --->
    Graphics Support --->
        Console display driver support --->
            [ ] Select compiled-in fonts
                [*] Bootup logo (optional)

Exit, saving the configuration.

4. Compiling the Kernel

make ARCH=arm
mkdir ../modules
make ARCH=arm INSTALL_MOD_PATH=../modules modules_install

Troubleshooting

Error 1:
scripts/mod/modpost.c:1465:7: error: use of undeclared identifier 'R_386_32'
        case R_386_32:

Create a new file elf.h and paste this code from the opensource.apple.com.

nano /usr/local/include/elf.h

In the same file append these...

#define R_386_NONE 0
#define R_386_32 1
#define R_386_PC32 2
#define R_ARM_NONE 0
#define R_ARM_PC24 1
#define R_ARM_ABS32 2
#define R_MIPS_NONE 0
#define R_MIPS_16 1
#define R_MIPS_32 2
#define R_MIPS_REL32 3
#define R_MIPS_26 4
#define R_MIPS_HI16 5
#define R_MIPS_LO16 6

Error2:

/usr/local/include/elf.h:45:10: fatal error: 'elftypes.h' file not found
#include "elftypes.h" /* In lieu of Solaris <sys/elftypes.h> */

create a new file elftypes.h and paste this code from  the opensource.apple.com.

nano /usr/local/include/elftypes.h

Error 3:

xargs: illegal option -- r

This is because BSD xargs doesn't have the same options as GNU xargs. Install GNU xargs from macports (It should show up earlier in your search path)

# Install GNU `find`, `locate`, `updatedb`, and `xargs`, g-prefixed
brew install findutils

Replace all files using 'xargs' to 'gxargs'. (Use a sublime or any texteditor).

5. Copy compiled Kernel

Copy the compiled kernel to your working directory:

cp arch/arm/boot/zImage ../

Done! You should name have a QEMU-bootable linux kernel and modules in your work directory.

Arduino UNO Clone Serial Port CH340/CH341 Drivers for Mac OS X

Recently I tried connecting my newly purchased clone version of the Arduino UNO with the MacBook OS X Yosemite. It turns outs that, nothing gonna detect my serial port. This is because most of the clone versions are using a different chip for USB-to-Serial communication namely CH340/CH341 instead of ATmega16U2.


After hours of work and digging throughout the Internet, I found these drivers for CH341/CH340 is working as expected.

Here how you do it;


Download the drivers and install relevant setup. This package includes, drivers for linux, mac os x and windows.

Download all-in-one drivers pack

One more additional step for Mac OS X users. Disable the kext signing security setting with this command.

sudo nvram boot-args="kext-dev-mode=1"

How to test it;

on the terminal type;

ls /dev/tty*

you should see something like "/dev/tty.wchusbserial1410". In addition, if you open up your Ardunio IDE then goto Tools->Port. You should see something similar to below.