/**
* Copyright (c) 2011-2014, OpenIoT
*
* This file is part of OpenIoT.
*
* OpenIoT is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* OpenIoT 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OpenIoT. If not, see <http://www.gnu.org/licenses/>.
*
* Contact: OpenIoT mailto: info@openiot.eu
* @author Sofiane Sarni
*/
package org.openiot.gsn.wrappers.tinyos;
import org.openiot.gsn.beans.DataField;
import org.openiot.gsn.beans.StreamElement;
import org.openiot.gsn.utils.Formatter;
import org.openiot.gsn.utils.Helpers;
import org.openiot.gsn.utils.UnsignedByte;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import java.io.*;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.DecimalFormat;
import java.util.*;
public class SensorScopeServerListener {
private static transient Logger logger = Logger.getLogger(SensorScopeServerListener.class);
private static final String PASSKEY = "FD83EC5EA68E2A5B";
private static final int TX_BUFFER_SIZE = 10;
private static final int RX_BUFFER_SIZE = 100000;
public static final String CONF_LOG4J_SENSORSCOPE_PROPERTIES = "conf/log4j_sensorscope.properties";
private static final String DEFAULT_PACKETS_LOGFILE = "logs/packets.txt";
private static final int PLUS_SIGN = 43;
private static final int MAX_DUPN = 15; // maximum DUPN value = maximum number of extended sensors supported -1
private static final int OFFSET_AIR_TEMP = 5 + (MAX_DUPN + 1) * 0;
private static final int OFFSET_AIR_HUMID = 5 + (MAX_DUPN + 1) * 1;
private static final int OFFSET_SOLAR_RAD = 5 + (MAX_DUPN + 1) * 2;
private static final int OFFSET_RAIN_METER = 5 + (MAX_DUPN + 1) * 3;
private static final int OFFSET_GROUND_TEMP_TNX = 5 + (MAX_DUPN + 1) * 4;
private static final int OFFSET_AIR_TEMP_TNX = 5 + (MAX_DUPN + 1) * 5;
private static final int OFFSET_SOIL_TEMP_ECTM = 5 + (MAX_DUPN + 1) * 6;
private static final int OFFSET_SOIL_MOISTURE_ECTM = 5 + (MAX_DUPN + 1) * 7;
private static final int OFFSET_SOIL_WATER_POTENTIAL = 5 + (MAX_DUPN + 1) * 8;
private static final int OFFSET_SOIL_TEMP_DECAGON = 5 + (MAX_DUPN + 1) * 9;
private static final int OFFSET_SOIL_MOISTURE_DECAGON = 5 + (MAX_DUPN + 1) * 10;
private static final int OFFSET_SOIL_CONDUCT_DECAGON = 5 + (MAX_DUPN + 1) * 11;
private static final int OFFSET_WIND_DIRECTION = 5 + (MAX_DUPN + 1) * 12;
private static final int OFFSET_WIND_SPEED = 5 + (MAX_DUPN + 1) * 13;
private static final int OFFSET_BATTERY_BOARD_VOLTAGE = 5 + (MAX_DUPN + 1) * 14;
private static final int OFFSET_SOLAR_RAD_SP212 = 5 + (MAX_DUPN + 1) * 15;
private static final int OFFSET_DECAGON_10HS_MV = 5 + (MAX_DUPN + 1) * 16;
private static final int OFFSET_DECAGON_10HS_VWC = 5 + (MAX_DUPN + 1) * 17;
private static final String CONF_SENSORSCOPE_SERVER_PROPERTIES = "conf/sensorscope_server.properties";
private static final String DEFAULT_FOLDER_FOR_CSV_FILES = "logs";
private DataField[] outputStructureCache = new DataField[]{
new DataField("station_id", "int", "Station ID"),
new DataField("int_batt_volt", "double", "Battery - Internal"),
new DataField("ext_batt_volt", "double", "Battery - External"),
new DataField("cpu_volt", "double", "CPU - Voltage"),
new DataField("cpu_temp", "double", "CPU - Temperature"),
new DataField("air_temp", "double", "SHT75 Temperature"),
new DataField("air_temp_2", "double", "SHT75 Temperature (2)"),
new DataField("air_temp_3", "double", "SHT75 Temperature (3)"),
new DataField("air_temp_4", "double", "SHT75 Temperature (4)"),
new DataField("air_temp_5", "double", "SHT75 Temperature (5)"),
new DataField("air_temp_6", "double", "SHT75 Temperature (6)"),
new DataField("air_temp_7", "double", "SHT75 Temperature (7)"),
new DataField("air_temp_8", "double", "SHT75 Temperature (8)"),
new DataField("air_temp_9", "double", "SHT75 Temperature (9)"),
new DataField("air_temp_10", "double", "SHT75 Temperature (10)"),
new DataField("air_temp_11", "double", "SHT75 Temperature (11)"),
new DataField("air_temp_12", "double", "SHT75 Temperature (12)"),
new DataField("air_temp_13", "double", "SHT75 Temperature (13)"),
new DataField("air_temp_14", "double", "SHT75 Temperature (14)"),
new DataField("air_temp_15", "double", "SHT75 Temperature (15)"),
new DataField("air_temp_16", "double", "SHT75 Temperature (16)"),
new DataField("air_humid", "double", "SHT75 Humidity"),
new DataField("air_humid_2", "double", "SHT75 Humidity (2)"),
new DataField("air_humid_3", "double", "SHT75 Humidity (3)"),
new DataField("air_humid_4", "double", "SHT75 Humidity (4)"),
new DataField("air_humid_5", "double", "SHT75 Humidity (5)"),
new DataField("air_humid_6", "double", "SHT75 Humidity (6)"),
new DataField("air_humid_7", "double", "SHT75 Humidity (7)"),
new DataField("air_humid_8", "double", "SHT75 Humidity (8)"),
new DataField("air_humid_9", "double", "SHT75 Humidity (9)"),
new DataField("air_humid_10", "double", "SHT75 Humidity (10)"),
new DataField("air_humid_11", "double", "SHT75 Humidity (11)"),
new DataField("air_humid_12", "double", "SHT75 Humidity (12)"),
new DataField("air_humid_13", "double", "SHT75 Humidity (13)"),
new DataField("air_humid_14", "double", "SHT75 Humidity (14)"),
new DataField("air_humid_15", "double", "SHT75 Humidity (15)"),
new DataField("air_humid_16", "double", "SHT75 Humidity (16)"),
new DataField("solar_rad", "double", "Davis Solar radiation"),
new DataField("solar_rad_2", "double", "Davis Solar radiation (2)"),
new DataField("solar_rad_3", "double", "Davis Solar radiation (3)"),
new DataField("solar_rad_4", "double", "Davis Solar radiation (4)"),
new DataField("solar_rad_5", "double", "Davis Solar radiation (5)"),
new DataField("solar_rad_6", "double", "Davis Solar radiation (6)"),
new DataField("solar_rad_7", "double", "Davis Solar radiation (7)"),
new DataField("solar_rad_8", "double", "Davis Solar radiation (8)"),
new DataField("solar_rad_9", "double", "Davis Solar radiation (9)"),
new DataField("solar_rad_10", "double", "Davis Solar radiation (10)"),
new DataField("solar_rad_11", "double", "Davis Solar radiation (11)"),
new DataField("solar_rad_12", "double", "Davis Solar radiation (12)"),
new DataField("solar_rad_13", "double", "Davis Solar radiation (13)"),
new DataField("solar_rad_14", "double", "Davis Solar radiation (14)"),
new DataField("solar_rad_15", "double", "Davis Solar radiation (15)"),
new DataField("solar_rad_16", "double", "Davis Solar radiation (16)"),
new DataField("rain_meter", "double", "Davis Rain Meter"),
new DataField("rain_meter_2", "double", "Davis Rain Meter (2)"),
new DataField("rain_meter_3", "double", "Davis Rain Meter (3)"),
new DataField("rain_meter_4", "double", "Davis Rain Meter (4)"),
new DataField("rain_meter_5", "double", "Davis Rain Meter (5)"),
new DataField("rain_meter_6", "double", "Davis Rain Meter (6)"),
new DataField("rain_meter_7", "double", "Davis Rain Meter (7)"),
new DataField("rain_meter_8", "double", "Davis Rain Meter (8)"),
new DataField("rain_meter_9", "double", "Davis Rain Meter (9)"),
new DataField("rain_meter_10", "double", "Davis Rain Meter (10)"),
new DataField("rain_meter_11", "double", "Davis Rain Meter (11)"),
new DataField("rain_meter_12", "double", "Davis Rain Meter (12)"),
new DataField("rain_meter_13", "double", "Davis Rain Meter (13)"),
new DataField("rain_meter_14", "double", "Davis Rain Meter (14)"),
new DataField("rain_meter_15", "double", "Davis Rain Meter (15)"),
new DataField("rain_meter_16", "double", "Davis Rain Meter (16)"),
new DataField("ground_temp_tnx", "double", "TNX Ground Temperature"),
new DataField("ground_temp_tnx_2", "double", "TNX Ground Temperature (2)"),
new DataField("ground_temp_tnx_3", "double", "TNX Ground Temperature (3)"),
new DataField("ground_temp_tnx_4", "double", "TNX Ground Temperature (4)"),
new DataField("ground_temp_tnx_5", "double", "TNX Ground Temperature (5)"),
new DataField("ground_temp_tnx_6", "double", "TNX Ground Temperature (6)"),
new DataField("ground_temp_tnx_7", "double", "TNX Ground Temperature (7)"),
new DataField("ground_temp_tnx_8", "double", "TNX Ground Temperature (8)"),
new DataField("ground_temp_tnx_9", "double", "TNX Ground Temperature (9)"),
new DataField("ground_temp_tnx_10", "double", "TNX Ground Temperature (10)"),
new DataField("ground_temp_tnx_11", "double", "TNX Ground Temperature (11)"),
new DataField("ground_temp_tnx_12", "double", "TNX Ground Temperature (12)"),
new DataField("ground_temp_tnx_13", "double", "TNX Ground Temperature (13)"),
new DataField("ground_temp_tnx_14", "double", "TNX Ground Temperature (14)"),
new DataField("ground_temp_tnx_15", "double", "TNX Ground Temperature (15)"),
new DataField("ground_temp_tnx_16", "double", "TNX Ground Temperature (16)"),
new DataField("air_temp_tnx", "double", "TNX Air Temperature"),
new DataField("air_temp_tnx_2", "double", "TNX Air Temperature (2)"),
new DataField("air_temp_tnx_3", "double", "TNX Air Temperature (3)"),
new DataField("air_temp_tnx_4", "double", "TNX Air Temperature (4)"),
new DataField("air_temp_tnx_5", "double", "TNX Air Temperature (5)"),
new DataField("air_temp_tnx_6", "double", "TNX Air Temperature (6)"),
new DataField("air_temp_tnx_7", "double", "TNX Air Temperature (7)"),
new DataField("air_temp_tnx_8", "double", "TNX Air Temperature (8)"),
new DataField("air_temp_tnx_9", "double", "TNX Air Temperature (9)"),
new DataField("air_temp_tnx_10", "double", "TNX Air Temperature (10)"),
new DataField("air_temp_tnx_11", "double", "TNX Air Temperature (11)"),
new DataField("air_temp_tnx_12", "double", "TNX Air Temperature (12)"),
new DataField("air_temp_tnx_13", "double", "TNX Air Temperature (13)"),
new DataField("air_temp_tnx_14", "double", "TNX Air Temperature (14)"),
new DataField("air_temp_tnx_15", "double", "TNX Air Temperature (15)"),
new DataField("air_temp_tnx_16", "double", "TNX Air Temperature (16)"),
new DataField("soil_temp_ectm", "double", "EC-TM Temperature"),
new DataField("soil_temp_ectm_2", "double", "EC-TM Temperature (2)"),
new DataField("soil_temp_ectm_3", "double", "EC-TM Temperature (3)"),
new DataField("soil_temp_ectm_4", "double", "EC-TM Temperature (4)"),
new DataField("soil_temp_ectm_5", "double", "EC-TM Temperature (5)"),
new DataField("soil_temp_ectm_6", "double", "EC-TM Temperature (6)"),
new DataField("soil_temp_ectm_7", "double", "EC-TM Temperature (7)"),
new DataField("soil_temp_ectm_8", "double", "EC-TM Temperature (8)"),
new DataField("soil_temp_ectm_9", "double", "EC-TM Temperature (9)"),
new DataField("soil_temp_ectm_10", "double", "EC-TM Temperature (10)"),
new DataField("soil_temp_ectm_11", "double", "EC-TM Temperature (11)"),
new DataField("soil_temp_ectm_12", "double", "EC-TM Temperature (12)"),
new DataField("soil_temp_ectm_13", "double", "EC-TM Temperature (13)"),
new DataField("soil_temp_ectm_14", "double", "EC-TM Temperature (14)"),
new DataField("soil_temp_ectm_15", "double", "EC-TM Temperature (15)"),
new DataField("soil_temp_ectm_16", "double", "EC-TM Temperature (16)"),
new DataField("soil_moisture_ectm", "double", "EC-TM Moisture"),
new DataField("soil_moisture_ectm_2", "double", "EC-TM Moisture (2)"),
new DataField("soil_moisture_ectm_3", "double", "EC-TM Moisture (3)"),
new DataField("soil_moisture_ectm_4", "double", "EC-TM Moisture (4)"),
new DataField("soil_moisture_ectm_5", "double", "EC-TM Moisture (5)"),
new DataField("soil_moisture_ectm_6", "double", "EC-TM Moisture (6)"),
new DataField("soil_moisture_ectm_7", "double", "EC-TM Moisture (7)"),
new DataField("soil_moisture_ectm_8", "double", "EC-TM Moisture (8)"),
new DataField("soil_moisture_ectm_9", "double", "EC-TM Moisture (9)"),
new DataField("soil_moisture_ectm_10", "double", "EC-TM Moisture (10)"),
new DataField("soil_moisture_ectm_11", "double", "EC-TM Moisture (11)"),
new DataField("soil_moisture_ectm_12", "double", "EC-TM Moisture (12)"),
new DataField("soil_moisture_ectm_13", "double", "EC-TM Moisture (13)"),
new DataField("soil_moisture_ectm_14", "double", "EC-TM Moisture (14)"),
new DataField("soil_moisture_ectm_15", "double", "EC-TM Moisture (15)"),
new DataField("soil_moisture_ectm_16", "double", "EC-TM Moisture (16)"),
new DataField("soil_water_potential", "double", "Decagon MPS-1 Potential"),
new DataField("soil_water_potential_2", "double", "Decagon MPS-1 Potential (2)"),
new DataField("soil_water_potential_3", "double", "Decagon MPS-1 Potential (3)"),
new DataField("soil_water_potential_4", "double", "Decagon MPS-1 Potential (4)"),
new DataField("soil_water_potential_5", "double", "Decagon MPS-1 Potential (5)"),
new DataField("soil_water_potential_6", "double", "Decagon MPS-1 Potential (6)"),
new DataField("soil_water_potential_7", "double", "Decagon MPS-1 Potential (7)"),
new DataField("soil_water_potential_8", "double", "Decagon MPS-1 Potential (8)"),
new DataField("soil_water_potential_9", "double", "Decagon MPS-1 Potential (9)"),
new DataField("soil_water_potential_10", "double", "Decagon MPS-1 Potential (10)"),
new DataField("soil_water_potential_11", "double", "Decagon MPS-1 Potential (11)"),
new DataField("soil_water_potential_12", "double", "Decagon MPS-1 Potential (12)"),
new DataField("soil_water_potential_13", "double", "Decagon MPS-1 Potential (13)"),
new DataField("soil_water_potential_14", "double", "Decagon MPS-1 Potential (14)"),
new DataField("soil_water_potential_15", "double", "Decagon MPS-1 Potential (15)"),
new DataField("soil_water_potential_16", "double", "Decagon MPS-1 Potential (16)"),
new DataField("soil_temp_decagon", "double", "Decagon Temperature"),
new DataField("soil_temp_decagon_2", "double", "Decagon Temperature (2)"),
new DataField("soil_temp_decagon_3", "double", "Decagon Temperature (3)"),
new DataField("soil_temp_decagon_4", "double", "Decagon Temperature (4)"),
new DataField("soil_temp_decagon_5", "double", "Decagon Temperature (5)"),
new DataField("soil_temp_decagon_6", "double", "Decagon Temperature (6)"),
new DataField("soil_temp_decagon_7", "double", "Decagon Temperature (7)"),
new DataField("soil_temp_decagon_8", "double", "Decagon Temperature (8)"),
new DataField("soil_temp_decagon_9", "double", "Decagon Temperature (9)"),
new DataField("soil_temp_decagon_10", "double", "Decagon Temperature (10)"),
new DataField("soil_temp_decagon_11", "double", "Decagon Temperature (11)"),
new DataField("soil_temp_decagon_12", "double", "Decagon Temperature (12)"),
new DataField("soil_temp_decagon_13", "double", "Decagon Temperature (13)"),
new DataField("soil_temp_decagon_14", "double", "Decagon Temperature (14)"),
new DataField("soil_temp_decagon_15", "double", "Decagon Temperature (15)"),
new DataField("soil_temp_decagon_16", "double", "Decagon Temperature (16)"),
new DataField("soil_moisture_decagon", "double", "Decagon Moisture"),
new DataField("soil_moisture_decagon_2", "double", "Decagon Moisture (2)"),
new DataField("soil_moisture_decagon_3", "double", "Decagon Moisture (3)"),
new DataField("soil_moisture_decagon_4", "double", "Decagon Moisture (4)"),
new DataField("soil_moisture_decagon_5", "double", "Decagon Moisture (5)"),
new DataField("soil_moisture_decagon_6", "double", "Decagon Moisture (6)"),
new DataField("soil_moisture_decagon_7", "double", "Decagon Moisture (7)"),
new DataField("soil_moisture_decagon_8", "double", "Decagon Moisture (8)"),
new DataField("soil_moisture_decagon_9", "double", "Decagon Moisture (9)"),
new DataField("soil_moisture_decagon_10", "double", "Decagon Moisture (10)"),
new DataField("soil_moisture_decagon_11", "double", "Decagon Moisture (11)"),
new DataField("soil_moisture_decagon_12", "double", "Decagon Moisture (12)"),
new DataField("soil_moisture_decagon_13", "double", "Decagon Moisture (13)"),
new DataField("soil_moisture_decagon_14", "double", "Decagon Moisture (14)"),
new DataField("soil_moisture_decagon_15", "double", "Decagon Moisture (15)"),
new DataField("soil_moisture_decagon_16", "double", "Decagon Moisture (16)"),
new DataField("soil_conduct_decagon", "double", "Decagon Conductivity"),
new DataField("soil_conduct_decagon_2", "double", "Decagon Conductivity (2)"),
new DataField("soil_conduct_decagon_3", "double", "Decagon Conductivity (3)"),
new DataField("soil_conduct_decagon_4", "double", "Decagon Conductivity (4)"),
new DataField("soil_conduct_decagon_5", "double", "Decagon Conductivity (5)"),
new DataField("soil_conduct_decagon_6", "double", "Decagon Conductivity (6)"),
new DataField("soil_conduct_decagon_7", "double", "Decagon Conductivity (7)"),
new DataField("soil_conduct_decagon_8", "double", "Decagon Conductivity (8)"),
new DataField("soil_conduct_decagon_9", "double", "Decagon Conductivity (9)"),
new DataField("soil_conduct_decagon_10", "double", "Decagon Conductivity (10)"),
new DataField("soil_conduct_decagon_11", "double", "Decagon Conductivity (11)"),
new DataField("soil_conduct_decagon_12", "double", "Decagon Conductivity (12)"),
new DataField("soil_conduct_decagon_13", "double", "Decagon Conductivity (13)"),
new DataField("soil_conduct_decagon_14", "double", "Decagon Conductivity (14)"),
new DataField("soil_conduct_decagon_15", "double", "Decagon Conductivity (15)"),
new DataField("soil_conduct_decagon_16", "double", "Decagon Conductivity (16)"),
new DataField("wind_direction", "double", "Davis Anemometer Direction"),
new DataField("wind_direction_2", "double", "Davis Anemometer Direction (2)"),
new DataField("wind_direction_3", "double", "Davis Anemometer Direction (3)"),
new DataField("wind_direction_4", "double", "Davis Anemometer Direction (4)"),
new DataField("wind_direction_5", "double", "Davis Anemometer Direction (5)"),
new DataField("wind_direction_6", "double", "Davis Anemometer Direction (6)"),
new DataField("wind_direction_7", "double", "Davis Anemometer Direction (7)"),
new DataField("wind_direction_8", "double", "Davis Anemometer Direction (8)"),
new DataField("wind_direction_9", "double", "Davis Anemometer Direction (9)"),
new DataField("wind_direction_10", "double", "Davis Anemometer Direction (10)"),
new DataField("wind_direction_11", "double", "Davis Anemometer Direction (11)"),
new DataField("wind_direction_12", "double", "Davis Anemometer Direction (12)"),
new DataField("wind_direction_13", "double", "Davis Anemometer Direction (13)"),
new DataField("wind_direction_14", "double", "Davis Anemometer Direction (14)"),
new DataField("wind_direction_15", "double", "Davis Anemometer Direction (15)"),
new DataField("wind_direction_16", "double", "Davis Anemometer Direction (16)"),
new DataField("wind_speed", "double", "Davis Anemometer Speed"),
new DataField("wind_speed_2", "double", "Davis Anemometer Speed (2)"),
new DataField("wind_speed_3", "double", "Davis Anemometer Speed (3)"),
new DataField("wind_speed_4", "double", "Davis Anemometer Speed (4)"),
new DataField("wind_speed_5", "double", "Davis Anemometer Speed (5)"),
new DataField("wind_speed_6", "double", "Davis Anemometer Speed (6)"),
new DataField("wind_speed_7", "double", "Davis Anemometer Speed (7)"),
new DataField("wind_speed_8", "double", "Davis Anemometer Speed (8)"),
new DataField("wind_speed_9", "double", "Davis Anemometer Speed (9)"),
new DataField("wind_speed_10", "double", "Davis Anemometer Speed (10)"),
new DataField("wind_speed_11", "double", "Davis Anemometer Speed (11)"),
new DataField("wind_speed_12", "double", "Davis Anemometer Speed (12)"),
new DataField("wind_speed_13", "double", "Davis Anemometer Speed (13)"),
new DataField("wind_speed_14", "double", "Davis Anemometer Speed (14)"),
new DataField("wind_speed_15", "double", "Davis Anemometer Speed (15)"),
new DataField("wind_speed_16", "double", "Davis Anemometer Speed (16)"),
new DataField("battery_board_voltage", "double", "Battery board 2.3 voltage"),
new DataField("battery_board_voltage_2", "double", "Battery board 2.3 voltage (2)"),
new DataField("battery_board_voltage_3", "double", "Battery board 2.3 voltage (3)"),
new DataField("battery_board_voltage_4", "double", "Battery board 2.3 voltage (4)"),
new DataField("battery_board_voltage_5", "double", "Battery board 2.3 voltage (5)"),
new DataField("battery_board_voltage_6", "double", "Battery board 2.3 voltage (6)"),
new DataField("battery_board_voltage_7", "double", "Battery board 2.3 voltage (7)"),
new DataField("battery_board_voltage_8", "double", "Battery board 2.3 voltage (8)"),
new DataField("battery_board_voltage_9", "double", "Battery board 2.3 voltage (9)"),
new DataField("battery_board_voltage_10", "double", "Battery board 2.3 voltage (10)"),
new DataField("battery_board_voltage_11", "double", "Battery board 2.3 voltage (11)"),
new DataField("battery_board_voltage_12", "double", "Battery board 2.3 voltage (12)"),
new DataField("battery_board_voltage_13", "double", "Battery board 2.3 voltage (13)"),
new DataField("battery_board_voltage_14", "double", "Battery board 2.3 voltage (14)"),
new DataField("battery_board_voltage_15", "double", "Battery board 2.3 voltage (15)"),
new DataField("battery_board_voltage_16", "double", "Battery board 2.3 voltage (16)"),
new DataField("solar_rad_sp212", "double", ""),
new DataField("solar_rad_sp212_2", "double", " (2)"),
new DataField("solar_rad_sp212_3", "double", " (3)"),
new DataField("solar_rad_sp212_4", "double", " (4)"),
new DataField("solar_rad_sp212_5", "double", " (5)"),
new DataField("solar_rad_sp212_6", "double", " (6)"),
new DataField("solar_rad_sp212_7", "double", " (7)"),
new DataField("solar_rad_sp212_8", "double", " (8)"),
new DataField("solar_rad_sp212_9", "double", " (9)"),
new DataField("solar_rad_sp212_10", "double", " (10)"),
new DataField("solar_rad_sp212_11", "double", " (11)"),
new DataField("solar_rad_sp212_12", "double", " (12)"),
new DataField("solar_rad_sp212_13", "double", " (13)"),
new DataField("solar_rad_sp212_14", "double", " (14)"),
new DataField("solar_rad_sp212_15", "double", " (15)"),
new DataField("solar_rad_sp212_16", "double", " (16)"),
new DataField("decagon_10hs_mv", "double", "Decagon 10HS mV"),
new DataField("decagon_10hs_mv_2", "double", "Decagon 10HS mV (2)"),
new DataField("decagon_10hs_mv_3", "double", "Decagon 10HS mV (3)"),
new DataField("decagon_10hs_mv_4", "double", "Decagon 10HS mV (4)"),
new DataField("decagon_10hs_mv_5", "double", "Decagon 10HS mV (5)"),
new DataField("decagon_10hs_mv_6", "double", "Decagon 10HS mV (6)"),
new DataField("decagon_10hs_mv_7", "double", "Decagon 10HS mV (7)"),
new DataField("decagon_10hs_mv_8", "double", "Decagon 10HS mV (8)"),
new DataField("decagon_10hs_mv_9", "double", "Decagon 10HS mV (9)"),
new DataField("decagon_10hs_mv_10", "double", "Decagon 10HS mV (10)"),
new DataField("decagon_10hs_mv_11", "double", "Decagon 10HS mV (11)"),
new DataField("decagon_10hs_mv_12", "double", "Decagon 10HS mV (12)"),
new DataField("decagon_10hs_mv_13", "double", "Decagon 10HS mV (13)"),
new DataField("decagon_10hs_mv_14", "double", "Decagon 10HS mV (14)"),
new DataField("decagon_10hs_mv_15", "double", "Decagon 10HS mV (15)"),
new DataField("decagon_10hs_mv_16", "double", "Decagon 10HS mV (16)"),
new DataField("decagon_10hs_vwc", "double", "Decagon 10HS vwc"),
new DataField("decagon_10hs_vwc_2", "double", "Decagon 10HS vwc (2)"),
new DataField("decagon_10hs_vwc_3", "double", "Decagon 10HS vwc (3)"),
new DataField("decagon_10hs_vwc_4", "double", "Decagon 10HS vwc (4)"),
new DataField("decagon_10hs_vwc_5", "double", "Decagon 10HS vwc (5)"),
new DataField("decagon_10hs_vwc_6", "double", "Decagon 10HS vwc (6)"),
new DataField("decagon_10hs_vwc_7", "double", "Decagon 10HS vwc (7)"),
new DataField("decagon_10hs_vwc_8", "double", "Decagon 10HS vwc (8)"),
new DataField("decagon_10hs_vwc_9", "double", "Decagon 10HS vwc (9)"),
new DataField("decagon_10hs_vwc_10", "double", "Decagon 10HS vwc (10)"),
new DataField("decagon_10hs_vwc_11", "double", "Decagon 10HS vwc (11)"),
new DataField("decagon_10hs_vwc_12", "double", "Decagon 10HS vwc (12)"),
new DataField("decagon_10hs_vwc_13", "double", "Decagon 10HS vwc (13)"),
new DataField("decagon_10hs_vwc_14", "double", "Decagon 10HS vwc (14)"),
new DataField("decagon_10hs_vwc_15", "double", "Decagon 10HS vwc (15)"),
new DataField("decagon_10hs_vwc_16", "double", "Decagon 10HS vwc (16)"),
new DataField("timestamp", "bigint", "Timestamp")
};
private static String csvFolderName = null;
private final int OUTPUT_STRUCTURE_SIZE = outputStructureCache.length;
private double[] buf = new double[OUTPUT_STRUCTURE_SIZE];
private Serializable[] buffer = new Serializable[OUTPUT_STRUCTURE_SIZE];
private int[] count = new int[OUTPUT_STRUCTURE_SIZE];
private long last_timestamp = -1;
private long previous_timestamp = -1;
private boolean doPostStreamElement;
int[] mRxBuf;
byte[] mTxBuf;
private static int port;
DecimalFormat measure = new DecimalFormat("0.00");
private SensorScopeBuffer rxBuffer = new SensorScopeBuffer();
private Vector<SensorScopeBuffer> allBuffers = new Vector<SensorScopeBuffer>();
private int mStationID;
private static final int CLIMAPS_ID = 0;
private static final byte BYTE_SYNC = 0x7E;
private static final byte BYTE_ESC = 0x7D;
private static final byte PKT_TYPE_DATA = 0x00;
private static final byte DATA_TYPE_SENSING = 0x01;
private static final byte PKT_TYPE_CRC = 0x01;
private static final byte BYTE_ACK = 0x00;
private static final byte BYTE_NACK = 0x01;
private static String DEFAULT_NULL_STRING = "null";
private static String nullString = DEFAULT_NULL_STRING;
private static Map<Integer, Long> latestTimestampForStation = new HashMap<Integer, Long>();
private static Map<Integer, Serializable[]> latestBufferForStation = new HashMap<Integer, Serializable[]>();
private static Map<Integer, Map<Long, Serializable[]>> stationsBuffer = new HashMap<Integer, Map<Long, Serializable[]>>();
public SensorScopeServerListener() {
Properties propertiesFile = new Properties();
try {
propertiesFile.load(new FileInputStream(CONF_SENSORSCOPE_SERVER_PROPERTIES));
} catch (IOException e) {
logger.error("Couldn't load configuration file: " + CONF_SENSORSCOPE_SERVER_PROPERTIES);
logger.error(e.getMessage(), e);
System.exit(-1);
}
csvFolderName = propertiesFile.getProperty("csvFolder", DEFAULT_FOLDER_FOR_CSV_FILES);
nullString = propertiesFile.getProperty("nullString", DEFAULT_NULL_STRING);
String str_port = propertiesFile.getProperty("serverPort");
if (str_port == null) {
logger.error("Couldn't find serverPort value in configuration file: " + CONF_SENSORSCOPE_SERVER_PROPERTIES);
System.exit(-1);
}
try {
port = Integer.parseInt(str_port);
} catch (NumberFormatException e) {
logger.error("Incorrect value (" + str_port + ") for serverPort in configuration file: " + CONF_SENSORSCOPE_SERVER_PROPERTIES);
System.exit(-1);
}
logger.info("CSV folder for CSV files: " + csvFolderName);
logger.info("Null string: \"" + nullString + "\"");
mRxBuf = new int[RX_BUFFER_SIZE];
mTxBuf = new byte[TX_BUFFER_SIZE];
// Create a server socket
try {
serverSocket = new ServerSocket(port);
} catch (IOException e) {
logger.error("Couldn't create server socket");
logger.error(e.getMessage(), e);
System.exit(-1);
}
logger.info("Server initialized on port " + port);
}
Socket client = null;
ServerSocket serverSocket = null;
int receive(byte[] buffer) {
try {
return client.getInputStream().read(buffer);
} catch (IOException e) {
logger.warn("Exception\n" + e.toString());
return -1;
}
}
int receive(byte[] buffer, int n) {
//logger.debug("Trying to read " + n + " bytes...");
try {
int nb_read = client.getInputStream().read(buffer, 0, n);
//logger.debug("Read (" + nb_read + ")");
return nb_read;
} catch (IOException e) {
logger.warn(e.getMessage(), e);
return -1;
}
}
int receive(UnsignedByte[] buffer, int n) {
logger.warn("Trying to read " + n + " unsigned bytes...");
byte[] byteBuffer = new byte[buffer.length];
try {
int nb_read = client.getInputStream().read(byteBuffer, 0, n);
buffer = UnsignedByte.ByteArray2UnsignedByteArray(byteBuffer);
logger.info("Read (" + nb_read + ")");
return nb_read;
} catch (IOException e) {
logger.warn(e.getMessage(), e);
return -1;
}
}
boolean send(byte[] buffer) {
boolean success = true;
try {
OutputStream out = client.getOutputStream();
out.write(buffer);
out.flush();
} catch (IOException e) {
logger.warn("Exception while trying to send data\n" + e);
success = false;
}
return success;
}
boolean send(byte[] buffer, int len) {
boolean success = true;
logger.info("*** Sending data to client");
try {
OutputStream out = client.getOutputStream();
out.write(buffer, 0, len);
out.flush();
} catch (IOException e) {
logger.warn("Exception while trying to send data\n" + e);
success = false;
}
return success;
}
boolean ReceivePacket(PacketInfo aPacket) {
int packet = aPacket.packet;
int length = aPacket.length;
//logger.info("ReceivePacket(packet=" + packet + ",length=" + length + ")");
boolean escape = false;
boolean lengthOk = false;
int idx = 0;
byte _byte[] = new byte[1];
_byte[0] = 0;
UnsignedByte b = new UnsignedByte();
// Reset buffer
rxBuffer.reset();
while (true) {
if (!ReceiveUnsignedByte(b))
return false;
rxBuffer.add(b.getInt());
dumpByte(b.getInt());
//logger.debug("byte => " + b.toString());
// Synchronization byte?
if (b.getByte() == BYTE_SYNC) {
mRxBuf[length] = 1;
length = 1;
aPacket.length = length;
mRxBuf[packet + 0] = BYTE_SYNC; // packet[0] = BYTE_SYNC
return true;
}
// Beware of escaped bytes
if (escape) {
b.setValue(b.getByte() ^ 0x20);
escape = false;
} else if (b.getByte() == BYTE_ESC) {
escape = true;
continue;
}
// First 'real' byte is the packet length
if (lengthOk == false) {
length = b.getInt();
aPacket.length = length;
lengthOk = true;
} else {
mRxBuf[packet + idx++] = b.getInt(); // packet[idx++] = byte;
// The GPRS sends '+++' upon disconnection
if (mRxBuf[length] == PLUS_SIGN && mRxBuf[packet + 0] == PLUS_SIGN && mRxBuf[1] == PLUS_SIGN) {
mRxBuf[length] = 3;
mRxBuf[packet + 2] = PLUS_SIGN;
return true;
}
// Do we have a complete packet?
if (idx == length) {
//logger.debug("complete packet");
return true;
}
}
}
}
private boolean ReceiveUnsignedByte(UnsignedByte b) {
byte[] _oneByte = new byte[1];
int n_bytes = receive(_oneByte, 1);
//logger.debug("Read (" + n_bytes + ") => " + b.toString());
if (n_bytes < 1)
return false;
else {
b.setValue(_oneByte[0]);
return true;
}
}
private boolean ReceiveByte(byte b[]) {
byte[] _oneByte = new byte[1];
int n_bytes = receive(_oneByte, 1);
logger.info("Read (" + n_bytes + ") => " + _oneByte[0]);
if (n_bytes < 1)
return false;
else {
b[0] = _oneByte[0];
return true;
}
}
public void dumpByte(int value) {
dumpByte(value, DEFAULT_PACKETS_LOGFILE);
}
public void dumpText(String s) {
dumpText(s, DEFAULT_PACKETS_LOGFILE);
}
public void dumpByte(int value, String fileName) {
try {
FileWriter fstream = new FileWriter(fileName, true);
BufferedWriter out = new BufferedWriter(fstream);
String s = value + " ";
out.write(s);
out.close();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
public void dumpText(String s, String fileName) {
try {
FileWriter fstream = new FileWriter(fileName, true);
BufferedWriter out = new BufferedWriter(fstream);
out.write(s);
out.close();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
public int entry() {
int rssi;
long rtt;
int[] challenge = new int[25];
byte[] buffer = new byte[7];
if (serverSocket == null) {
logger.error("Failed connection");
return 0;
}
long counter = 0;
try {
// Wait for a request
logger.warn("Server listening...");
client = serverSocket.accept();
logger.info("Connection from: " + client.getRemoteSocketAddress().toString());
// Get rssi
logger.info("Trying to receive RSSI...");
int n_read = receive(buffer, 2);
if (n_read < 2) {
CleanUp("receiving RSSI");
logger.info(Formatter.listArray(buffer, n_read));
return 0;
}
logger.info(Formatter.listArray(buffer, n_read));
int buffer_1 = ((int) buffer[1] & 0xff);
if (buffer_1 <= 31) rssi = -113 + (2 * buffer_1);
else rssi = -255;
logger.info("RSSI = " + rssi);
// Send the authentication challenge
FillAuthChallenge(challenge);
rtt = System.currentTimeMillis();
if (!send(toByteArray(challenge))) {
CleanUp("sending authentication challenge");
return 0;
}
// Get the reply to the challenge
if (receive(buffer, 7) < 0) {
CleanUp("receiving authentication data");
return 0;
}
logger.info("* Response to challenge *");
logger.info(Formatter.listArray(buffer, 7));
rtt = System.currentTimeMillis() - rtt;
// Check that the station correctly authenticated itself
if (!CheckAuthentication(PASSKEY, challenge[1], challenge[9], buffer[3], buffer[5])) {
logger.error("Failed authentication from " + client.getRemoteSocketAddress().toString());
client.close();
return 0;
}
mStationID = ((int) buffer[1] << 8) + (int) buffer[2];
if (mStationID == CLIMAPS_ID)
logger.info("Climaps authenticated (RTT = " + rtt + " ms)");
else
logger.info("Station " + mStationID + " (RTT = " + rtt + " ms, RSSI = " + rssi + " dBm)");
ProcessPackets();
client.close();
counter++;
} catch (IOException ioe) {
logger.warn("Error in Server: " + ioe);
} finally {
try {
client.close();
} catch (Exception e) {
logger.warn("can't close streams" + e.getMessage());
}
}
return 0;
}
private void ProcessPackets() {
logger.info("-- Processing packets --");
// clearing buffers container
allBuffers.clear();
int rxIdx = 0;
int nbPkts = 0;
int pktLen = 0;
try {
while (true) {
dumpText("\nCalling ReceivePacket()\n");
dumpText("\nCalling ReceivePacket()\n", "logs/packets2.txt");
int pkt = mRxBuf[rxIdx + 1];
logger.info("Trying to receive packets with pkt=" + pkt + " rxIdx=" + rxIdx);
PacketInfo aPacket = new PacketInfo(pkt, rxIdx);
if (!ReceivePacket(aPacket)) {
CleanUp("receiving packets");
return;
}
String strPacket = rxBuffer.toString();
dumpText(strPacket + "\n", "logs/buffers.txt");
pkt = aPacket.packet;
rxIdx = aPacket.length;
logger.info("* RECEIVED PACKET *, pkt=" + pkt + " rxIdx=" + rxIdx);
logger.info(strPacket);
// This is a (dirty?) hack to mimic MMC card buffers, where the length includes the length byte itself
mRxBuf[rxIdx]++;
pktLen = mRxBuf[rxIdx] - 1;
rxIdx += pktLen + 1;
// '+++' means that the GPRS has disconnected
if (rxBuffer.getPacketSize() == 3
&& rxBuffer.get(1) == PLUS_SIGN
&& rxBuffer.get(2) == PLUS_SIGN
&& rxBuffer.get(3) == PLUS_SIGN) {
if (mStationID == CLIMAPS_ID)
logger.info("Climaps has disconnected");
else
logger.info("Station " + mStationID + " has disconnected");
return;
}
// A synchronization byte resets the reception
if (rxBuffer.getSize() == 1 && rxBuffer.get(0) == BYTE_SYNC) {
logger.info("*** BYTE_SNYC *** should recet reception");
rxIdx = 0;
nbPkts = 0;
allBuffers.clear();//TODO: empty list of buffers, reset reception
continue;
}
// A data packet?
if (rxBuffer.get(1) == PKT_TYPE_DATA) {
++nbPkts;
allBuffers.add(new SensorScopeBuffer(rxBuffer));
logger.info("*** Data packet *** now " + nbPkts + " packets (" + allBuffers.size() + ")");
continue;
}
// At this point, it must be a CRC (3 bytes long)
if (rxBuffer.getPacketSize() != 3 || rxBuffer.get(1) != PKT_TYPE_CRC) {
mTxBuf[1] = BYTE_NACK;
logger.warn("Corrupted CRC packet received");
} else {
// So far so good, let's check the crc
int expectedCRC = rxBuffer.get(2) << 8 + rxBuffer.get(3);
logger.info("Expected CRC = " + expectedCRC);
int nextPktIdx = 0;
int crc = 0;
for (int i = 0; i < rxIdx - 3; ++i) {//TODO: fix crc calculation
if (i == nextPktIdx) nextPktIdx += mRxBuf[i];
else crc = Crc16Byte(crc, mRxBuf[i]);
}
//TODO: remove this hack, only for testing
crc = expectedCRC; // hack !!!!!!!!!!
//TODO: remove this hack, only for testing
if (expectedCRC == crc) {
if (mStationID == CLIMAPS_ID)
logger.warn("Successfully received " + nbPkts + " data packet from Climaps");
else
logger.warn("Successfully received " + nbPkts + "data packet from station " + mStationID);
ExtractData();
mTxBuf[1] = BYTE_ACK;
logger.info("Sending a BYTE_ACK to client");
} else {
mTxBuf[1] = BYTE_NACK;
logger.error("Invalid CRC received");
}
}
// Once here, in any case, we must send back an ACK or a NACK
mTxBuf[0] = 1;
logger.info("Going to send...");
if (!send(mTxBuf, 2)) {
if (mTxBuf[1] == BYTE_ACK)
CleanUp("sending back an ACK");
else
CleanUp("sending back a NACK");
return;
}
// Done with the current batch of packets
rxIdx = 0;
nbPkts = 0;
//return; //TODO: check if a return is needed. Without a return, looping again but always getting a reception error
}
} catch (ArrayIndexOutOfBoundsException e) {
logger.error(e.getMessage(), e);
logger.error("rxIdx = " + rxIdx);
logger.error("nbPkts = " + nbPkts);
logger.error("pktLen = " + pktLen);
}
}
private void interpretPacket(int[] dataPacket) {
logger.info(" ---> " + Formatter.listArray(dataPacket, dataPacket.length));
int stationID = (dataPacket[1] << 8) + dataPacket[2];
logger.info("stationID: " + stationID + "[ " + dataPacket[1] + " << 8 + " + dataPacket[2] + " ]");
long referenceTimestamp = (dataPacket[3] << 24) + (dataPacket[4] << 16) + (dataPacket[5] << 8) + dataPacket[6]; //pkt[idx] << 24) + (pkt[idx+1] << 16) + (pkt[idx+2] << 8) + pkt[idx+3];
logger.info("Reference timestamp: " + referenceTimestamp);
int dataPacketLength = dataPacket.length - 1; //skip first element, containing actual length
int currentChunk = 0;
boolean stillOtherChunks = true;
int currentChunk_begin = 3;
int timestamp_offset = -1;
while (stillOtherChunks) {
long timestamp = -1;
if (currentChunk == 0) {
timestamp = referenceTimestamp;
timestamp_offset = 4;
} else {
timestamp = referenceTimestamp + dataPacket[currentChunk_begin];
timestamp_offset = 1;
}
int currentChunkLength = dataPacket[currentChunk_begin + timestamp_offset];
int currentChunk_end = currentChunk_begin + timestamp_offset + currentChunkLength;
logger.info("currentChunk_begin:" + currentChunk_begin + " , currentChunkLength: " + currentChunkLength + " , currentChunk_end: " + currentChunk_end);
if (currentChunk_end > dataPacketLength) {
logger.error("Error in packet. Chunk end is out of bounds");
return;
}
int[] currentChunkData = new int[currentChunkLength];
for (int j = 0; j < currentChunkLength; j++) {
currentChunkData[j] = dataPacket[currentChunk_begin + timestamp_offset + j + 1];
}
logger.info("Chunk " + currentChunk + " : TS=" + timestamp + " , length = " + currentChunkLength + " , end = " + currentChunk_end);
logger.info(Formatter.listArray(currentChunkData, currentChunkData.length));
// starting to read within a chunk of data
// input is currentChunkData[] array
boolean stillOtherReadingsInChunk = true;
int last_data_reading = -1; // index of last data reading, needed for processing possible further readings within a chunk
int readingShift = 0; // shift within readings, for multiple readings within a chunk
while (stillOtherReadingsInChunk) {
try {
int ext = currentChunkData[0 + readingShift] / 128;
int sid1 = currentChunkData[0 + readingShift] % 128;
int sid = -1;
int dupn = 0;
int reading[];
logger.debug("ext: " + ext + " , sid1:" + sid1);
if ((ext == 0) && (sid1 < 108)) { // no extension, no sid2
reading = new int[2];
reading[0] = currentChunkData[1 + readingShift];
reading[1] = currentChunkData[2 + readingShift];
last_data_reading = 2 + readingShift;
sid = sid1;
logger.debug("SID=" + sid + " Reading=" + Formatter.listArray(reading));
} else if ((ext == 1) && (sid1 < 108)) { // extension, but no sid2
int data_dupn = currentChunkData[1 + readingShift] / 16;
int data_length = currentChunkData[1 + readingShift] % 16;
dupn = data_dupn;
if (logger.isDebugEnabled())
logger.debug("data_dupn=" + data_dupn + " data_length=" + data_length);
reading = new int[data_length + 1];
for (int i = 0; i < reading.length; i++)
reading[i] = currentChunkData[2 + i + readingShift]; // skip sid + dat_length
last_data_reading = 1 + reading.length + readingShift;
sid = sid1;
logger.debug("SID=" + sid + " Reading=" + Formatter.listArray(reading));
} else if ((ext == 0) && (sid1 >= 108)) { // no extension, with sid2
int sid2 = currentChunkData[1];
logger.debug("sid2=" + sid2);
sid = (sid1 - 108) * 256 + sid2;
reading = new int[2];
reading[0] = currentChunkData[2 + readingShift]; // shifted by 1, because of sid2
reading[1] = currentChunkData[3 + readingShift]; // shifted by 1, because of sid2
last_data_reading = 3 + readingShift;
logger.debug("SID=" + sid + " Reading=" + Formatter.listArray(reading));
} else {// (ext==1) && /sid1 >=108)
int sid2 = currentChunkData[1];
logger.debug("sid2=" + sid2);
sid = (sid1 - 108) * 256 + sid2;
int data_dupn = currentChunkData[2] / 16;
int data_length = currentChunkData[2] % 16;
dupn = data_dupn;
if (logger.isDebugEnabled())
logger.debug("data_dupn=" + data_dupn + " data_length=" + data_length);
// shift by 3
reading = new int[data_length + 1];
for (int i = 0; i < reading.length; i++)
reading[i] = currentChunkData[3 + i + readingShift];
last_data_reading = 2 + reading.length + readingShift;
logger.debug("SID=" + sid + " Reading=" + Formatter.listArray(reading));
}
logger.info("SENSOR => TS:" + timestamp + " , stationID:" + stationID + " , SID:" + sid + " , dupn:" + dupn + " , reading: " + Formatter.listArray(reading));
StreamElement aStreamElement = publishSensor(timestamp, stationID, sid, dupn, reading);
if (aStreamElement != null) {
//PublishStreamElement(aStreamElement);
}
if (last_data_reading < currentChunkLength - 1) { // still other readings within chunk
stillOtherReadingsInChunk = true;
readingShift = last_data_reading + 1;
} else
stillOtherReadingsInChunk = false; //TODO: check stop condition
} catch (IndexOutOfBoundsException e) {
logger.error("Error while parsing current chunk with readingShift=" + readingShift);
logger.error("Chunk: " + Formatter.listArray(currentChunkData));
logger.error(e.getMessage(), e);
stillOtherReadingsInChunk = false;
}
}
// end of reading within current chunk of data
// goto next chunk, if any
currentChunk_begin += timestamp_offset + 1 + currentChunkLength;
if (currentChunk_begin > dataPacketLength - 1)
stillOtherChunks = false;
currentChunk++;
}
}
Serializable[] mergePackets(Serializable[] olderPacket, Serializable[] newerPacket) {
Serializable[] mergedPacket = olderPacket.clone();
for (int i = 0; i < olderPacket.length; i++) {
if (olderPacket[i] == null && newerPacket[i] != null)
mergedPacket[i] = newerPacket[i];
}
return mergedPacket;
}
/*
* Publish buffer
* Merges packets for similar timestamps including timestamps older than latest,
* uses a buffer of size 10 to store history (moving window of size 10 and step 1)
* */
private void PublishPacketWithHistory(Serializable[] packet, long timestamp, int stationID) {
if (stationsBuffer.containsKey(stationID)) {
AddToStationBuffer(stationID, timestamp, packet);
} else {
stationsBuffer.put(stationID, new HashMap<Long, Serializable[]>()); // create buffer for station stationID
stationsBuffer.get(stationID).put(timestamp, packet); // add packet for station stationID
}
}
private void AddToStationBuffer(int stationID, long timestamp, Serializable[] packet) {
if (stationsBuffer.get(stationID).containsKey(timestamp)) { // timestamp already present
stationsBuffer.get(stationID).put(timestamp, mergePackets(stationsBuffer.get(stationID).get(timestamp), packet)); // merge new buffer with previous
} else {
stationsBuffer.get(stationID).put(timestamp, packet);
}
CheckQueueSizeForStation(stationID);
}
/*
* Keeps only 10 values in the queue
* Removes oldest value if queue is has more than 10 elements
* (moving window of size 10 and step 1)
* */
private void CheckQueueSizeForStation(int stationID) {
int queueSize = stationsBuffer.get(stationID).size();
logger.info("Queue [" + stationID + "] = " + queueSize);
// search for oldest timestamp (smaller value)
Long oldestTimestamp = Long.MAX_VALUE;
for (Long timestamp : stationsBuffer.get(stationID).keySet()) {
if (timestamp < oldestTimestamp)
oldestTimestamp = timestamp;
}
Serializable[] _buffer = stationsBuffer.get(stationID).get(oldestTimestamp);
if (queueSize > 10) {
try { // Publish one element
String stationFileName = csvFolderName + "/" + stationID + ".csv";
FileWriter fstream = new FileWriter(stationFileName, true);
BufferedWriter out = new BufferedWriter(fstream);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < _buffer.length; i++) {
if (_buffer[i] == null)
sb.append(nullString).append(",");
else
sb.append(_buffer[i]).append(",");
}
sb.append(Helpers.convertTimeFromLongToIso(oldestTimestamp, "yyyy-MM-dd HH:mm:ss"));
sb.append("\n");
out.write(sb.toString());
out.close();
stationsBuffer.get(stationID).remove(oldestTimestamp); // Remove one element
logger.info("Queue [" + stationID + "] = " + queueSize + " after publishing");
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
/*
* Publish buffer
* Merges packets for similar timestamps but doesn't handle timestamps older than latest
* */
private void PublishBuffer(Serializable[] packet, long timestamp, int stationID) {
if (!latestTimestampForStation.containsKey(stationID)) { // first time we receive that stationID
logger.debug("first time we receive stationID=" + stationID);
latestTimestampForStation.put(stationID, timestamp);
latestBufferForStation.put(stationID, packet.clone());
} else {
if (timestamp == latestTimestampForStation.get(stationID)) {
latestBufferForStation.put(stationID, mergePackets(latestBufferForStation.get(stationID), packet));
logger.debug("Merging buffers for stationID=" + stationID);
} else {
if ((timestamp > latestTimestampForStation.get(stationID))) {
logger.debug("Publishing data for stationID=" + stationID);
latestTimestampForStation.put(stationID, timestamp); // update timestamp
latestBufferForStation.put(stationID, packet.clone()); // update buffer
try { // Publish it
String stationFileName = csvFolderName + "/" + stationID + "_nopast.csv";
FileWriter fstream = new FileWriter(stationFileName, true);
BufferedWriter out = new BufferedWriter(fstream);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < packet.length; i++) {
if (packet[i] == null)
sb.append(nullString).append(",");
else
sb.append(packet[i]).append(",");
}
sb.append(Helpers.convertTimeFromLongToIso(timestamp, "yyyy-MM-dd HH:mm:ss"));
sb.append("\n");
out.write(sb.toString());
out.close();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
} else {
//TODO: received data from the past
}
}
}
}
/*
* Publish buffer
* Doesn't merge buffers for similar timestamps
*/
private void PublishBufferNoMerge(Serializable[] packet, long timestamp, int stationID) {
logger.debug("Publishing data for stationID=" + stationID);
try {
String stationFileName = csvFolderName + "/" + stationID + "_nomerge.csv";
FileWriter fstream = new FileWriter(stationFileName, true);
BufferedWriter out = new BufferedWriter(fstream);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < packet.length; i++) {
if (packet[i] == null)
sb.append(nullString).append(",");
else
sb.append(packet[i]).append(",");
}
sb.append(Helpers.convertTimeFromLongToIso(timestamp, "yyyy-MM-dd HH:mm:ss"));
sb.append("\n");
out.write(sb.toString());
out.close();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
private StreamElement publishSensor(long timestamp, int stationID, int sid, int dupn, int[] reading) {
StreamElement aStreamElement = null;
// interpreting raw readings
double sid1_int_batt_volt;
double sid1_ext_batt_volt;
double sid1_cpu_volt;
double sid1_cpu_temp;
double sid2_air_temp;
double sid2_air_humid;
double sid4_solar_rad;
double sid5_rain_meter;
double sid6_ground_temp;
double sid6_air_temp;
double sid7_soil_temp;
double sid7_soil_moisture;
double sid8_soil_water_potential;
double sid9_soil_temp;
double sid9_soil_moisture;
double sid9_soil_conduct;
double sid10_wind_direction;
double sid10_wind_speed;
double sid12_battery_board_voltage;
double sid19_decagon_10hs_mv;
double sid19_decagon_10hs_vwc;
double sid20_solar_rad_sp212;
last_timestamp = timestamp * 1000;
buffer[0] = new Integer(stationID);
buf[0] = stationID;
for (int i = 1; i <= OUTPUT_STRUCTURE_SIZE - 2; i++)
buffer[i] = null;
buffer[OUTPUT_STRUCTURE_SIZE - 1] = new Long(last_timestamp);
doPostStreamElement = true;
// extended sensors (when other sensors share the same bus)
// are supported up to dupn=MAX_DUPN (MAX_DUPN+1 sensors in total)
if (dupn > MAX_DUPN)
doPostStreamElement = false;
if (dupn <= MAX_DUPN)
switch (sid) {
case 1:
long raw_int_batt_volt = reading[0] * 16 + reading[1] / 16;
long raw_ext_batt_volt = (reading[1] % 16) * 256 + reading[2];
long raw_cpu_volt = reading[3] * 16 + reading[4] / 16;
long raw_cpu_temp = (reading[4] % 16) * 256 + reading[5];
sid1_int_batt_volt = raw_int_batt_volt * 2.4 * 2.5 / 4095;
sid1_ext_batt_volt = raw_ext_batt_volt * 6.12 * 2.5 / 4095 + 0.242;
sid1_cpu_volt = raw_cpu_volt * 3.0 / 4095;
sid1_cpu_temp = (raw_cpu_temp * 1.5 / 4095 - 0.986) / 0.00355;
logger.info("sid1_int_batt_volt: " + measure.format(sid1_int_batt_volt) +
" sid1_ext_batt_volt: " + measure.format(sid1_ext_batt_volt) +
" sid1_cpu_volt: " + measure.format(sid1_cpu_volt) +
" sid1_cpu_temp: " + measure.format(sid1_cpu_temp));
buffer[1] = new Double(sid1_int_batt_volt);
buf[1] = sid1_int_batt_volt;
count[1]++;
buffer[2] = new Double(sid1_ext_batt_volt);
buf[2] = sid1_ext_batt_volt;
count[2]++;
buffer[3] = new Double(sid1_cpu_volt);
buf[3] = sid1_cpu_volt;
count[3]++;
buffer[4] = new Double(sid1_cpu_temp);
buf[4] = sid1_cpu_temp;
count[4]++;
break;
case 2:
long raw_airtemp = reading[0] * 64 + reading[1] / 4;
long raw_airhumidity = reading[3] / 64 + reading[2] * 4 + (reading[1] % 4) * 1024;
sid2_air_temp = raw_airtemp * 1.0 / 100 - 39.6;
sid2_air_humid = (raw_airhumidity * 1.0 * 0.0405) - 4 - (raw_airhumidity * raw_airhumidity * 0.0000028) + ((raw_airhumidity * 0.00008) + 0.01) * (sid2_air_temp - 25);
logger.info("sid2_air_temp: " + measure.format(sid2_air_temp) +
" sid2_air_humid: " + measure.format(sid2_air_humid));
buffer[OFFSET_AIR_TEMP + dupn] = new Double(sid2_air_temp);
buf[OFFSET_AIR_TEMP + dupn] = sid2_air_temp;
count[OFFSET_AIR_TEMP + dupn]++;
buffer[OFFSET_AIR_HUMID + dupn] = new Double(sid2_air_humid);
buf[OFFSET_AIR_HUMID + dupn] = sid2_air_humid;
count[OFFSET_AIR_HUMID + dupn]++;
break;
case 4:
long raw_solar_rad = reading[0] * 256 + reading[1];
sid4_solar_rad = raw_solar_rad * 2.5 * 1000 * 6 / (4095 * 1.67 * 5);
logger.info("sid4_solar_rad: " + measure.format(sid4_solar_rad));
buffer[OFFSET_SOLAR_RAD + dupn] = new Double(sid4_solar_rad);
buf[OFFSET_SOLAR_RAD + dupn] = sid4_solar_rad;
count[OFFSET_SOLAR_RAD + dupn]++;
break;
case 5:
long raw_rain_meter = reading[0] * 256 + reading[1];
sid5_rain_meter = raw_rain_meter * 0.254;
logger.info("sid5_rain_meter: " + measure.format(sid5_rain_meter));
buffer[OFFSET_RAIN_METER + dupn] = new Double(sid5_rain_meter);
buf[OFFSET_RAIN_METER + dupn] = sid5_rain_meter;
count[OFFSET_RAIN_METER + dupn]++;
break;
case 6:
long raw_ground_temp = reading[0] * 256 + reading[1];
long raw_air_temp = reading[2] * 256 + reading[3];
sid6_ground_temp = raw_ground_temp / 16.0 - 273.15;
sid6_air_temp = raw_air_temp / 16.0 - 273.15;
buffer[OFFSET_GROUND_TEMP_TNX + dupn] = new Double(sid6_ground_temp);
buf[OFFSET_GROUND_TEMP_TNX + dupn] = sid6_ground_temp;
count[OFFSET_GROUND_TEMP_TNX + dupn]++;
buffer[OFFSET_AIR_TEMP_TNX + dupn] = new Double(sid6_air_temp);
buf[OFFSET_AIR_TEMP_TNX + dupn] = sid6_air_temp;
count[OFFSET_AIR_TEMP_TNX + dupn]++;
logger.info("sid6_ground_temp: " + measure.format(sid6_ground_temp) +
" sid6_air_temp: " + measure.format(sid6_air_temp));
break;
case 7:
long raw_soil_temp = reading[0] * 256 + reading[1];
long raw_soil_moisture = reading[2] * 256 + reading[3];
sid7_soil_temp = (raw_soil_temp - 400.0) / 10.0;
sid7_soil_moisture = (raw_soil_moisture * 0.00104 - 0.5) * 100;
buffer[OFFSET_SOIL_TEMP_ECTM + dupn] = new Double(sid7_soil_temp);
buf[OFFSET_SOIL_TEMP_ECTM + dupn] = sid7_soil_temp;
count[OFFSET_SOIL_TEMP_ECTM + dupn]++;
buffer[OFFSET_SOIL_MOISTURE_ECTM + dupn] = new Double(sid7_soil_moisture);
buf[OFFSET_SOIL_MOISTURE_ECTM + dupn] = sid7_soil_moisture;
count[OFFSET_SOIL_MOISTURE_ECTM + dupn]++;
logger.info("sid7_soil_temp: " + measure.format(sid7_soil_temp) +
" sid7_soil_moisture: " + measure.format(sid7_soil_moisture));
break;
case 8:
long raw_soil_water_potential = reading[0] * 256 + reading[1];
sid8_soil_water_potential = raw_soil_water_potential;
buffer[OFFSET_SOIL_WATER_POTENTIAL + dupn] = new Double(sid8_soil_water_potential);
buf[OFFSET_SOIL_WATER_POTENTIAL + dupn] = sid8_soil_water_potential;
count[OFFSET_SOIL_WATER_POTENTIAL + dupn]++;
logger.info("sid8_soil_water_potential:" + measure.format(sid8_soil_water_potential));
break;
case 9:
long raw_sid9_soil_temp = reading[0] * 256 + reading[1];
long raw_sid9_soil_moisture = reading[2] * 256 + reading[3];
long raw_sid9_soil_conduct = reading[4] * 256 + reading[5];
if (raw_sid9_soil_temp <= 900)
sid9_soil_temp = (raw_sid9_soil_temp - 400.0) / 10.0;
else
sid9_soil_temp = (900 + 5 * (raw_sid9_soil_temp - 900.0) - 400) / 10.0;
sid9_soil_moisture = raw_sid9_soil_moisture / 50.0;
if (raw_sid9_soil_conduct <= 700)
sid9_soil_conduct = raw_sid9_soil_conduct / 100.0;
else
sid9_soil_conduct = (700 + 5.0 * (raw_sid9_soil_conduct - 700)) / 100.0;
buffer[OFFSET_SOIL_TEMP_DECAGON + dupn] = new Double(sid9_soil_temp);
buf[OFFSET_SOIL_TEMP_DECAGON + dupn] = sid9_soil_temp;
count[OFFSET_SOIL_TEMP_DECAGON + dupn]++;
buffer[OFFSET_SOIL_MOISTURE_DECAGON + dupn] = new Double(sid9_soil_moisture);
buf[OFFSET_SOIL_MOISTURE_DECAGON + dupn] = sid9_soil_moisture;
count[OFFSET_SOIL_MOISTURE_DECAGON + dupn]++;
buffer[OFFSET_SOIL_CONDUCT_DECAGON + dupn] = new Double(sid9_soil_conduct);
buf[OFFSET_SOIL_CONDUCT_DECAGON + dupn] = sid9_soil_conduct;
count[OFFSET_SOIL_CONDUCT_DECAGON + dupn]++;
logger.info("sid9_soil_temp: " + measure.format(sid9_soil_temp) +
" sid9_soil_moisture: " + measure.format(sid9_soil_moisture) +
" sid9_soil_conduct: " + measure.format(sid9_soil_conduct));
break;
case 10:
int sign = reading[0] / 128;
long raw_sid10_wind_direction = (reading[0] % 16) * 256 + reading[1];
long raw_sid10_wind_speed = reading[2] * 256 + reading[3];
if (sign == 0)
sid10_wind_direction = java.lang.Math.acos(((raw_sid10_wind_direction * 2.0) / 4095.0) - 1) * 360.0 / (2 * java.lang.Math.PI);
else
sid10_wind_direction = 360 - java.lang.Math.acos((raw_sid10_wind_direction * 2.0) / 4095.0 - 1) * 360.0 / (2 * java.lang.Math.PI);
sid10_wind_speed = raw_sid10_wind_speed * 3600.0 * 1.6093 / (600 * 1600 * 3.6);
buffer[OFFSET_WIND_DIRECTION + dupn] = new Double(sid10_wind_direction);
buf[OFFSET_WIND_DIRECTION + dupn] = sid10_wind_direction;
count[OFFSET_WIND_DIRECTION + dupn]++;
buffer[OFFSET_WIND_SPEED + dupn] = new Double(sid10_wind_speed);
buf[OFFSET_WIND_SPEED + dupn] = sid10_wind_speed;
count[OFFSET_WIND_SPEED + dupn]++;
logger.info("sid10_wind_direction: " + measure.format(sid10_wind_direction) +
" sid10_wind_speed: " + measure.format(sid10_wind_speed));
break;
case 19:
long decagon_10hs_raw = reading[0] * 256 + reading[1];
sid19_decagon_10hs_mv = (decagon_10hs_raw * 2.5) / (4.095 * 2);
sid19_decagon_10hs_vwc = (0.00000000297 * sid19_decagon_10hs_mv * sid19_decagon_10hs_mv * sid19_decagon_10hs_mv) - (0.00000737 * sid19_decagon_10hs_mv * sid19_decagon_10hs_mv) + (0.00669 * sid19_decagon_10hs_mv) - 1.92;
buffer[OFFSET_DECAGON_10HS_MV + dupn] = new Double(sid19_decagon_10hs_mv);
buf[OFFSET_DECAGON_10HS_MV + dupn] = sid19_decagon_10hs_mv;
count[OFFSET_DECAGON_10HS_MV + dupn]++;
buffer[OFFSET_DECAGON_10HS_VWC + dupn] = new Double(sid19_decagon_10hs_vwc);
buf[OFFSET_DECAGON_10HS_VWC + dupn] = sid19_decagon_10hs_vwc;
count[OFFSET_DECAGON_10HS_VWC + dupn]++;
logger.info("sid19_decagon_10hs_mv: " + measure.format(sid19_decagon_10hs_mv) +
" sid19_decagon_10hs_vwc: " + measure.format(sid19_decagon_10hs_vwc));
break;
case 20:
long solar_rad_sp212_raw = reading[0] * 256 + reading[1];
sid20_solar_rad_sp212 = solar_rad_sp212_raw * 2.5 / 4.095 * 0.5;
buffer[OFFSET_SOLAR_RAD_SP212 + dupn] = new Double(sid20_solar_rad_sp212);
buf[OFFSET_SOLAR_RAD_SP212 + dupn] = sid20_solar_rad_sp212;
count[OFFSET_SOLAR_RAD_SP212 + dupn]++;
logger.info("sid20_solar_rad_sp212: " + measure.format(sid20_solar_rad_sp212));
break;
case 12:
long battery_board_voltage_raw = reading[0] * 256 + reading[1];
//TODO: verify packet size (1 or 2 bytes)
sid12_battery_board_voltage = battery_board_voltage_raw * 6 * 2.5 / 4095;
buffer[OFFSET_BATTERY_BOARD_VOLTAGE + dupn] = new Double(sid12_battery_board_voltage);
buf[OFFSET_BATTERY_BOARD_VOLTAGE + dupn] = sid12_battery_board_voltage;
count[OFFSET_BATTERY_BOARD_VOLTAGE + dupn]++;
logger.info("sid12_battery_board_voltage: " + measure.format(sid12_battery_board_voltage));
break;
default:
logger.debug("Unknown SID:" + sid);
doPostStreamElement = false;
break;
} // switch
if (doPostStreamElement) {
aStreamElement = new StreamElement(outputStructureCache, buffer, timestamp * 1000);
//PublishBuffer(buffer, timestamp * 1000, stationID);
PublishPacketWithHistory(buffer, timestamp * 1000, stationID); // moving window of size 10, step 1
//PublishBufferNoMerge(buffer, timestamp * 1000, stationID);
// reset
for (int i = 0; i < OUTPUT_STRUCTURE_SIZE; i++) { // i=1 => don't reset SID
buffer[i] = null;
buf[i] = -1;
count[i] = 0;
}
}
return aStreamElement;
}
private void ExtractData() {
logger.info("\n\n ***** LOG DATA ***** \n\n");
logger.info(allBuffers.size() + " buffers to log");
for (int currentBuffer = 0; currentBuffer < allBuffers.size(); currentBuffer++) {
SensorScopeBuffer currentPacket = allBuffers.get(currentBuffer);
logger.info("[" + currentBuffer + "] " + currentPacket);
if (currentPacket.get(1) != PKT_TYPE_DATA || currentPacket.get(2) != DATA_TYPE_SENSING) {
logger.info("[" + currentBuffer + "] SKIPPED (not data packet or not sensing) ");
continue; //skip it
}
if (currentPacket.get(0) == 0 || currentPacket.get(0) >= currentPacket.getSize()) {
logger.error("Corrupted packet found (invalid packet length)");
continue; // skip it
//TODO: check whether all packets should be skipped or just current one
}
int[] dataPacket = currentPacket.getDataPacket();
interpretPacket(dataPacket);
}
}
private boolean CheckAuthentication(String passkey, int i, int i1, byte b, byte b1) {
return true; //TODO: implement authentication checking method
}
private byte[] toByteArray(int[] challenge) {
byte[] _array = new byte[challenge.length];
for (int i = 0; i < challenge.length; i++)
_array[i] = (byte) challenge[i];
return _array;
}
private void FillAuthChallenge(int[] challenge) {
long utc;
int crc;
// Packet size
challenge[0] = 24;
Random randomGenerator = new Random();
for (int i = 1; i < 17; ++i)
challenge[i] = randomGenerator.nextInt() & 0xff;
utc = System.currentTimeMillis() / 1000;
challenge[17] = (int) ((utc >> 24) & 0xFF);
challenge[18] = (int) ((utc >> 16) & 0xFF);
challenge[19] = (int) ((utc >> 8) & 0xFF);
challenge[20] = (int) (utc & 0xFF);
challenge[21] = 0;
challenge[22] = 0;
// CRC
int[] _challenge = new int[22];
System.arraycopy(challenge, 1, _challenge, 0, 22);
logger.info("* challenge *");
logger.info(Formatter.listArray(challenge, 24));
logger.info("* _challenge *");
logger.info(Formatter.listArray(_challenge, 22));
crc = Crc16(_challenge, 22);
challenge[23] = (crc >> 8) & 0xFF;
challenge[24] = crc & 0xFF;
}
int Crc16Byte(int crc, int _byte) {
crc = ((crc >> 8) & 0xFF) | (crc << 8);
crc ^= _byte;
crc ^= (crc & 0xFF) >> 4;
crc ^= crc << 12;
crc ^= (crc & 0xFF) << 5;
return crc;
}
int Crc16(int[] buffer, int len) {
int i;
int crc = 0;
for (i = 0; i < len; ++i)
crc = Crc16Byte(crc, buffer[i]);
return crc;
}
void CleanUp(String when) {
logger.error("Error while " + when);
try {
client.close();
} catch (IOException e) {
logger.warn(e.getMessage(), e);
}
}
public static void main(java.lang.String[] args) {
PropertyConfigurator.configure(CONF_LOG4J_SENSORSCOPE_PROPERTIES);
SensorScopeServerListener server = new SensorScopeServerListener();
logger.warn("Entering server mode...");
while (true) {
server.entry();
logger.warn("\n\n********************\n\n");
}
}
/*
* Encapsulates information about a sensorscope packet within a buffer
* */
public class PacketInfo {
public int packet;
public int length;
public PacketInfo() {
packet = 0;
length = 0;
}
public PacketInfo(int _packet, int _length) {
this.packet = _packet;
this.length = _length;
}
}
public class SensorScopeBuffer {
private int MAXIMUM_BUFFER_SIZE = 2048;
private int[] buffer;
private int size = 0;
SensorScopeBuffer() {
this.buffer = new int[MAXIMUM_BUFFER_SIZE];
}
SensorScopeBuffer(SensorScopeBuffer aSensorScopeBuffer) {
this.buffer = new int[MAXIMUM_BUFFER_SIZE];
this.size = aSensorScopeBuffer.size;
for (int i = 0; i < this.size; i++)
this.buffer[i] = aSensorScopeBuffer.buffer[i];
}
public void reset() {
this.size = 0;
}
public int[] getBuffer() {
return this.buffer;
}
public int get(int i) {
return this.buffer[i];
}
public int add(int value) {
this.buffer[this.size] = value;
return ++size;
}
public String toString() {
return Formatter.listArray(this.buffer, this.size);
}
public int getPacketSize() {
if (size > 0)
return this.buffer[0];
else
return 0;
}
public int[] getDataPacket() {
int dataPacketSize = this.size - 3;
int[] dataPacket = new int[dataPacketSize];
for (int i = 0; i < dataPacketSize; i++)
dataPacket[i] = this.buffer[i + 3];
return dataPacket;
}
public int getSize() {
return size;
}
}
}