com.mchp.android.PIC32_BTSK.TemperatureFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.mchp.android.PIC32_BTSK.TemperatureFragment.java

Source

/*
 * Bluetooth Starter Kit Android app. For use with the Microchip Bluetooth 
 * Starter Kit DM320018
 *
 * Copyright (C) 2014  Microchip Technology Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.mchp.android.PIC32_BTSK;

import java.util.ArrayList;
import java.util.LinkedList;

import com.jjoe64.graphview.*;
import com.jjoe64.graphview.GraphView.GraphViewData;
import com.mchp.android.PIC32_BTSK.R;

import android.support.v4.app.Fragment;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;

/*
 * This is the Temperature fragment. It has a graph with recently received temperature values, an interface to 
 * start/stop temperature updates, and an interface to select and send an update rate.
 */
public class TemperatureFragment extends Fragment implements SeekBar.OnSeekBarChangeListener {

    // Constants
    static String timerCmd = "252"; // Command to set the temperature update rate
    static String enableCmd = "253"; // Command to start/stop temperature updates
    static int timerDefault = 1000; // Default update rate, in ms

    // Frequency spec table, used to define possible update rates settable by the slider bar. 
    // Each row in the table defines a range of values. Given {min,max,incr}, the range would be from 
    // min to max with increments of incr.
    // With this table, the following values are possible:
    // 250, 255, 260, ..., 490, 495ms
    // 500, 525, 550, ..., 950, 975ms
    // 1000, 2000, ..., 7000, 8000ms
    static int[][] freqSpec = {
            // min,  max, incr
            { 250, 500, 5 }, { 500, 1000, 25 }, { 1000, 8000, 1000 }, };

    static int tempMin = 60; // Minimum temperature shown on graph's y-axis
    static int tempMax = 100; // Maximum temperature shown on graph's y-axis
    static int tempInterval = 5; // Interval between ticks on graph's y-axis    

    // UI elements
    // Graph and text to show recently received temperature values
    private TextView mLastTemp;
    private GraphView graphView;
    private GraphViewSeries graphViewSeries;
    private GraphViewData graphViewData[];
    private GraphViewStyle graphViewStyle;
    private int tickSize = tempInterval;
    private int minY = tempMin;
    private int maxY = tempMax;

    // Interface for sending start/stop command
    private Button mStart;

    // Interface for selecting and sending update rate command
    private Button mFrequency;
    private SeekBar mSeekBarFreq;
    private TextView mProgressTextFreq;
    private Button mUpFreq;
    private Button mDownFreq;

    int mFreq = timerDefault;
    int mSeekBarValue;

    ArrayList<Integer> freqValues;

    // Callback functions
    // These callbacks allow a fragment to call a function defined in its parent Activity.

    // This callback allows this fragment to send a string over Bluetooth, using its parent Activity's Bluetooth 
    // connection. This is used to send the start/stop or timer update commands over Bluetooth, when the 
    // user presses the respective buttons.
    public interface OnSendRequestListener {
        public void onSendRequest(String s);
    }

    OnSendRequestListener mSendRequestCallback;

    // This callback allows this fragment to get the temperature log, which is stored by its parent Activity. This 
    // is used to get the temperature log when the fragment is created.
    public interface OnTempRequestListener {
        public LinkedList<Integer> onTempRequest();
    }

    OnTempRequestListener mTempRequestCallback;

    // Action callbacks
    // These callbacks happen when the user interacts with the UI elements

    // Called when the user changes the seekbar. Gets the new frequency from the seekbar, and updates
    // the other UI elements with the new frequency.
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
        mSeekBarValue = seekBar.getProgress();
        mFreq = freqValues.get(mSeekBarValue);
        mProgressTextFreq.setText(mFreq + " ms");
    }

    // Called when the user starts changing the seekbar
    public void onStartTrackingTouch(SeekBar seekBar) {
    }

    // Called when the user stops changing the seekbar
    public void onStopTrackingTouch(SeekBar seekBar) {
    }

    // Lifecycle callbacks
    // These are called by the system when starting, closing, or navigating through the app

    // Called when this fragment is attached to its container activity (when its tab is selected)
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This checks that the container activity (BluetoothChat) has implemented
        // the OnSendRequestListener interface. If not, it throws an exception. If it
        // has been implemented, sets mSendRequestCallback to the implementation in the
        // container activity.
        try {
            mSendRequestCallback = (OnSendRequestListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnSendRequestListener");
        }

        // This checks that the container activity (BluetoothChat) has implemented
        // the OnTempRequestListener interface. If not, it throws an exception.  If it
        // has been implemented, sets mTempRequestCallback to the implementation in the
        // container activity.
        try {
            mTempRequestCallback = (OnTempRequestListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnTempRequestListener");
        }

        return;
    }

    // Called when this fragment is created
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        createFreqValues();
    }

    // Called when this fragment View is created. Performs setup of the UI.
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        super.onCreateView(inflater, container, savedInstanceState);

        // Inflate the layout for this fragment
        ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_temperature, container, false);

        // Get each UI object from the layout
        mLastTemp = (TextView) rootView.findViewById(R.id.last_temp);
        mStart = (Button) rootView.findViewById(R.id.temp_start);
        mFrequency = (Button) rootView.findViewById(R.id.temp_freq);
        mSeekBarFreq = (SeekBar) rootView.findViewById(R.id.seek_freq);
        mProgressTextFreq = (TextView) rootView.findViewById(R.id.progress_freq);
        mDownFreq = (Button) rootView.findViewById(R.id.freq_down);
        mUpFreq = (Button) rootView.findViewById(R.id.freq_up);

        // Initialize the states of the UI objects
        mSeekBarFreq.setMax(freqValues.size() - 1);
        mSeekBarFreq.setProgress(freqValues.indexOf(mFreq));

        mLastTemp.setTextSize(100.0f);
        mLastTemp.setText("--\u00b0");
        mStart.setText("Start/Stop");
        mFrequency.setText("Set Timer");
        mProgressTextFreq.setText(mFreq + " ms");
        mDownFreq.setText("-");
        mUpFreq.setText("+");

        // Set listeners for the UI objects
        mSeekBarFreq.setOnSeekBarChangeListener(this);

        // Define a click listener for the start/stop button. When clicked, it sends the start/stop command.
        mStart.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mSendRequestCallback.onSendRequest(enableCmd);
            }
        });

        // Define a click listener for the timer button. When clicked, it sends the timer command with the current 
        // frequency.
        mFrequency.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mSendRequestCallback.onSendRequest(timerCmd + "," + mFreq);
            }
        });

        // Define click listeners for the fine tune buttons. When clicked, they update the current frequency and 
        // update other UI elements with the new frequency.
        mDownFreq.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mSeekBarValue = mSeekBarFreq.getProgress();
                mSeekBarValue--;
                mSeekBarFreq.setProgress(mSeekBarValue);
            }
        });
        mUpFreq.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                mSeekBarValue = mSeekBarFreq.getProgress();
                mSeekBarValue++;
                mSeekBarFreq.setProgress(mSeekBarValue);
            }
        });

        // Set up the graph
        // Create a new bar graph
        graphView = new BarGraphView(this.getActivity().getApplicationContext(), "");

        // Set the graph data to the values in the temperature log
        graphViewData = new GraphViewData[PIC32_BTSK.numTemperatures];
        setGraphViewData(mTempRequestCallback.onTempRequest());

        // Add the graph data to the graph.
        graphViewSeries = new GraphViewSeries(graphViewData);
        graphView.addSeries(graphViewSeries);

        // Setup the graph axis ranges, zoom and scroll
        graphView.setManualYAxisBounds(maxY, minY);
        graphView.setScalable(true);
        graphView.setScrollable(true);
        graphView.setViewPort(2, 40);

        // Setup the graph axes labels
        graphViewStyle = new GraphViewStyle();
        graphViewStyle.setHorizontalLabelsColor(0);
        graphViewStyle.setNumHorizontalLabels(2);
        graphViewStyle.setNumVerticalLabels(1 + (maxY - minY) / tickSize);
        graphView.setGraphViewStyle(graphViewStyle);

        // Add the graph to the layout
        LinearLayout g = (LinearLayout) rootView.findViewById(R.id.temp_graph);
        g.addView(graphView);

        graphView.scrollToEnd();

        // Return the layout for this fragment
        return rootView;
    }

    // Called when returning to this fragment (when its tab is reselected). Restores the state of UI objects.
    @Override
    public void onViewStateRestored(Bundle savedInstanceState) {
        super.onViewStateRestored(savedInstanceState);

        Double d = graphViewData[graphViewData.length - 1].getY();
        mLastTemp.setText(String.valueOf(d.intValue()) + "\u00b0");

        return;
    }

    // Looks for the string "253,<int>" where <int> is a temperature value. If there is a match,
    // updates the temperature log with the temperature value.
    public static void parseTemperature(String s, LinkedList<Integer> l) {
        int i;
        s = s.trim();
        String splitS[] = s.split(",", 2);
        if (splitS.length != 2) {
            return;
        }
        if (!splitS[0].contentEquals(enableCmd)) {
            return;
        }
        try {
            i = Integer.parseInt(splitS[1]);
        } catch (NumberFormatException e) {
            return;
        }
        l.add(i);
        l.remove();

        return;
    }

    // Initializes the temperature log with all 0s.
    public static void initTemperatureList(LinkedList<Integer> l, int size) {
        int i;
        for (i = 0; i < size; i++) {
            l.add(0);
        }
    }

    // Sets the graph data to the values in the temperature log.
    void setGraphViewData(LinkedList<Integer> l) {
        int i;
        for (i = 0; i < l.size(); i++) {
            graphViewData[i] = new GraphViewData(i, l.get(i));
        }
    }

    // Updates the graph with the temperature log.
    public void updateGraph(LinkedList<Integer> l) {
        setGraphViewData(l);
        graphViewSeries.resetData(graphViewData);
        graphViewSeries.removeGraphView(graphView);
        graphViewSeries.addGraphView(graphView);

        graphView.scrollToEnd();
        mLastTemp.setText(l.getLast().toString() + "\u00b0");
    }

    // Create the frequency values from the frequency spec table.
    void createFreqValues() {
        int start, end, incr;
        int i, j, count;
        int total = 0;
        count = 0;
        j = 0;
        for (i = 0; i < freqSpec.length; i++) {
            total = total + (freqSpec[i][1] - freqSpec[i][0]) / freqSpec[i][2];
        }
        total++;
        freqValues = new ArrayList<Integer>();

        for (i = 0; i < freqSpec.length; i++) {
            start = freqSpec[i][0];
            end = freqSpec[i][1];
            incr = freqSpec[i][2];
            for (j = start; j < end; j += incr) {
                freqValues.add(j);
                Log.d(PIC32_BTSK.TAG, "" + freqValues.get(count));
                count++;
            }
        }
        freqValues.add(j);
        Log.d(PIC32_BTSK.TAG, "" + freqValues.get(count));

        return;
    }
}