Friday, 26 August 2016

MATLAB Error: Subscript indices must either be real positive integers or logicals.

I was attempting to run some code in MATLAB to perform filtering, and was hit by the following error:

Subscript indices must either be real positive integers or logicals.

The code that I was using was taken from a Stack Overflow Post and the relevant line of code that generated the error is as follows:

% Process the signal with the matched filter
y = filter(b,1,x);

This was resulting in the above error. The issue was that in some previous code, I had defined the variable 'filter' as the coefficients of a filter, and this was still in my workspace. Thus MATLAB was interpreting 'filter' as a variable instead of a function, and so the parameters passed to the function were actually interpreted as indicies within the variable, which must be whole numbers. So to fix the error, before calling the line with the 'filter()' function, I just have to delete the variable with the same name. This can be done using the 'clear' command. There is the possiblity to clear the entire workspace of variables, or rather just the specific offending variable.

To clear the variable that is causing the problem, I used the following command:

clear('filter')

where filter is my variable name. Alternatively just the command 'clear' on its own will clear all variables from the workspace:

clear





Wednesday, 29 June 2016

MATLAB Undefined function 'strsplit' for input arguments of type 'char'.

I encountered the following error in MATLAB:

Undefined function 'strsplit' for input arguments of type 'char'.

This is because the function strsplit() was only added in R2013a, and any earlier versions. Instead I used the textscan() function, and set the 'delimeter' parameter to the character I wanted to split the string by.

Tuesday, 28 June 2016

Problem with MATLAB textscan only reading in first cell

I was having a problem with MATLAB using the textscan() function, where it was only reading in the data for the first cell, but wasn't throwing any errors.

I was using the following command:

T = textscan(fid, format_spec, 'HeaderLines', 0);

Evaluating T seemed to show that the file was being read correctly, with the correct number of colums matching my CSV.

>> T
T =
  Columns 1 through 4
    {1x1 cell}    [11]    [0x1 double]    [0x1 double]
  Columns 5 through 7
    [0x1 double]    [0x1 double]    [0x1 double]
  Columns 8 through 10
    [0x1 double]    [0x1 double]    [0x1 double]

The problem was that I was reading a CSV file, and the default setting for textscan uses another option for the delimiter. By leaving this field unspecified, the function was not able to handle the file correctly. I changed the line to the following:

T = textscan(fid, format_spec, 'Delimiter', ',', 'HeaderLines', 0);

This now read in the entire file correctly, revealing all of the rows were read in as expected:

>> T
T =
  Columns 1 through 2
    {81231x1 cell}    [81231x1 double]
  Columns 3 through 4
    [81231x1 double]    [81231x1 double]
  Columns 5 through 6
    [81231x1 double]    [81231x1 double]
  Columns 7 through 8
    [81231x1 double]    [81231x1 double]
  Columns 9 through 10
    [81231x1 double]    [81231x1 double]

Note that the data was read into "cells", which means that it must be handled slightly differently. In this case, if I evaluate T(1), this doesn't give all of the data from column one, I just get the following:


>> T(1)
ans =
    {81231x1 cell}

Instead, I have to use the following command:

>> T{1}
ans = 
    '2016-02-05_19-09-50'    '2016-02-05_19-10-38'    '2016-02-05_19-21-43'    '2016-02-05_19-22-31'    '2016-02-05_19-23-19'    '2016-02-05_19-24-08'    '2016-02-05_19-26-11'    '2016-02-05_19-26-59'    '2016-02-05_19-27-47'    '2016-02-05_19-28-36'

Note the curly braces around the number after T. It is also possible to only return a subset of the data by specifying the indices after the curly braces, as follows:

>> T{1}(1:3)
ans = 
    '2016-02-05_19-09-50'    '2016-02-05_19-10-38'    '2016-02-05_19-21-43'

Finally, we can get the data into a format we are more used to by using the cell2mat() function.

dates=cell2mat(T{1})

This concerts the data into a matrix. In my case I have read in strings, and so the matrix is a 2d array. Now to view the first three dates, I can use the following command:

>> dates(1:3,:)
ans =
2016-02-05_19-09-502016-02-05_19-10-382016-02-05_19-21-43

And from here the data can be treated as normal.







MATLAB Error using textscan Param/value pairs must come in pairs. Also Error using textscan Badly formed format string.

The textscan() function expects certain parameters in a specific order. If these are not as expected, the following error is given:

Error using textscan
Param/value pairs must come in pairs.

From the documentation, this format should be as follows:
C = textscan(fileID,formatSpec)

or with the optional parameters set:
C = textscan(fileID, formatSpec, Name, Value);

I was getting this error as I had originally tried to define the 'formatspec' entry name - and this turns out to be unnecessary.

I ended up using the following formatSpec for the command:

format_spec = '%s%f%f%f%f%f%f%f%f%f'

(Note no commas here)

I had also tried to use a date format string as follows:

date_format='%{yyyy-mm-dd_HH-MM-SS}D'; 

However this produced the following error:

Error using textscan
Badly formed format string.

I'm sure that the date_format string is correct, so I found that I can replace this with a simple %s to read the column into a string, and handle the data manually.

Undefined function 'readtable' for input arguments of type 'char'. or type 'double'.

There are two separate errors for the readtable() function in MATLAB that can occur for different reasons. The first is the following:

Undefined function 'readtable' for input arguments of type 'char'.

This occurs when passing a filename to the 'readtable()' function, as it expects to be passed a file hander, so instead the following usage should be used:

fid = fopen(file, 'r');
T = readtable(fid, 'Delimiter', ',', 'Format', format_spec);
flcose(fid);

The other reason for getting this error is using a version of MATLAB that is too old. If you run the code with this change, with a version of MATLAB that is too old then you will get the following error:

Undefined function 'readtable' for input arguments of type 'double'.

The readtable() function was introduced to MATLAB in R2013b, so any versions earlier than this will give this error as the function is not defined.

R Install Required Packages

When using R, if there is a script with multiple packages that might not be installed, it can take some time to go through the list and check they are all installed.

Instead of using the "require(packagename)" command, I used the following script to load packages

pkgTest <- function(x)
{
  if (!require(x,character.only = TRUE))
  {
    install.packages(x,dep=TRUE)
    if(!require(x,character.only = TRUE)) stop("Package not found")
  }
}

This script tries to load the package using the "require" command, and if this is not successful then will try to install it. It then tries the "require" command once more, and if not successful will stop the code execution.

Monday, 6 June 2016

MATLAB Error - Warning: Executing startup failed in matlabrc. In matlabrc at 212

After reinstalling MATLAB I saw the following error:

Warning: Executing startup failed in matlabrc.
This indicates a potentially serious problem in your MATLAB
setup,
which should be resolved as soon as possible.  Error detected
was:
MATLAB:FileIO:InvalidFid
Invalid file identifier.  Use fopen to generate a valid file
identifier.
> In matlabrc at 212 

This was due to a problem in my "startup.m" file which was still persistent from a previous installation, which tried to load a toolbox that was no longer installed. This was located in the following folder:

%UserProfile%\Documents\MATLAB

As I had no files there that I needed, I renamed the folder to MATLAB_old, then tried opening MATLAB again. This time it started up fine so I deleted the folder completely as it is not needed for my version (R2012a).

Saturday, 9 April 2016

Problems when programming the ESP8266-12E using Arduino software/IDE

I followed this instructables tutorial to program the ESP8266-12E. I was able to program the board the first time correctly, however trying to make changes and update the code didn't work. When I tried to update the code using the arduino IDE, I got the following messages:

warning: espcomm_sync failed
error: espcomm_open failed
error: espcomm_upload_mem failed

So I tried changing some settings with no luck. By trial and error I found the solution. On the board is a button called "Flash". This button needs to be held down when connecting the USB cable between the board and your computer. If not, it is not possible to program using the default arduino settings. I expect there is some way to enable this however I haven't yet dug deeper in to this problem, as I just wanted to get some basic functionality working.

Friday, 26 February 2016

R View more than 100 columns when exploring variable data.

I normally use R Studio when working with R. I found there is a problem when double clicking the variable name in the environment view, as the window which is displayed only shows the first 100 rows. Double clicking the variable name is the same as entering the following command:

View(data)

Instead, use the following command:

utils::View(data)

These examples assume the name "data" is the one that you want to view.

Friday, 5 February 2016

Scan WiFi networks on the raspberry pi using essid and the grep command

First of all, find the name of the wireless network adapter. Enter the command ifconfig to show each network interface along with its details. The IP address and further information is also shown, but we just need the name shown in the left most column. There will be an entry for lo, and probabaly one for eth0 if you have a connection by ethernet also. My WiFi dongle showed up as wlan0 which is typical. If you have more than one WiFi adapter, it will probabaly show up as wlan1, wlan2, etc.

Then use the following command:

sudo iwlist wlan0 scan

I have used wlan0 as the interface name, if you found something earlier in a previous step then obviously you should change wlan0 to the interface name.

I ended up getting quite a log list of networks which went off the top of the screen, with a lot of unneeded information. So it is possible to reduce the amount of information shown. To do that, we pipe the output to the grep command, which searches within the data and only displays data that matches what we are searching for. Each network contains information about the network, including the field "ESSID" which is the network ID. To only display these lines, use the following command:

sudo iwlist wlan0 scan | grep ESSID

The command is case sensitive, alternatively we can use the -i flag at the end to make it case insensitive, as follows:

sudo iwlist wlan0 scan | grep essid -i

Thursday, 28 January 2016

Connecting SKU193431 I2C RTC To a Raspberry Pi

The I2C module came in a bag with "SKU193431 EVU" on the sticker, which Googling finds the banggood page from which it was ordered, but not much else.

http://www.banggood.com/RTC-Real-Time-Clock-Module-For-Raspberry-Pi-p-965976.html

There is no schematic or any further details, also there is no markings on the RTC module to indicate even which pin is positive. I found the following image on the internet showing the GPIO header pinout:



I took a guess that I should connect it to point 01, 03, 05, 07, 09. This is the inner most set of connectors. Then I carried on with a guide that I had found online. Luckily my guess was correct. There are no other pins on the GPIO header with an I2C label, but I was mostly concerned about the power connections - if connected the wrong way with 3.3V the wrong way across the battery it could cause some damage. Anyway, luck was on my side and it seemed to all work fine. So on to the software setup.

The first thing to do is to enable I2C in the raspi-config tool. To do this, open the configuration tool:

sudo raspi-config

Go in "Advanced Options" > "I2C" > "Yes"

When asked if the default module should be loaded by default, select "Yes", and then reboot the raspberry pi.

Then I followed steps from here: http://www.drewkeller.com/blog/adding-hardware-clock-raspberry-pi-ds3231

# Comment out the blacklist entry so the module can be loaded on boot
sudo sed -i 's/blacklist i2c-bcm2708/#blacklist i2c-bcm2708/' /etc/modprobe.d/raspi-blacklist.conf
# Load the module now
sudo modprobe i2c-bcm2708
# Notify Linux of the Dallas RTC device (use -0 for Model A or -1 for Model B)
echo ds3231 0x68 | sudo tee /sys/class/i2c-adapter/i2c-1/new_device
# Test whether Linux can see our RTC module.
sudo hwclock

The response was the time that the RTC thought it was, which hadn't yet been set. If you get this, then that looks good ad the hardware aspect is correctly connected and working.

The raspberry pi was connected to the internet and got the time and date automatically, as can be checked by the "date" command.

If the date is wrong, this can be set with the following command:

sudo date -s "Jan 27 2016 12:41:01"

I have previously had some problems when setting the time and date together, and found I had better luck setting first the date, and then the time, rather than both together in the same command. I think this was due to problems with the formatting, but this method of splitting the time and date helped. Then write the current date and time to the RTC module using the following command:

sudo hwclock -w

Then edit the /etc/rc.local file with this command:

sudo nano /etc/rc.local

and add the following two lines before the line "exit 0":

echo ds3231 0x68 > /sys/class/i2c-adapter/i2c-1/new_device
hwclock -s

Now disable the fake hardware clock with the following line:

sudo update-rc.d fake-hwclock disable

The network time can also be disabled, but I wanted to leave this in place. To disable this, use the following command:

sudo update-rc.d ntp disable

But if it is left in place, then the clock should be updated each time that the raspberry pi connects to the internet, but will keep time when powered off, and when rebooted without power.



Python base64 decode Problem

I was struggling with a problem in Python, trying to use the base64 package to decode some base64 data, using the base64.decode() function. I was passing my string to the function, so my code looked link the following:

import base64
#code to load base64 data from file
encoded='ZGF0YSB0byBiZSBlbmNvZGVk'
outputdata=base64.decode(encoded)

Well I obviously had different code to handle the loading of the data from the file, but I have just changed the code to use a string with encoded data for this example.

If you try and run this code, you will get the following error:

Traceback (most recent call last):
  File "removed", line 4, in <module>
    outputdata=base64.decode(encoded)
TypeError: decode() takes exactly 2 arguments (1 given)

This was confusing as I couldn't find any more information about what should be in the second argument, so I tried a few different things, nothing works.  If you do this, the error will instead change to the following:

Traceback (most recent call last):
  File "removed", line 4, in <module>
    outputdata=base64.decode(encoded, '')
  File "C:\Python27\lib\base64.py", line 303, in decode
    line = input.readline()
AttributeError: 'str' object has no attribute 'readline'

The problem was that I was infact calling the wrong function name. There are 2 separate functions, and the function I thought I was using, takes just a string, and the function that I was actually using takes 2 parameters, and I think is intended to read from a file on this disk.

So this is quite an easy fix, which is to instead use the function base64.b64decode(encoded_data), and just means I wasn't reading the manual well enough. I am documenting it here because Googling the previous error messages along with some keywords about base64 and decoding didn't turn up anything. It was only when I went back to the very basic example that I noticed my error. Thus the final working code is as follows:

import base64
#code to load base64 data from file
encoded='ZGF0YSB0byBiZSBlbmNvZGVk'
outputdata=base64.b64decode(encoded)
print(outputdata)


Wednesday, 27 January 2016

Creating a captive portal on the raspberry pi that functions separately to the ethernet connection using a Realtek Semiconductor Corp. RTL8188CUS 802.11n WLAN Adapter

I wanted to add a USB WiFi dongle to my Raspberry Pi to allow connection to it with a mobile phone, and to display a status page in the browser, but I didn't want to bridge the WiFi network to the internet, so that I didn't have to worry about unauthorised people accessing the internet through my WiFi connection. I also didn't want to disconnect the Raspberry Pi from the internet completely, as it it "phones home" to my server occasionally so that I know it is still running, and by leaving the ethernet connection functioning fully, it also allows me to update the Rasbperry Pi or make changes to the software.

Most of the tutorials on the internet for setting up a wireless access point (AP) are assuming that it will done with the connection to the internet. This is not the case for me, and so by some trial and error, and following a few different guides, I have finally found a working solution.

The first step was to understand the hardware that I had. Using the command "lsusb" lists the USB devices that are connected. By entering the command, then connecting the USB WiFi dongle, and entering the command again it is easy to see what has changed. For my dongle, I get the following information:

Bus 001 Device 005: ID 0bda:8176 Realtek Semiconductor Corp. RTL8188CUS 802.11n WLAN Adapter


The identifying string is RTL8188CUS and googling this shows some issues with the driver when trying to connect it to the raspberry pi.

First of all, I got the dongle working as an access point with the correct driver. To do this, I followed the excellent tutorial by Dave Conroy. The tutorial can be found here: http://www.daveconroy.com/turn-your-raspberry-pi-into-a-wifi-hotspot-with-edimax-nano-usb-ew-7811un-rtl8188cus-chipset/

I already had the raspberry pi running correctly, so I started with the "Prerequsites" section. The first command to install two packages is as follows:

sudo apt-get install bridge-utils hostapd
With this command, both bridge-utils and hostapd were installed. I don't think bridge-utils was needed, but I left the command incase there are any changes made by this package that weren't immediately apparent.

The next set of commands were copied verbatim from Dave's Blog. He hosts a replacement hostapd binary which resolves the incompatibilities with the WiFi dongle chipset. This can be downloaded and installed with the following commands:

wget http://www.daveconroy.com/wp3/wp-content/uploads/2013/07/hostapd.zip
unzip hostapd.zip
sudo mv /usr/sbin/hostapd /usr/sbin/hostapd.bak
sudo mv hostapd /usr/sbin/hostapd.edimax
sudo ln -sf /usr/sbin/hostapd.edimax /usr/sbin/hostapd
sudo chown root.root /usr/sbin/hostapd
sudo chmod 755 /usr/sbin/hostapd

The above commands will replace the standard hostapd binaries with new updated ones from the zip file that are compatible with out WiFi dongle driver.

The section on "Bridging the Connections", I skipped entirely, as I want the ethernet and Wifi networks to be separate. I skipped to the section "Configuring Hostapd". Here to enter the file editor, enter the command:

sudo nano /etc/hostapd/hostapd.conf

Then there is some recommended entries for the file, however I modified this somewhat. My version of the file is as follows:

interface=wlan0
driver=rtl871xdrv
#bridge=br0
ssid=NETWORKNAME
channel=6
wmm_enabled=0
#wpa=1
#wpa_passphrase=ConroyPi
#wpa_key_mgmt=WPA-PSK
#wpa_pairwise=TKIP
#rsn_pairwise=CCMP
#auth_algs=1
#macaddr_acl=0
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0


The hash (#) character represents a comment for the entire line, and so the line is skipped over. I have commented out the section to do with security as I want the hotspot to work without authentication. This is also why I wanted to separate the two networks and not bridge them. The last two lines were added in from a separate tutorial, which I will link to shortly.

The next step was to reboot, and then test the configruation using the following command:

sudo hostapd -dd /etc/hostapd/hostapd.conf

Then I checked with a WiFi enabled device and found my network SSID. This allowed me to connect, however requesting a website failed - which for me was a success!

Now I started to Google further for how to make a captive portal, and found a guide on the website sirlagz.net, here: http://sirlagz.net/2013/08/23/how-to-captive-portal-on-the-raspberry-pi/ - This guide also has several previous steps on setting up the access point. So I went back to the access point guide and reviewed this to make sure I hadn't missed any prerequisits here also. This guide is linked here: http://sirlagz.net/2012/08/09/how-to-use-the-raspberry-pi-as-a-wireless-access-pointrouter-part-1/

Something that I hadn't done yet was to assign a static IP. To do this, enter the following command;

sudo nano /etc/network/interfaces

This opens the text editor for the network interfaces. Then further down the file, there should be an entry for wlan0. Change the entry so that the settings are as follows:

iface wlan0 inet static
address 10.0.0.1
netmask 255.255.255.0

My complete interfaces file is as follows:


# interfaces(5) file used by ifup(8) and ifdown(8)
# Please note that this file is written to be used with dhcpcd# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
# Include files from /etc/network/interfaces.d:source-directory /etc/network/interfaces.d
auto loiface lo inet loopback
iface eth0 inet manual
allow-hotplug wlan0iface wlan0 inet staticaddress 10.0.0.1netmask 255.255.255.0#    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
allow-hotplug wlan1iface wlan1 inet manual    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf


Note once again, a hash at the beginning of the line indicates the line is commented. Next the hostapd file needs to be set. To do this, open the file with the following command:

/etc/default/hostapd

And find the line with the following text:

DAEMON_CONF=""


This needs to be modified so that it refers to the location of the .conf file, so it should appear as follows:

DAEMON_CONF="/etc/hostapd/hostapd.conf"

Then the access point tutorial talks more  about changing the hostapd.conf file, but we did this earlier. Also there is some changes to the WiFi settings, but these are also okay. Finally we need to install dnsmasq. The tutorial I followed mentions that this is to handle the issuing of IP addresses.

To install the package, run the following command;

apt-get install dnsmasq

Then we need to edit the .conf configutation file. To open that use the command;

sudo nano /etc/dnsmasq.conf

This is a huge file, and we need to scroll right to the bottom. The keyboard shortcut ctrl+v scrolls down one page at a time, which is faster than the arrow keys going one line at a time. At the bottom add the following lines:

interface=wlan0
dhcp-range=10.0.0.2,10.0.0.250,255.255.255.0,12h
address=/#/10.0.0.1

For my file, it looked like everything else was commented out. It is a long file and I didn't look so closely, but if everything else is commented out this shouldn't actually need to be at the bottom of the file. Anyway, the line configures the wlan0 interface and sets the range of IPs that can be given out. In the original tutorial, this is a much smaller range, I expanded this to cover more IPs. The last line is taken from the final tutorial that I followed, which redirects all requests to 10.0.0.1. This is the IP address of the raspberry pi on the wlan0 interface, as set earlier on in the /etc/network/interfaces file, and must match this IP. So now after saving the file, any traffic on the wlan0 network should be redirected to the raspberry pi.

The final tutorial that I followed is also from sirlagz.net, and is linked here: http://sirlagz.net/2013/08/23/how-to-captive-portal-on-the-raspberry-pi/ and talks about setting up the captive portal. The only real change to be made was changing the last line of the dnsmasq.conf file, as done a few lines above.

Now the only remaining thing to do is to install a webserver. The server suggested in the sirlagz tutorial was lighttpd, which I have also used at the moment. To install this, use the following command:

apt-get install lighttpd

Finally I restarted everything for good measure. Now connecting to the wifi network and requesting a page, redirects to the Placeholder Page for lighttpd. Success! The location for my files that are served up by the webserver is:

/var/www/html/

Within this folder, is the location that the files need to go for the webserver.

Update: I had rebooted several times along the way, and thought that the above worked fine, but trying it the next day had problems, and no longer worked correctly. There are a couple of half related issues. Pinging google.com would resolev to my local ip of 10.0.0.1, but pinging 8.8.8.8 for example would fail completely. The problem with pinging ip addresses was related to the gateway not being setup correctly. To see this, enter the command "route -n". Here, to work correctly, there needs to be an entry in the "Desitnation" column with 0.0.0.0, and with your gateway in the "Gateway" column. This wasn't working for me, and so I can use the following command to add the gateway correctly:

sudo route add default gw 192.168.100.1 eth0

Where  my gateway IP is 192.168.100.1, and the interface is eth0. I haven't yet found a way to get this to work automatically. It would be possible to add this to a script without any problems, however I don't know how the gateway could be changed to the correct IP for the network.

The second problem was with DNS lookups. To fix this, I needed to add a couple of lines to the /etc/dnsmasq.conf file. I had thought that the dnsmasq captive portal only applied to the wlan0 interface, but this doesn't appear to be the case, and it overrides traffic from all interfaces. So I made two changes. The line:

address=/#/10.0.0.1

I changed to the following:

address=/pi/10.0.0.1

This now only redirects the domain "pi" to the local server, not all addresses. I also added the following two lines to the end of the file:

server=8.8.8.8
server=8.8.4.4

This uses the Google DNS servers for DNS lookups. After running both of these commands, it should be now possible to ping google.com, and to perform updates etc. So it appears that all the settings apply to both interfaces.

Update 2: After testing on another network, it seems that the problem with the default gateway being added only occurs on one network, that is perhaps configured incorrectly, and it isn't actually a problem with the setup on the raspberry pi. I found this out by reinstalling raspbian again and not following the above steps, and leaving all of the network connection settings as the default. Then it was still not possible to connect to the internet automatically. This is strange as it wasn't previously a problem, and I never used to have the problem where it was necessary to add the gateway. However it seems something in the network has changed, which was unrelated to what I had done, but I had falsely attributed it to the steps I had taken. So the "update" comments can be ignored.


Saturday, 23 January 2016

Code Snippet: Ping local IP addresses


Here is a code snippet that I have created for the purpose of finding a Raspberry Pi when it is connected to a network without a screen. For my setup, I have both an ethernet connection and a WiFi connection. Normally the ethernet connection is connected directly to the raspberry pi, and the WiFi connection goes directly to the router. My code was written and tested on Windows 8.1, with Python 2.7.10. 

from __future__ import print_function
import socket
import os
import time
import subprocess
from threading import Thread

def ping(hostname, timeout=100):

    timeout=str(timeout)

    #perform ping command. -n sets the number (1 here) and -w sets the timeout.
    #creationflag=8 hides the window.
    response = subprocess.Popen(["ping", hostname, "-n", '1', "-w", timeout],
                                stdout=subprocess.PIPE, creationflags=8).stdout.read()
    ping_reply=0

    if "time=" in response.lower() or "time<" in response.lower():
        ping_reply=1

    return ping_reply

def ping_and_print(hostname):

    #perform ping command
    ping_reply=ping(hostname)

    #print whether ip address responded to ping or not.
    #I added the "\n" character to the print command because
    #when multiple threads try to print, it was causing
    #overlapping for some reason. It seems there is a bit of a delay
    #between the string being printed and the end of line
    #character being printed.
    if (ping_reply==1):
        print(hostname + " - UP!\n", end="")
    else:
        if verbose==1:
            print(hostname + " - Down!\n", end="")
    return


verbose=0 #also print out ips that aren't responding to pings.

#this gets the local ip range, the range with the ethernet adapter
local_ip=socket.gethostbyname(socket.gethostname())

#this pings the gmail server and gets the IP address used to connect, so
#should always be the ip address used for internet connections
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("gmail.com",80))
web_facing_ip=s.getsockname()[0]
s.close()

print("Local IP     : " + str(local_ip))
print("Web facing IP: " + str(web_facing_ip))

#check we can actually ping the internet
hostname="8.8.8.8"
ping_reply=ping(hostname,5000)

print("Internet ping: " + str(ping_reply))

#create the network stem for the local ip range
network_stem=".".join(local_ip.split(".")[0:3])

#ping primary ip range
for ip in range(1,255):
    this_ip_address=network_stem + "." + str(ip)

    t = Thread(target=ping_and_print, args=(this_ip_address,))
    t.start()

#create the network stem for the internet connecting ip range
network_stem=".".join(web_facing_ip.split(".")[0:3])

#check we are running on a second network range and not just repeating the
#previous tests.
if local_ip<>web_facing_ip:
    #ping secondary ip range
    for ip in range(1,255):
        this_ip_address=network_stem + "." + str(ip)

        t = Thread(target=ping_and_print, args=(this_ip_address,))
        t.start()

#sleep at the end for a bit to wait for remaining responses.
for i in range(1,100):
    time.sleep(0.01)

print("Done.")