Voltage Measurement through Channels in PSLab

The Pocket Science Lab multimeter has got three channels namely CH1,CH2 and CH3 with different ranges for measuring the voltages.This blog will give a brief description on how we measure voltages in channels.

Measuring Voltages at channels can be divided into three parts:-

        1. Communication between between device and Android.
        2. Setting up analog channel (analog constants)
        3. Voltage measuring function of android.

Communication between PSLab device and Android App

The communication between the PSLab device and  Android occurs through the help of UsbManger package of CommunicationHandler class of the app. The main two functions involved in the communication are read and write functions in which we send particular number of bytes and then we receive certain bytes.

The read function :-

public int read(byte[] dest, int bytesToBeRead, int timeoutMillis) throws IOException {
    int numBytesRead = 0;
    //synchronized (mReadBufferLock) {
    int readNow;
    Log.v(TAG, "TO read : " + bytesToBeRead);
    int bytesToBeReadTemp = bytesToBeRead;
    while (numBytesRead < bytesToBeRead) {
        readNow = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, bytesToBeReadTemp, timeoutMillis);
        if (readNow < 0) {
            Log.e(TAG, "Read Error: " + bytesToBeReadTemp);
            return numBytesRead;
        } else {
            //Log.v(TAG, "Read something" + mReadBuffer);
            System.arraycopy(mReadBuffer, 0, dest, numBytesRead, readNow);
            numBytesRead += readNow;
            bytesToBeReadTemp -= readNow;
            //Log.v(TAG, "READ : " + numBytesRead);
            //Log.v(TAG, "REMAINING: " + bytesToBeRead);
        }
    }
    //}
    Log.v("Bytes Read", "" + numBytesRead);
    return numBytesRead;
}

Similarly the write function is –

public int write(byte[] src, int timeoutMillis) throws IOException {
    if (Build.VERSION.SDK_INT < 18) {
        return writeSupportAPI(src, timeoutMillis);
    }
    int written = 0;
    while (written < src.length) {
        int writeLength, amtWritten;
        //synchronized (mWriteBufferLock) {
        writeLength = Math.min(mWriteBuffer.length, src.length - written);
        // bulk transfer supports offset from API 18
        amtWritten = mConnection.bulkTransfer(mWriteEndpoint, src, written, writeLength, timeoutMillis);
        //}
        if (amtWritten < 0) {
            throw new IOException("Error writing " + writeLength +
                " bytes at offset " + written + " length=" + src.length);
        }
        written += amtWritten;
    }
    return written;
}

Although these are the core functions used for communication but the data received through these functions are further processed using another class known as PacketHandler. In the PacketHandler class also there are two major functions i.e sendByte and getByte(), these are the main functions which are further used in other classes for communication.

The sendByte function:-

public void sendByte(int val) throws IOException {
    if (!connected) {
        throw new IOException("Device not connected");
    }
    if (!loadBurst) {
        try {
            mCommunicationHandler.write(new byte[] {
                (byte)(val & 0xff), (byte)((val >> 8) & 0xff)
            }, timeout);
        } catch (IOException e) {
            Log.e("Error in sending int", e.toString());
            e.printStackTrace();
        }
    } else {
        burstBuffer.put(new byte[] {
            (byte)(val & 0xff), (byte)((val >> 8) & 0xff)
        });
    }
}

As we can see that in this function also the main function used is the write function of communicationHandler but in this class the data is further processed.

Setting Up the Analog Constants

For setting up the ranges, gains and other properties of channels, a different class of AnalogConstants is implemented in the android app, in this class all the properties which are used by the channels are defined which are further used in the sendByte() functions for communication.

public class AnalogConstants {

    public double[] gains = {1, 2, 4, 5, 8, 10, 16, 32, 1 / 11.};
    public String[] allAnalogChannels = {"CH1", "CH2", "CH3", "MIC", "CAP", "SEN", "AN8"};
    public String[] biPolars = {"CH1", "CH2", "CH3", "MIC"};
    public Map<String, double[]> inputRanges = new HashMap<>();
    public Map<String, Integer> picADCMultiplex = new HashMap<>();

    public AnalogConstants() {

        inputRanges.put("CH1", new double[]{16.5, -16.5});
        inputRanges.put("CH2", new double[]{16.5, -16.5});
        inputRanges.put("CH3", new double[]{-3.3, 3.3});
        inputRanges.put("MIC", new double[]{-3.3, 3.3});
        inputRanges.put("CAP", new double[]{0, 3.3});
        inputRanges.put("SEN", new double[]{0, 3.3});
        inputRanges.put("AN8", new double[]{0, 3.3});

        picADCMultiplex.put("CH1", 3);
        picADCMultiplex.put("CH2", 0);
        picADCMultiplex.put("CH3", 1);
        picADCMultiplex.put("MIC", 2);
        picADCMultiplex.put("AN4", 4);
        picADCMultiplex.put("SEN", 7);
        picADCMultiplex.put("CAP", 5);
        picADCMultiplex.put("AN8", 8);

    }
}

Also in the AnalogInput sources class many other properties such as CHOSA( a variable assigned to denote the analog to decimal conversion constant of each channel) are also defined

public AnalogInputSource(String channelName) {
    AnalogConstants analogConstants = new AnalogConstants();
    this.channelName = channelName;
    range = analogConstants.inputRanges.get(channelName);
    gainValues = analogConstants.gains;
    this.CHOSA = analogConstants.picADCMultiplex.get(channelName);
    calPoly10 = new PolynomialFunction(new double[] {
        0.,
        3.3 / 1023,
        0.
    });
    calPoly12 = new PolynomialFunction(new double[] {
        0.,
        3.3 / 4095,
        0.
    });
    if (range[1] - range[0] < 0) {
        inverted = true;
        inversion = -1;
    }
    if (channelName.equals("CH1")) {
        gainEnabled = true;
        gainPGA = 1;
        gain = 0;
    } else if (channelName.equals("CH2")) {
        gainEnabled = true;
        gainPGA = 2;
        gain = 0;
    }
    gain = 0;
    regenerateCalibration();
}

Also in this constructor a polynomial function is also called which further plays an important  role in measuring voltage as it is through this polynomial function we get the voltage of channels in the science lab class , also it is also used in oscilloscope for plotting the graph . So this was the setup of analog channels.

Voltage Measuring Functions

There are two major functions for measuring voltages which are present in the scienceLab class

  • getAverageVoltage
  • getRawableVoltage

Here are the functions

private double getRawAverageVoltage(String channelName) {
    try {
        int chosa = this.calcCHOSA(channelName);
        mPacketHandler.sendByte(mCommandsProto.ADC);
        mPacketHandler.sendByte(mCommandsProto.GET_VOLTAGE_SUMMED);
        mPacketHandler.sendByte(chosa);
        int vSum = mPacketHandler.getVoltageSummation();
        mPacketHandler.getAcknowledgement();
        return vSum / 16.0;
    } catch (IOException | NullPointerException e) {
        e.printStackTrace();
        Log.e(TAG, "Error in getRawAverageVoltage");
    }
    return 0;
}

This is the major function which takes the data from the communicationHandler class via packetHandler. Further this function is used in the getAverageVoltage function.

private double getAverageVoltage(String channelName, Integer sample) {
    if (sample == null) sample = 1;
    PolynomialFunction poly;
    double sum = 0;
    poly = analogInputSources.get(channelName).calPoly12;
    ArrayList < Double > vals = new ArrayList < > ();
    for (int i = 0; i < sample; i++) {
        vals.add(getRawAverageVoltage(channelName));
    }
    for (int j = 0; j < vals.size(); j++) {
        sum = sum + poly.value(vals.get(j));
    }
    return sum / vals.size();
}

This function uses the data from the getRawableVoltage function and uses it the polynomial generated in the analog lasses to calculate the final voltage. Thus this was the core backend of calculating the voltages through channels in PSLab.

Resources:

Continue Reading Voltage Measurement through Channels in PSLab

Using Multimeter in PSLab Android Application

The Pocket Science Lab as we all know is on the verge of development and new features and UI are added almost every day. One such feature is the implementation of multimeter which I have also discussed in my previous blogs.

Figure (1) : Screenshot of the multimeter

But although many functionality of multimeter such as resistance measurement are working perfectly, there are still various bugs in the multimeter. This blog is dedicated to using multimeter in the android app.

Using the multimeter

Figure (2): Screenshot showing guide of multimeter

Figure (2) shows the guide of the multimeter, i.e how basic basic elements such as resistance and voltage are measured using the multimeter. The demonstration of measuring the resistance and voltage are given below.

Measuring the resistance

The resistance is measure by connecting the SEN pin to the positive end of resistor and the GND pin to the negative end of resistor and then clicking the RESISTANCE button.

                   Figure (3) : Demonstration of resistance measurement

Measuring the voltage

To measure the voltage as said in the Guide, directly connect the power source to the the channel pins, although currently only the CH3 pin will show the most accurate results, work is going on other channel improvisation as well.

Figure (4) : Demonstration of Voltage measurement

 

And thus this is how the multimeter is used is used in the android app.  Of course there are still many many features such as capacitance measurements which are yet to be implemented and the work is going on them

Resources:

Continue Reading Using Multimeter in PSLab Android Application

Deploying loklak search on Heroku & Using config to store and load external URLs

It is really important to have a separate configuration for all the hardcoded URLs having multiple instances across the project. It would help in testing and comparing projects like loklak with a separate configuration for hardcoded URLs. We would also be discussing deployment of Angular based loklak on heroku through this blog post.

Creating shared URL config

The idea here is to export a const Object containing all the collective hardcoded URLs used inside the project. We would try to store similar/collective URLs inside a same key e.g. all the github URLs must go inside key: ‘github’.

export const defaultUrlConfig = {
	fossasia: {
		root: 'https://fossasia.org',
		blog: 'https://blog.fossasia.org'
	},
	loklak: {
		apiServer: 'https://api.loklak.org',
		apiBase: 'loklak.org',
		blog: 'http://blog.loklak.net',
		dev: 'https://dev.loklak.org',
		apps: 'https://apps.loklak.org'
	},
	github: {
		loklak: 'https://github.com/loklak',
		fossasia: 'https://github.com/fossasia'
	},
	phimpme: {
		root: 'https://phimp.me'
	},
	susper: {
		root: 'https://susper.com'
	},
	susiChat: {
		root: 'https://chat.susi.ai'
	},
	pslab: {
		root: 'https://pslab.fossasia.org'
	},
	eventyay: {
		root: 'https://eventyay.com'
	}
};

 

Storing URLs with a key instead of storing it inside a simple Array, makes it easier to add a new URL at required place and easy to modify the existing ones. Now, this configuration can easily be called inside any Component file.

Using config inside the component

Now, the work is really simple. We just need to import the configuration file inside the required Component and store/use directly the respective URLs.

First step would be to import the configuration file as follows:

import { defaultUrlConfig } from ‘../shared/url-config’;

 

Note: Respective path for url-config file for different components might differ.

Now, we would need to store the defaultUrlConfig inside a variable.

public configUrl = defaultUrlConfig;

 

At this point, we have all the configuration URLs which could be extracted from configUrl.

Displaying URLs in HTML

We would use Angular’s interpolation binding syntax to display the URLs from configUrl in HTML. Let’s say we want to display FOSSASIA’s github url in HTML, then we would simply need to do:

{{ configUrl.github.fossasia }}

 

This could be used as an example to to replace all the hardcoded URLs inside the project.

Deploying loklak search on Heroku

Note: I am skipping the initial steps of creating a project on heroku. It is very easy to setup a project on heroku, for initial steps please follow up here.

First step in this direction would be to add a server.js file in root directory and add the following express server code in it:

const express = require(‘express’);
const path = require(‘path’);
const app = express();
app.use(express.static(__dirname + ‘/dist/<name-of-app>’));
app.get(‘/*’, function(req,res) {
res.sendFile(path.join(__dirname+‘/dist/<name-of-app>/index.html’));
});
app.listen(process.env.PORT || 8080);

 

Second step would be to add the following commands inside package.json at respective attributes.

“postinstall”: “ng build –aot -prod”
“start”: “node server.js”

 

Testing

Click on the respective URL link inside the project UI to test the configuration for hardcoded URLs. To check the deployment on heroku, please open the following URLs:

Development branch: loklak-search-dev.herokuapp.com

Master branch: loklak-search.herokuapp.com

Resources

Continue Reading Deploying loklak search on Heroku & Using config to store and load external URLs

Implement Sensor Data Fetching Using AsyncTask

In PSLab android app we have implemented sensor data fetching of various sensors inbuilt in the mobile device like light sensor, accelerometer, gyrometer. We can use PSLab to log the data and show in the form of the graph or maybe export the data in the form of CSV format for future use.

But recording data from the phone sensor imposes a serious problem in the performance of the Android app as it is a costly to process in terms of memory, resources and time. In CS terms there is too much work that has to be done on the single main thread which sometimes leads to lag and compromises the UX.

So as a solution we applied a concept of the Multithreading provided by Java in which we can shift the heavy process to a separate background thread so that the main thread never gets interrupted during fetching the sensor data and the background thread handles all the fetching and updates the UI as soon as it gets the data, till then the Main thread continues to serves the user so to user the application remains always responsive.

For implementing this we used a special class provided by Android Framework called AsyncTask. Which provides below methods:-

  • doInBackground() : This method contains the code which needs to be executed in the background. In this method, we can send results multiple times to the UI thread by publishProgress() method.

  • onPreExecute() : This method contains the code which is executed before the background processing starts.

  • onPostExecute() : This method is called after doInBackground method completes processing. Result from doInBackground is passed to this method.

  • onProgressUpdate() : This method receives progress updates from doInBackground() method, which is published via publishProgress() method, and this method can use this progress update to update the UI thread.

  • onCancelled(): This method is called when the background task has been canceled. Here we can free up resources or write some cleanup code to avoid memory leaks.

We created a class SensorDataFetch and extended this AsyncTask class and override its methods according to our needs.

private class SensorDataFetch extends AsyncTask<Void, Void, Void> implements SensorEventListener {

   private float data;
   private long timeElapsed;

   @Override
   protected Void doInBackground(Void... params) {
      
       sensorManager.registerListener(this, sensor, updatePeriod);
       return null;
   }

   protected void onPostExecute(Void aVoid) {
       super.onPostExecute(aVoid);
       visualizeData();
   }

   @Override
   protected void onPreExecute() {
 super.onPreExecute();
   //do nothing
   }

   @Override
   protected void onProgressUpdate(Void... values) {
       super.onProgressUpdate(values);
          //do nothing
   }

   @Override
   protected void onCancelled() {
       super.onCancelled();
          //do nothing
   }

In doInBackground() method we implemented the fetching raw data from the sensor by registering the listener and in onPostExecute() method we updated that data on the UI to be viewed by the user.

When this process is being run in the background thread the Main UI thread is free and remains responsive to the user. We can see in Figure 1 below that the UI is responsive to the user swipe action even when the sensor data is updating continuously on the screen.

Figure 1 shows Lux Meter responding to user swipe while fetching sensor data flawlessly.

 

Resources

https://developer.android.com/reference/android/os/AsyncTask – Android Developer documentation for Async Task class.

Continue Reading Implement Sensor Data Fetching Using AsyncTask

Snackbar Implementation in PSLab Android App

In PSLab android app we have developed the functionality of logging sensor data in CSV format. We can start and stop the data recording using the save button in the upper right corner of the menu bar and toast message was shown to notify the user for logging status whether it is started or stopped but it leads to some problem like:-

  • The user doesn’t know where the logged file has been created in the external storage.
  • If the user accidentally clicked on the save button the data logging will start the user have to manually go the storage location and delete the recently created unwanted CSV file.

What’s the solution?

The solution to both these problem is solved by implementing Snackbar instead of Toast message.

According to Material Design documentation:-

The Snackbar widget provides brief feedback about an operation through a message at the bottom of the screen. Snackbar disappears automatically, either after a timeout or after a user interaction elsewhere on the screen, and can also be swiped off the screen.

Snackbar can also offer the ability to perform an action, such as undoing an action that was just taken or retrying an action that had failed.

 

Figure 1 shows a Snackbar sample
(Source: – https://material.io/develop/android/components/snackbar/ )

 

To implement the Snackbar in our Android app I started by creating a custom snack bar class which contains all the code to create and show the Snackbar on the screen.

public class CustomSnackBar {

   public static void showSnackBar(@NonNull CoordinatorLayout holderLayout,  
                                   @NonNull String displayText,
                                   String actionText, 
                                   View.OnClickListener clickListener){
       
   Snackbar snackbar =     
              Snackbar.make(holderLayout,displayText,Snackbar.LENGTH_LONG)
              .setAction(actionText, clickListener);

  //do your customization here
}

The custom class contains a static method ‘showSnackBar()’ having parameters:

Parameter Return Type Description
holderLayout CoordinatorLayout Container layout in which the snack bar will be shown at the bottom (should not be null)
displayText String Text to be displayed in the content of Snackbar (should not be null)
actionText String Clickable text which has some action associated with it
clickListener View.OnClickListener On click listener specifying an action to be performed when actionText is clicked

 

Inside the method, I called the static make()  method provided by the Snackbar class and passed holderlayout, displayText and duration of Snackbar in this case Snackbar.LENGTH_LONG as parameters.

Then I called setAction() and passed in the actionText and the clickListener as parameters in it to set the action text. If we pass in null no action text will be generated.

Then, if we want to changes the action text color we can do that by calling setActionTextColor() and passing in the desired color.

snackbar.setActionTextColor(ContextCompat.getColor(holderLayout.getContext(), R.color.colorPrimary));

And if we want to change the content text color then we need to first get the view then we need to get the instance of TextView containing the content text using findViewById() and passing android.support.design.R.id.snackbar_text which is default ID for context TextView, and then call setTextColor() to set the desired color.

View sbView = snackbar.getView();
   TextView textView =     
             sbView.findViewById(android.support.design.R.id.snackbar_text);
       textView.setTextColor(Color.WHITE);
   }

So, now our Snackbar engine is complete now we need to call CustomSnackBar class static method showSnackbar() in our sensor data logger.

For doing this I replaced all the instances of the Toast message with the ‘CustomSnackBar’ by passing in the desired messages that were being passed in Toast message.

But I still need to find the location of our stored CSV file and a method to delete the current generated CSV file.

For that, I did below modification to the CSVLogger class in PSLab android app.

public class CSVLogger {
   private static final String CSV_DIRECTORY = "PSLab";
   public CSVLogger(String category) {
       this.category = category;
       setupPath();
   }
   /*Below methods are included at the bottom of the class */
   public String getCurrentFilePath() {
       return Environment.getExternalStorageDirectory().getAbsolutePath() +
               File.separator + CSV_DIRECTORY + File.separator + category;
   }
   public void deleteFile() {
       csvFile.delete();
   }
}

Now for passing the location of the stored file and implementing delete option, I called the below method when the CSV logging is stopped by the user:

CustomSnackBar.showSnackBar((CoordinatorLayout) parent.findViewById(R.id.cl),

                    “CSV File stored at” + " " +lux_logger.getCurrentFilePath(),
  
                    “DELETE”,

                    new View.OnClickListener() {
                              Override
                              public void onClick(View view) {
                                             lux_logger.deleteFile();    
                              });

By doing this I get a Snackbar as shown in Figure 2, clicking on the “DELETE” text deletes the current CSV file.

Figure 2 shows snackbar showing file stored location and delete option

 

So, implementing Snackbar helped to make the app interactive and keeps user notified and control the data logging.

Resources

  1. https://www.journaldev.com/10324/android-snackbar-example-tutorial – Android SnackBar example implemetation tutorial
  2. https://material.io/develop/android/components/snackbar/ – Android Material Desing implementation of Snackbar.

Continue Reading Snackbar Implementation in PSLab Android App

Creating step designs from KiCAD for PSLab

PSLab hardware device is developed using KiCAD. It is an open source PCB designing tool which we can use for free and it has almost all the features needed to build a professional PCB. But it lacks one thing. It cannot generate and export 3D models. In fact there is a 3D viewer in KiCAD but there is no way to export it. When manufacturing PSLab devices, it was required by the manufacturers so that they can have a clear understanding how the components are placed. This step is necessary for them to design the production line.

Before we get started, there are few prerequisites to help us get this done. They are as follows;

  1. FreeCAD: Open source 3D modeling software
  2. KiCAD step up tools: External library to import KiCAD PCB layouts to FreeCAD

You may need to follow installation instructions to install FreeCAD from the link given. Once we are all set, extract the KiCAD Stepup tools. There we can find a set of python libraries and some bash scripts. We can either use the scripts or type commands ourselves. I found scripts having some issues configuring paths.

To fire up FreeCAD with KiCAD stepup tools enabled, type the following command on your console;

$ freecad kicad-StepUp-tools.FCMacro

Make sure the console is pointing to the directory where the FCMacro file is located. This will open up FreeCAD and if you opened it already and saw the opening screen of FreeCAD, you’d notice a whole new toolbar is added.

Here you can see many tools related to import and export step files and 3D models from outside libraries and folders. Each tool is specific;

  • Load-kicad-footprint:

This tool is useful to generate a step file for an individual PCB component, say a resistor into a step file.

  • Export-to-kicad:

There are instances where when we design a custom foot print, and KiCAD doesn’t have the 3D model. In such a case we can export such a model to KiCAD

  • Load-kicad:

This is the tool we are using to export PSLab PCB board to step format. Before we move on to this tool there is one last configuration we have to do. FreeCAD doesn’t know where we have put KiCAD 3D models. This library simply transforms the available 3D models in KiCAD into step files and build the final output combining all of them together as in the featured image of this blog post. To setup the 3D model path, in KiCAD, there is a path configuration option. Copy the path under “KISYS3DMOD”.

Figure 2: Path Configuration dialog box in KiCAD

And paste it into the ini file named “ksu-config.ini” which you can find in home folder.

Figure 3: Place to add 3D model path in ksu-config.ini file

Once that is done, click on the Load-KiCAD tool icon and browse to the repository where the PSLab hardware files are located at. Open the board file and FreeCAD will generate part by part and finally output the complete design. Now we can export the design in plenty of formats such as steps, stl another similar file format and many more.

Reference:

  1. https://www.freecadweb.org/wiki/Download
  2. http://kicad-pcb.org/external-tools/stepup/

Continue Reading Creating step designs from KiCAD for PSLab

Use Travis to extract testing APKs for PSLab

Travis CI is a popular continuous integration tool built to test software and deployments done at GitHub repositories. They provide free plans to open source projects. PSLab Android is using Travis to ensure that all the pull requests made and the merges are build-bug frees. Travis can do this pretty well, but that is not all it can do. It’s a powerful tool and we can think of it as a virtual machine (with high specs) installed in a server for us to utilize efficiently.

There was a need in PSLab development that, if we want to test the functionalities of code at a branch. To fulfil this need, one has to download the branch to his local machine and use gradle to build a new apk. This is a tedious task, not to mention reviewers, even developers wouldn’t like to do this.

If the apk files were generated and in a branch, we can simply download them using a console command.

$ wget https://raw.github.com/fossasia/<repository>/<branch>/<file with extension>

 

With the help of Travis integration, we can create a simple script to generate these apks for us. This is done as follows;

Once the Travis build is complete for a triggering event such as a pull request, it will run it’s “after_success” block. We are going to execute a script at this point. Simply add the following code snippet.

after_success:
  - 'if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then bash <script-name>.sh; fi'

 

This will run the script you have mentioned using bash. Here we will have the following code snippets in the specified bash script.

First of all we have to define the branch we want to build. This can be done using a variable assignment.

export DEVELOPMENT_BRANCH=${DEVELOPMENT_BRANCH:-development}

 

Once the build is complete, there will be new folders in the virtual machine. One of them is the app folder. Inside this folder contains the build folder where all the apk files are generated. So the next step is to copy these apk files to a place of our preference. I am using a folder named apk to make it much sense.

cd apk
\cp -r ../app/build/outputs/apk/*/**.apk .
\cp -r ../app/build/outputs/apk/debug/output.json debug-output.json
\cp -r ../app/build/outputs/apk/release/output.json release-output.json
\cp -r ../README.md .

 

Usually, the build folder has following apk files

  • app-debug.apk
  • app-release-unsigned.apk
  • app-release.apk

Release apks are usually signed with a key and it would cause issues while installation. So we have to filter out the debug apk that we usually use for debugging and get it as the output apk. This involves simple file handling operations in Linux and a bit of git.

First of all, rename the apk file so that it will be different from other files.

# Rename apks with dev prefixes
mv app-debug.apk app-dev-debug.apk

 

Then add and commit them to a specific branch where we want the output from.

git add -A
git commit -am "Travis build pushed [development]"
git push origin apk --force --quiet> /dev/null

 

Once it is all done, you will have a branch created and updated with the apk files you have defined.

 

Figure 1: UI of pslab-android apk branch

Reference:

  1. https://travis-ci.org/

Continue Reading Use Travis to extract testing APKs for PSLab

I2C communication in PSLab Android

PSLab device is a compact electronic device with a variety of features. One of them is the ability to integrate sensors and get readings from them. One might think that why they should use PSLab device to get sensor readings and they can use some other hardware like Arduino. In those devices, user has to create firmware and need to know how to interface them with correct sampling rates and settings. But with PSLab, they all come in the whole package. User just have to plug the device to his phone and the sensor to device and he’s ready.

The idea of this blog post is to show how this sophisticated process is actually happening. Before that, let me give you a basic introduction on how I2C communication protocol works. I2C protocol is superior to UART and SPI protocols as they are device limited or requires many wires. But with I2C, you can literally connect thousands of sensors with just 4 wires. These wires are labeled as follows;

  • VCC – Power line
  • GND – Ground line
  • SDA – Data line
  • SCL – Signal clock

It is required that the SDA and SCL lines need to be connected to VCC line using two pull up resistors. But that’s just hardware. Let’s move on to learn how I2C communicate.

Here there is this communicating concept called master and slave. To start communication, master issues a global signal like a broadcast to all the devices connected to SCL and SDA lines. This signal contains the address of the slave, master needs to address and get data from. If the slave received this call to him, he will pull down the SDA line to signal the master that he heard him and ready to communicate with him. Here communication means reading or writing data. Then the communication happens and the link between master and slave breaks giving opportunity to other masters and slaves.

One might think this is a slow process. But these signals are transmitted at high frequencies. In PSLab it is at 100 kHz and that is one millisecond.

PSLab library has a special class to handle I2C communication. That is

public class I2C {/**/}

 

Once this class is initiated, one has to call the start function to start communication. This method requires the address we wish to communicate with and the mode of operation stating if it is a read or write operation

public int start(int address, int rw) throws IOException {
   packetHandler.sendByte(commandsProto.I2C_HEADER);
   packetHandler.sendByte(commandsProto.I2C_START);
   packetHandler.sendByte((address << 1) | rw & 0xff);
   return (packetHandler.getAcknowledgement() >> 4);
}

 

Once the address is sent out, protocol requires us to stop and wait for acknowledgement.

public void wait() throws IOException {
   packetHandler.sendByte(commandsProto.I2C_HEADER);
   packetHandler.sendByte(commandsProto.I2C_WAIT);
   packetHandler.getAcknowledgement();
}

 

If there are no congestion in the lines such as reading from multiple devices, the acknowledgement will be instantaneous. Once that is complete, we can start communication either byte-wise or bulk-wise

public int send(int data) throws IOException {
   packetHandler.sendByte(commandsProto.I2C_HEADER);
   packetHandler.sendByte(commandsProto.I2C_SEND);
   packetHandler.sendByte(data);
   return (packetHandler.getAcknowledgement() >> 4);
}

 

As an example, reading sensor values at a given interval can be done using the following method call.

public ArrayList<Byte> read(int length) throws IOException {
   ArrayList<Byte> data = new ArrayList<>();
   for (int i = 0; i < length - 1; i++) {
       packetHandler.sendByte(commandsProto.I2C_HEADER);
       packetHandler.sendByte(commandsProto.I2C_READ_MORE);
       data.add(packetHandler.getByte());
       packetHandler.getAcknowledgement();
   }
   packetHandler.sendByte(commandsProto.I2C_HEADER);
   packetHandler.sendByte(commandsProto.I2C_READ_END);
   data.add(packetHandler.getByte());
   packetHandler.getAcknowledgement();
   return data;
}

 

Once we get the data bundle, either we can save them or display in a graph whatever the way it’s convenient.

Reference:

  1. https://en.wikipedia.org/wiki/I%C2%B2C

Continue Reading I2C communication in PSLab Android

Adding Data Point Markers to OSM

PSLab Android app supports multiple sensors external and internal. Users can view sensor readings and record them into a csv file for later use. They can also have their location embedded into the data set they are recording. Saving the location related to each sensor reading is important. Say in a school experiment teacher can ask the student to measure dust particle concentration in city and inside his house. If the data set didn’t have any reference to the location where it was recorded, it is just incomplete. To facilitate this feature, we have enabled location in data recordings.

Enabling location is just not enough. User should be able to view the locations. Probably on a map itself would be a good idea. With the use of Open Street Maps, we can add markers to specific locations. These markers can be used as a point to show on map where a specific data set had been recorded by the user. This can be implemented further to add additional features such as standardized labels to view which data set is at which location etc.

Figure 1: Markers on Map

Unlike Google Maps API, in Open Street Maps there is no direct implementation to add a marker. But it is not a hard implementation either. We can simply create a class extending map overlays and use that as a base to add markers.

We can start by creating a new class that extends ItemizedOverlay<OverlayItem> class as follows. In this class, it would be wise to have an array list full of markers we are using in the map to modularize the whole markers related tasks into this one class rather than implementing in every place where map is used.

public class MapOverlay extends ItemizedOverlay<OverlayItem> {

    private ArrayList<OverlayItem> overlayItemList = new   ArrayList<OverlayItem>();

}

 

Once the class is initiated, have the following methods implemented. The following method will add markers to the array list we have created at the beginning.

public void addItem(GeoPoint p, String title, String snippet){
  OverlayItem newItem = new OverlayItem(title, snippet, p);
  overlayItemList.add(newItem);
  populate(); 
}

 

This method will be used to handle focusing events related to map markers.

@Override
public boolean onSnapToItem(int arg0, int arg1, Point arg2, IMapView arg3){
  return false;
}

 

Following method is used by the map itself to generate markers from the marker list.

@Override
protected OverlayItem createItem(int arg0) {
  return overlayItemList.get(arg0);
}

 

This method is an overriden method we will have to include in the class body.

@Override
public int size() {
  return overlayItemList.size();
}

 

Once the overlay class is completed, we can move on to actual implementation of a map on Openstreetmap view.

From the main activity where the map is viewed, initiate the marker overlay class and pass the drawable that needs to be shown as the marker to the class constructor as follows:

MapOverlay mapoverlay = null;
Drawable marker=getResources().getDrawable(android.R.drawable.map_hand);
int markerWidth = marker.getIntrinsicWidth();
int markerHeight = marker.getIntrinsicHeight();
marker.setBounds(0, markerHeight, markerWidth, 0);

ResourceProxy resourceProxy = new DefaultResourceProxyImpl(getApplicationContext());
mapoverlay = new MapOverlay(marker, resourceProxy);
mapView.getOverlays().add(mapoverlay);
         
GeoPoint point = new GeoPoint(55.75, 37.616667);
mapoverlay.addItem(point, "Russia", "Russia");

 

We can add as many GeoPoints as we want to markers list and they all will be displayed on the map like this;

Figure 2: Final Output of Markers

Reference:

http://android-coding.blogspot.com/2012/06/example-of-implementing-openstreetmap.html

Continue Reading Adding Data Point Markers to OSM

Adding Open Street Maps to PSLab Android

PSLab Android app is an open source app that uses fully open libraries and tools so that the community can use all it’s features without any compromises related to pricing or feature constraints. This will brings us to the topic how to implement a map feature in PSLab Android app without using proprietary tools and libraries. This is really important as now the app is available on Fdroid and they don’t allow apps to have proprietary tools in them if they are published there. In other words, it simply says we cannot use Google Maps APIs no matter how powerful they are in usage.

There is a workaround and that is using Open Street Maps (OSM). OSM is an open source project which is supported by a number of developers all around the globe to develop an open source alternative to Google Maps. It supports plenty of features we need in PSLab Android app as well. Starting from displaying a high resolution map along with caching the places user has viewed, we can add markers to show data points and locations in sensor data logging implementations.

All these features can be made available once we add the following dependencies in gradle build file. Make sure to use the latest version as there will be improvements and bug fixes in each newer version

implementation "org.osmdroid:osmdroid-android:$rootProject.osmVersion"
implementation "org.osmdroid:osmdroid-mapsforge:$rootProject.mapsforgeVersion"
implementation "org.osmdroid:osmdroid-geopackage:$rootProject.geoPackageVersion"

 

OSM will be functional only after the following permission states were granted.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"  />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

 

In a view xml file, add the layout org.osmdroid.views.MapView to initiate the map view. There is a known issue in OSM library. That is during the initiation, if the zoom factor is set to a small value, there will be multiple instances of maps as shown in Fig 1. The solution is to have a higher zoom value when the map is loaded.

Figure 1: Multiple map tiles in OSM

Once we initialize the map view inside an activity, a zoom level can be easily set using a map controller as follows;

map = findViewById(R.id.osmmap);
map.setTileSource(TileSourceFactory.MAPNIK);
map.setBuiltInZoomControls(true);
map.setMultiTouchControls(true);

IMapController mapController = map.getController();
mapController.setZoom((double) 9);
GeoPoint startPoint = new GeoPoint(0.00, 0.00);
mapController.setCenter(startPoint);

 

After successfully implementing the map view, we can develop the business logic to add markers and descriptions to improve the usability of OS Maps. They will be available in the upcoming blog posts.

Reference:

  1. https://github.com/osmdroid/osmdroid/wiki/How-to-add-the-osmdroid-library-via-Gradle
  2. https://www.openstreetmap.org/

Continue Reading Adding Open Street Maps to PSLab Android