Add pubsub client
This commit is contained in:
Submodule libraries/MySensors/drivers/pubsubclient deleted from 2f97e4a558
@@ -1,216 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Connect the MQ2 sensor as follows :
|
||||
*
|
||||
* A H A >>> 5V
|
||||
* B >>> A0
|
||||
* H >>> GND
|
||||
* B >>> 10K ohm >>> GND
|
||||
*
|
||||
* Contribution: epierre
|
||||
* Based on http://sandboxelectronics.com/?p=165
|
||||
* License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
|
||||
* Modified by HEK to work in 1.4
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define CHILD_ID_MQ 0
|
||||
/************************Hardware Related Macros************************************/
|
||||
#define MQ_SENSOR_ANALOG_PIN (0) //define which analog input channel you are going to use
|
||||
#define RL_VALUE (5) //define the load resistance on the board, in kilo ohms
|
||||
#define RO_CLEAN_AIR_FACTOR (9.83) //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO,
|
||||
//which is derived from the chart in datasheet
|
||||
/***********************Software Related Macros************************************/
|
||||
#define CALIBARAION_SAMPLE_TIMES (50) //define how many samples you are going to take in the calibration phase
|
||||
#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the
|
||||
//cablibration phase
|
||||
#define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation
|
||||
#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in
|
||||
//normal operation
|
||||
/**********************Application Related Macros**********************************/
|
||||
#define GAS_LPG (0)
|
||||
#define GAS_CO (1)
|
||||
#define GAS_SMOKE (2)
|
||||
/*****************************Globals***********************************************/
|
||||
unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
|
||||
//VARIABLES
|
||||
float Ro = 10000.0; // this has to be tuned 10K Ohm
|
||||
int val = 0; // variable to store the value coming from the sensor
|
||||
float valMQ =0.0;
|
||||
float lastMQ =0.0;
|
||||
float LPGCurve[3] = {2.3,0.21,-0.47}; //two points are taken from the curve.
|
||||
//with these two points, a line is formed which is "approximately equivalent"
|
||||
//to the original curve.
|
||||
//data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59)
|
||||
float COCurve[3] = {2.3,0.72,-0.34}; //two points are taken from the curve.
|
||||
//with these two points, a line is formed which is "approximately equivalent"
|
||||
//to the original curve.
|
||||
//data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15)
|
||||
float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from the curve.
|
||||
//with these two points, a line is formed which is "approximately equivalent"
|
||||
//to the original curve.
|
||||
//data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22)
|
||||
|
||||
|
||||
MyMessage msg(CHILD_ID_MQ, V_LEVEL);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Air Quality Sensor", "1.0");
|
||||
|
||||
// Register all sensors to gateway (they will be created as child devices)
|
||||
present(CHILD_ID_MQ, S_AIR_QUALITY);
|
||||
|
||||
Ro = MQCalibration(MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air
|
||||
//when you perform the calibration
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint16_t valMQ = MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO);
|
||||
Serial.println(val);
|
||||
|
||||
Serial.print("LPG:");
|
||||
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_LPG) );
|
||||
Serial.print( "ppm" );
|
||||
Serial.print(" ");
|
||||
Serial.print("CO:");
|
||||
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO) );
|
||||
Serial.print( "ppm" );
|
||||
Serial.print(" ");
|
||||
Serial.print("SMOKE:");
|
||||
Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_SMOKE) );
|
||||
Serial.print( "ppm" );
|
||||
Serial.print("\n");
|
||||
|
||||
if (valMQ != lastMQ) {
|
||||
send(msg.set((int)ceil(valMQ)));
|
||||
lastMQ = ceil(valMQ);
|
||||
}
|
||||
|
||||
sleep(SLEEP_TIME); //sleep for: sleepTime
|
||||
}
|
||||
|
||||
/****************** MQResistanceCalculation ****************************************
|
||||
Input: raw_adc - raw value read from adc, which represents the voltage
|
||||
Output: the calculated sensor resistance
|
||||
Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage
|
||||
across the load resistor and its resistance, the resistance of the sensor
|
||||
could be derived.
|
||||
************************************************************************************/
|
||||
float MQResistanceCalculation(int raw_adc)
|
||||
{
|
||||
return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));
|
||||
}
|
||||
|
||||
/***************************** MQCalibration ****************************************
|
||||
Input: mq_pin - analog channel
|
||||
Output: Ro of the sensor
|
||||
Remarks: This function assumes that the sensor is in clean air. It use
|
||||
MQResistanceCalculation to calculates the sensor resistance in clean air
|
||||
and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about
|
||||
10, which differs slightly between different sensors.
|
||||
************************************************************************************/
|
||||
float MQCalibration(int mq_pin)
|
||||
{
|
||||
int i;
|
||||
float val=0;
|
||||
|
||||
for (i=0;i<CALIBARAION_SAMPLE_TIMES;i++) { //take multiple samples
|
||||
val += MQResistanceCalculation(analogRead(mq_pin));
|
||||
delay(CALIBRATION_SAMPLE_INTERVAL);
|
||||
}
|
||||
val = val/CALIBARAION_SAMPLE_TIMES; //calculate the average value
|
||||
|
||||
val = val/RO_CLEAN_AIR_FACTOR; //divided by RO_CLEAN_AIR_FACTOR yields the Ro
|
||||
//according to the chart in the datasheet
|
||||
|
||||
return val;
|
||||
}
|
||||
/***************************** MQRead *********************************************
|
||||
Input: mq_pin - analog channel
|
||||
Output: Rs of the sensor
|
||||
Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
|
||||
The Rs changes as the sensor is in the different consentration of the target
|
||||
gas. The sample times and the time interval between samples could be configured
|
||||
by changing the definition of the macros.
|
||||
************************************************************************************/
|
||||
float MQRead(int mq_pin)
|
||||
{
|
||||
int i;
|
||||
float rs=0;
|
||||
|
||||
for (i=0;i<READ_SAMPLE_TIMES;i++) {
|
||||
rs += MQResistanceCalculation(analogRead(mq_pin));
|
||||
delay(READ_SAMPLE_INTERVAL);
|
||||
}
|
||||
|
||||
rs = rs/READ_SAMPLE_TIMES;
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
/***************************** MQGetGasPercentage **********************************
|
||||
Input: rs_ro_ratio - Rs divided by Ro
|
||||
gas_id - target gas type
|
||||
Output: ppm of the target gas
|
||||
Remarks: This function passes different curves to the MQGetPercentage function which
|
||||
calculates the ppm (parts per million) of the target gas.
|
||||
************************************************************************************/
|
||||
int MQGetGasPercentage(float rs_ro_ratio, int gas_id)
|
||||
{
|
||||
if ( gas_id == GAS_LPG ) {
|
||||
return MQGetPercentage(rs_ro_ratio,LPGCurve);
|
||||
} else if ( gas_id == GAS_CO ) {
|
||||
return MQGetPercentage(rs_ro_ratio,COCurve);
|
||||
} else if ( gas_id == GAS_SMOKE ) {
|
||||
return MQGetPercentage(rs_ro_ratio,SmokeCurve);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************** MQGetPercentage **********************************
|
||||
Input: rs_ro_ratio - Rs divided by Ro
|
||||
pcurve - pointer to the curve of the target gas
|
||||
Output: ppm of the target gas
|
||||
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
|
||||
of the line could be derived if y(rs_ro_ratio) is provided. As it is a
|
||||
logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
|
||||
value.
|
||||
************************************************************************************/
|
||||
int MQGetPercentage(float rs_ro_ratio, float *pcurve)
|
||||
{
|
||||
return (pow(10,( ((log(rs_ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])));
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This is an example that demonstrates how to report the battery level for a sensor
|
||||
* Instructions for measuring battery capacity on A0 are available here:
|
||||
* http://www.mysensors.org/build/battery
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point
|
||||
|
||||
unsigned long SLEEP_TIME = 900000; // sleep time between reads (seconds * 1000 milliseconds)
|
||||
int oldBatteryPcnt = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
// use the 1.1 V internal reference
|
||||
#if defined(__AVR_ATmega2560__)
|
||||
analogReference(INTERNAL1V1);
|
||||
#else
|
||||
analogReference(INTERNAL);
|
||||
#endif
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Battery Meter", "1.0");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// get the battery Voltage
|
||||
int sensorValue = analogRead(BATTERY_SENSE_PIN);
|
||||
#ifdef DEBUG
|
||||
Serial.println(sensorValue);
|
||||
#endif
|
||||
|
||||
// 1M, 470K divider across battery and using internal ADC ref of 1.1V
|
||||
// Sense point is bypassed with 0.1 uF cap to reduce noise at that point
|
||||
// ((1e6+470e3)/470e3)*1.1 = Vmax = 3.44 Volts
|
||||
// 3.44/1023 = Volts per bit = 0.003363075
|
||||
float batteryV = sensorValue * 0.003363075;
|
||||
int batteryPcnt = sensorValue / 10;
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print("Battery Voltage: ");
|
||||
Serial.print(batteryV);
|
||||
Serial.println(" V");
|
||||
|
||||
Serial.print("Battery percent: ");
|
||||
Serial.print(batteryPcnt);
|
||||
Serial.println(" %");
|
||||
#endif
|
||||
|
||||
if (oldBatteryPcnt != batteryPcnt) {
|
||||
// Power up radio after sleep
|
||||
sendBatteryLevel(batteryPcnt);
|
||||
oldBatteryPcnt = batteryPcnt;
|
||||
}
|
||||
sleep(SLEEP_TIME);
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Simple binary switch example
|
||||
* Connect button or door/window reed switch between
|
||||
* digitial I/O pin 3 (BUTTON_PIN below) and GND.
|
||||
* http://www.mysensors.org/build/binary
|
||||
*/
|
||||
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <Bounce2.h>
|
||||
|
||||
#define CHILD_ID 3
|
||||
#define BUTTON_PIN 3 // Arduino Digital I/O pin for button/reed switch
|
||||
|
||||
Bounce debouncer = Bounce();
|
||||
int oldValue=-1;
|
||||
|
||||
// Change to V_LIGHT if you use S_LIGHT in presentation below
|
||||
MyMessage msg(CHILD_ID,V_TRIPPED);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Setup the button
|
||||
pinMode(BUTTON_PIN,INPUT);
|
||||
// Activate internal pull-up
|
||||
digitalWrite(BUTTON_PIN,HIGH);
|
||||
|
||||
// After setting up the button, setup debouncer
|
||||
debouncer.attach(BUTTON_PIN);
|
||||
debouncer.interval(5);
|
||||
|
||||
// Register binary input sensor to gw (they will be created as child devices)
|
||||
// You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage.
|
||||
// If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
|
||||
present(CHILD_ID, S_DOOR);
|
||||
}
|
||||
|
||||
|
||||
// Check if digital input has changed and send in new value
|
||||
void loop()
|
||||
{
|
||||
debouncer.update();
|
||||
// Get the update value
|
||||
int value = debouncer.read();
|
||||
|
||||
if (value != oldValue) {
|
||||
// Send in the new value
|
||||
send(msg.set(value==HIGH ? 1 : 0));
|
||||
oldValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Interrupt driven binary switch example with dual interrupts
|
||||
* Author: Patrick 'Anticimex' Fallberg
|
||||
* Connect one button or door/window reed switch between
|
||||
* digitial I/O pin 3 (BUTTON_PIN below) and GND and the other
|
||||
* one in similar fashion on digital I/O pin 2.
|
||||
* This example is designed to fit Arduino Nano/Pro Mini
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define SKETCH_NAME "Binary Sensor"
|
||||
#define SKETCH_MAJOR_VER "1"
|
||||
#define SKETCH_MINOR_VER "0"
|
||||
|
||||
#define PRIMARY_CHILD_ID 3
|
||||
#define SECONDARY_CHILD_ID 4
|
||||
|
||||
#define PRIMARY_BUTTON_PIN 2 // Arduino Digital I/O pin for button/reed switch
|
||||
#define SECONDARY_BUTTON_PIN 3 // Arduino Digital I/O pin for button/reed switch
|
||||
|
||||
#if (PRIMARY_BUTTON_PIN < 2 || PRIMARY_BUTTON_PIN > 3)
|
||||
#error PRIMARY_BUTTON_PIN must be either 2 or 3 for interrupts to work
|
||||
#endif
|
||||
#if (SECONDARY_BUTTON_PIN < 2 || SECONDARY_BUTTON_PIN > 3)
|
||||
#error SECONDARY_BUTTON_PIN must be either 2 or 3 for interrupts to work
|
||||
#endif
|
||||
#if (PRIMARY_BUTTON_PIN == SECONDARY_BUTTON_PIN)
|
||||
#error PRIMARY_BUTTON_PIN and BUTTON_PIN2 cannot be the same
|
||||
#endif
|
||||
#if (PRIMARY_CHILD_ID == SECONDARY_CHILD_ID)
|
||||
#error PRIMARY_CHILD_ID and SECONDARY_CHILD_ID cannot be the same
|
||||
#endif
|
||||
|
||||
|
||||
// Change to V_LIGHT if you use S_LIGHT in presentation below
|
||||
MyMessage msg(PRIMARY_CHILD_ID, V_TRIPPED);
|
||||
MyMessage msg2(SECONDARY_CHILD_ID, V_TRIPPED);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Setup the buttons
|
||||
pinMode(PRIMARY_BUTTON_PIN, INPUT);
|
||||
pinMode(SECONDARY_BUTTON_PIN, INPUT);
|
||||
|
||||
// Activate internal pull-ups
|
||||
digitalWrite(PRIMARY_BUTTON_PIN, HIGH);
|
||||
digitalWrite(SECONDARY_BUTTON_PIN, HIGH);
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER "." SKETCH_MINOR_VER);
|
||||
|
||||
// Register binary input sensor to sensor_node (they will be created as child devices)
|
||||
// You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage.
|
||||
// If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
|
||||
present(PRIMARY_CHILD_ID, S_DOOR);
|
||||
present(SECONDARY_CHILD_ID, S_DOOR);
|
||||
}
|
||||
|
||||
// Loop will iterate on changes on the BUTTON_PINs
|
||||
void loop()
|
||||
{
|
||||
uint8_t value;
|
||||
static uint8_t sentValue=2;
|
||||
static uint8_t sentValue2=2;
|
||||
|
||||
// Short delay to allow buttons to properly settle
|
||||
sleep(5);
|
||||
|
||||
value = digitalRead(PRIMARY_BUTTON_PIN);
|
||||
|
||||
if (value != sentValue) {
|
||||
// Value has changed from last transmission, send the updated value
|
||||
send(msg.set(value==HIGH ? 1 : 0));
|
||||
sentValue = value;
|
||||
}
|
||||
|
||||
value = digitalRead(SECONDARY_BUTTON_PIN);
|
||||
|
||||
if (value != sentValue2) {
|
||||
// Value has changed from last transmission, send the updated value
|
||||
send(msg2.set(value==HIGH ? 1 : 0));
|
||||
sentValue2 = value;
|
||||
}
|
||||
|
||||
// Sleep until something happens with the sensor
|
||||
sleep(PRIMARY_BUTTON_PIN-2, CHANGE, SECONDARY_BUTTON_PIN-2, CHANGE, 0);
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* MH-Z14 CO2 sensor
|
||||
*
|
||||
* Wiring:
|
||||
* Pad 1, Pad 5: Vin (Voltage input 4.5V-6V)
|
||||
* Pad 2, Pad 3, Pad 12: GND
|
||||
* Pad 6: PWM output ==> pin 6
|
||||
*
|
||||
* From: http://davidegironi.blogspot.fr/2014/01/co2-meter-using-ndir-infrared-mh-z14.html
|
||||
* MH-Z14 has a PWM output, with a sensitivity range of 0ppm to 2000ppm CO2, an accurancy of ±200ppm.
|
||||
* The cycle is 1004ms±5%, given the duty cicle Th (pulse high), Tl is 1004-Th, we can convert it to CO2 value using the formula:
|
||||
* CO2ppm = 2000 * (Th - 2ms) /(Th + Tl - 4ms)
|
||||
* From: http://airqualityegg.wikispaces.com/Sensor+Tests
|
||||
* - response time is less than 30 s
|
||||
* - 3 minute warm up time
|
||||
* datasheet: http://www.futurlec.com/Datasheet/Sensor/MH-Z14.pdf
|
||||
* Contributor: epierre
|
||||
**/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define CHILD_ID_AIQ 0
|
||||
#define AIQ_SENSOR_ANALOG_PIN 6
|
||||
|
||||
unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds)
|
||||
|
||||
float valAIQ =0.0;
|
||||
float lastAIQ =0.0;
|
||||
|
||||
MyMessage msg(CHILD_ID_AIQ, V_LEVEL);
|
||||
MyMessage msg2(CHILD_ID_AIQ, V_UNIT_PREFIX);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("AIQ Sensor CO2 MH-Z14", "1.0");
|
||||
|
||||
// Register all sensors to gateway (they will be created as child devices)
|
||||
present(CHILD_ID_AIQ, S_AIR_QUALITY);
|
||||
send(msg2.set("ppm"));
|
||||
|
||||
sleep(SLEEP_TIME);
|
||||
|
||||
pinMode(AIQ_SENSOR_ANALOG_PIN, INPUT);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
//unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH);
|
||||
while(digitalRead(AIQ_SENSOR_ANALOG_PIN) == HIGH) {;}
|
||||
//wait for the pin to go HIGH and measure HIGH time
|
||||
unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH);
|
||||
|
||||
//Serial.print(duration/1000); Serial.println(" ms ");
|
||||
//from datasheet
|
||||
//CO2 ppm = 2000 * (Th - 2ms) / (Th + Tl - 4ms)
|
||||
// given Tl + Th = 1004
|
||||
// Tl = 1004 - Th
|
||||
// = 2000 * (Th - 2ms) / (Th + 1004 - Th -4ms)
|
||||
// = 2000 * (Th - 2ms) / 1000 = 2 * (Th - 2ms)
|
||||
long co2ppm = 2 * ((duration/1000) - 2);
|
||||
//Serial.print(co2ppm);
|
||||
if ((co2ppm != lastAIQ)&&(abs(co2ppm-lastAIQ)>=10)) {
|
||||
send(msg.set((long)ceil(co2ppm)));
|
||||
lastAIQ = ceil(co2ppm);
|
||||
}
|
||||
|
||||
//Serial.println();
|
||||
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
sleep(SLEEP_TIME); //sleep for: sleepTime
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This sketch clears radioId, relayId and other routing information in EEPROM back to factory default
|
||||
*
|
||||
*/
|
||||
|
||||
#include <MyConfig.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(MY_BAUD_RATE);
|
||||
Serial.println("Started clearing. Please wait...");
|
||||
for (int i=0;i<512;i++) {
|
||||
EEPROM.write(i, 0xff);
|
||||
}
|
||||
Serial.println("Clering done. You're ready to go!");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Nothing to do here...
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Example sketch showing how to send in DS1820B OneWire temperature readings back to the controller
|
||||
* http://www.mysensors.org/build/temp
|
||||
*/
|
||||
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <DallasTemperature.h>
|
||||
#include <OneWire.h>
|
||||
|
||||
#define COMPARE_TEMP 1 // Send temperature only if changed? 1 = Yes 0 = No
|
||||
|
||||
#define ONE_WIRE_BUS 3 // Pin where dallase sensor is connected
|
||||
#define MAX_ATTACHED_DS18B20 16
|
||||
unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
|
||||
OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
|
||||
DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature.
|
||||
float lastTemperature[MAX_ATTACHED_DS18B20];
|
||||
int numSensors=0;
|
||||
boolean receivedConfig = false;
|
||||
boolean metric = true;
|
||||
// Initialize temperature message
|
||||
MyMessage msg(0,V_TEMP);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Startup up the OneWire library
|
||||
sensors.begin();
|
||||
// requestTemperatures() will not block current thread
|
||||
sensors.setWaitForConversion(false);
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Temperature Sensor", "1.1");
|
||||
|
||||
// Fetch the number of attached temperature sensors
|
||||
numSensors = sensors.getDeviceCount();
|
||||
|
||||
// Present all sensors to controller
|
||||
for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {
|
||||
present(i, S_TEMP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Fetch temperatures from Dallas sensors
|
||||
sensors.requestTemperatures();
|
||||
|
||||
// query conversion time and sleep until conversion completed
|
||||
int16_t conversionTime = sensors.millisToWaitForConversion(sensors.getResolution());
|
||||
// sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater)
|
||||
sleep(conversionTime);
|
||||
|
||||
// Read temperatures and send them to controller
|
||||
for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) {
|
||||
|
||||
// Fetch and round temperature to one decimal
|
||||
float temperature = static_cast<float>(static_cast<int>((getConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.;
|
||||
|
||||
// Only send data if temperature has changed and no error
|
||||
#if COMPARE_TEMP == 1
|
||||
if (lastTemperature[i] != temperature && temperature != -127.00 && temperature != 85.00) {
|
||||
#else
|
||||
if (temperature != -127.00 && temperature != 85.00) {
|
||||
#endif
|
||||
|
||||
// Send in the new temperature
|
||||
send(msg.setSensor(i).set(temperature,1));
|
||||
// Save new temperatures for next compare
|
||||
lastTemperature[i]=temperature;
|
||||
}
|
||||
}
|
||||
sleep(SLEEP_TIME);
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - February 15, 2014 - Bruce Lacey
|
||||
* Version 1.1 - August 13, 2014 - Converted to 1.4 (hek)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This sketch provides a Dimmable LED Light using PWM and based Henrik Ekblad
|
||||
* <henrik.ekblad@gmail.com> Vera Arduino Sensor project.
|
||||
* Developed by Bruce Lacey, inspired by Hek's MySensor's example sketches.
|
||||
*
|
||||
* The circuit uses a MOSFET for Pulse-Wave-Modulation to dim the attached LED or LED strip.
|
||||
* The MOSFET Gate pin is connected to Arduino pin 3 (LED_PIN), the MOSFET Drain pin is connected
|
||||
* to the LED negative terminal and the MOSFET Source pin is connected to ground.
|
||||
*
|
||||
* This sketch is extensible to support more than one MOSFET/PWM dimmer per circuit.
|
||||
* http://www.mysensors.org/build/dimmer
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define SN "DimmableLED"
|
||||
#define SV "1.1"
|
||||
|
||||
#define LED_PIN 3 // Arduino pin attached to MOSFET Gate pin
|
||||
#define FADE_DELAY 10 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
|
||||
|
||||
static int currentLevel = 0; // Current dim level...
|
||||
MyMessage dimmerMsg(0, V_DIMMER);
|
||||
MyMessage lightMsg(0, V_LIGHT);
|
||||
|
||||
|
||||
/***
|
||||
* Dimmable LED initialization method
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
// Initialize library and add callback for incoming messages (signing is required)
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
// Register the LED Dimmable Light with the gateway
|
||||
present( 0, S_DIMMER );
|
||||
|
||||
sendSketchInfo(SN, SV);
|
||||
// Pull the gateway's current dim level - restore light level upon sendor node power-up
|
||||
request( 0, V_DIMMER );
|
||||
}
|
||||
|
||||
/***
|
||||
* Dimmable LED main processing loop
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
if (message.type == V_LIGHT || message.type == V_DIMMER) {
|
||||
|
||||
// Retrieve the power or dim level from the incoming request message
|
||||
int requestedLevel = atoi( message.data );
|
||||
|
||||
// Adjust incoming level if this is a V_LIGHT variable update [0 == off, 1 == on]
|
||||
requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 );
|
||||
|
||||
// Clip incoming level to valid range of 0 to 100
|
||||
requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
|
||||
requestedLevel = requestedLevel < 0 ? 0 : requestedLevel;
|
||||
|
||||
Serial.print( "Changing level to " );
|
||||
Serial.print( requestedLevel );
|
||||
Serial.print( ", from " );
|
||||
Serial.println( currentLevel );
|
||||
|
||||
fadeToLevel( requestedLevel );
|
||||
|
||||
// Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
|
||||
send(lightMsg.set(currentLevel > 0 ? 1 : 0));
|
||||
|
||||
// hek comment: Is this really nessesary?
|
||||
send( dimmerMsg.set(currentLevel) );
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* This method provides a graceful fade up/down effect
|
||||
*/
|
||||
void fadeToLevel( int toLevel ) {
|
||||
|
||||
int delta = ( toLevel - currentLevel ) < 0 ? -1 : 1;
|
||||
|
||||
while ( currentLevel != toLevel ) {
|
||||
currentLevel += delta;
|
||||
analogWrite( LED_PIN, (int)(currentLevel / 100. * 255) );
|
||||
delay( FADE_DELAY );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - January 30, 2015 - Developed by GizMoCuz (Domoticz)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This sketch provides an example how to implement a Dimmable Light
|
||||
* It is pure virtual and it logs messages to the serial output
|
||||
* It can be used as a base sketch for actual hardware.
|
||||
* Stores the last light state and level in eeprom.
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable debug prints
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define CHILD_ID_LIGHT 1
|
||||
|
||||
#define EPROM_LIGHT_STATE 1
|
||||
#define EPROM_DIMMER_LEVEL 2
|
||||
|
||||
#define LIGHT_OFF 0
|
||||
#define LIGHT_ON 1
|
||||
|
||||
#define SN "Dimable Light"
|
||||
#define SV "1.0"
|
||||
|
||||
int LastLightState=LIGHT_OFF;
|
||||
int LastDimValue=100;
|
||||
|
||||
MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT);
|
||||
MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Initialize library and add callback for incoming messages (signing is required)
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
// Send the Sketch Version Information to the Gateway
|
||||
sendSketchInfo(SN, SV);
|
||||
|
||||
present(CHILD_ID_LIGHT, S_DIMMER );
|
||||
|
||||
//Retreive our last light state from the eprom
|
||||
int LightState=loadState(EPROM_LIGHT_STATE);
|
||||
if (LightState<=1) {
|
||||
LastLightState=LightState;
|
||||
int DimValue=loadState(EPROM_DIMMER_LEVEL);
|
||||
if ((DimValue>0)&&(DimValue<=100)) {
|
||||
//There should be no Dim value of 0, this would mean LIGHT_OFF
|
||||
LastDimValue=DimValue;
|
||||
}
|
||||
}
|
||||
|
||||
//Here you actualy switch on/off the light with the last known dim level
|
||||
SetCurrentState2Hardware();
|
||||
|
||||
Serial.println( "Node ready to receive messages..." );
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message)
|
||||
{
|
||||
if (message.type == V_LIGHT) {
|
||||
Serial.println( "V_LIGHT command received..." );
|
||||
|
||||
int lstate= atoi( message.data );
|
||||
if ((lstate<0)||(lstate>1)) {
|
||||
Serial.println( "V_LIGHT data invalid (should be 0/1)" );
|
||||
return;
|
||||
}
|
||||
LastLightState=lstate;
|
||||
saveState(EPROM_LIGHT_STATE, LastLightState);
|
||||
|
||||
if ((LastLightState==LIGHT_ON)&&(LastDimValue==0)) {
|
||||
//In the case that the Light State = On, but the dimmer value is zero,
|
||||
//then something (probably the controller) did something wrong,
|
||||
//for the Dim value to 100%
|
||||
LastDimValue=100;
|
||||
saveState(EPROM_DIMMER_LEVEL, LastDimValue);
|
||||
}
|
||||
|
||||
//When receiving a V_LIGHT command we switch the light between OFF and the last received dimmer value
|
||||
//This means if you previously set the lights dimmer value to 50%, and turn the light ON
|
||||
//it will do so at 50%
|
||||
}
|
||||
else if (message.type == V_DIMMER) {
|
||||
Serial.println( "V_DIMMER command received..." );
|
||||
int dimvalue= atoi( message.data );
|
||||
if ((dimvalue<0)||(dimvalue>100)) {
|
||||
Serial.println( "V_DIMMER data invalid (should be 0..100)" );
|
||||
return;
|
||||
}
|
||||
if (dimvalue==0) {
|
||||
LastLightState=LIGHT_OFF;
|
||||
}
|
||||
else {
|
||||
LastLightState=LIGHT_ON;
|
||||
LastDimValue=dimvalue;
|
||||
saveState(EPROM_DIMMER_LEVEL, LastDimValue);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Serial.println( "Invalid command received..." );
|
||||
return;
|
||||
}
|
||||
|
||||
//Here you set the actual light state/level
|
||||
SetCurrentState2Hardware();
|
||||
}
|
||||
|
||||
void SetCurrentState2Hardware()
|
||||
{
|
||||
if (LastLightState==LIGHT_OFF) {
|
||||
Serial.println( "Light state: OFF" );
|
||||
}
|
||||
else {
|
||||
Serial.print( "Light state: ON, Level: " );
|
||||
Serial.println( LastDimValue );
|
||||
}
|
||||
|
||||
//Send current state to the controller
|
||||
SendCurrentState2Controller();
|
||||
}
|
||||
|
||||
void SendCurrentState2Controller()
|
||||
{
|
||||
if ((LastLightState==LIGHT_OFF)||(LastDimValue==0)) {
|
||||
send(dimmerMsg.set(0));
|
||||
}
|
||||
else {
|
||||
send(dimmerMsg.set(LastDimValue));
|
||||
}
|
||||
}
|
||||
|
||||
-240
@@ -1,240 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Developed by Bruce Lacey and GizMoCuz (Domoticz)
|
||||
* Version 1.1 - Modified by hek to incorporate a rotary encode to adjust
|
||||
* light level locally at node
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This sketch provides an example how to implement a dimmable led light node with a rotary
|
||||
* encoder connected for adjusting light level.
|
||||
* The encoder has a click button which turns on/off the light (and remembers last dim-level)
|
||||
* The sketch fades the light (non-blocking) to the desired level.
|
||||
*
|
||||
* Default MOSFET pin is 3
|
||||
*
|
||||
* Arduino Encoder module
|
||||
* ---------------------------
|
||||
* 5V 5V (+)
|
||||
* GND GND (-)
|
||||
* 4 CLK (or putput 1)
|
||||
* 5 DT (or output 1)
|
||||
* 6 SW (Switch/Click)
|
||||
*/
|
||||
|
||||
|
||||
// Enable debug prints
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <Bounce2.h>
|
||||
#include <Encoder.h>
|
||||
|
||||
#define LED_PIN 3 // Arduino pin attached to MOSFET Gate pin
|
||||
#define KNOB_ENC_PIN_1 4 // Rotary encoder input pin 1
|
||||
#define KNOB_ENC_PIN_2 5 // Rotary encoder input pin 2
|
||||
#define KNOB_BUTTON_PIN 6 // Rotary encoder button pin
|
||||
#define FADE_DELAY 10 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
|
||||
#define SEND_THROTTLE_DELAY 400 // Number of milliseconds before sending after user stops turning knob
|
||||
#define SN "DimmableLED /w button"
|
||||
#define SV "1.2"
|
||||
|
||||
#define CHILD_ID_LIGHT 1
|
||||
|
||||
#define EEPROM_DIM_LEVEL_LAST 1
|
||||
#define EEPROM_DIM_LEVEL_SAVE 2
|
||||
|
||||
#define LIGHT_OFF 0
|
||||
#define LIGHT_ON 1
|
||||
|
||||
int dimValue;
|
||||
int fadeTo;
|
||||
int fadeDelta;
|
||||
byte oldButtonVal;
|
||||
bool changedByKnob=false;
|
||||
bool sendDimValue=false;
|
||||
unsigned long lastFadeStep;
|
||||
unsigned long sendDimTimeout;
|
||||
char convBuffer[10];
|
||||
|
||||
MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER);
|
||||
Encoder knob(KNOB_ENC_PIN_1, KNOB_ENC_PIN_2);
|
||||
Bounce debouncer = Bounce();
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Initialize library and add callback for incoming messages (signing is required)
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
// Set knob button pin as input (with debounce)
|
||||
pinMode(KNOB_BUTTON_PIN, INPUT);
|
||||
digitalWrite(KNOB_BUTTON_PIN, HIGH);
|
||||
debouncer.attach(KNOB_BUTTON_PIN);
|
||||
debouncer.interval(5);
|
||||
oldButtonVal = debouncer.read();
|
||||
|
||||
// Set analog led pin to off
|
||||
analogWrite( LED_PIN, 0);
|
||||
|
||||
// Send the Sketch Version Information to the Gateway
|
||||
present(CHILD_ID_LIGHT, S_DIMMER);
|
||||
sendSketchInfo(SN, SV);
|
||||
|
||||
// Retreive our last dim levels from the eprom
|
||||
fadeTo = dimValue = 0;
|
||||
byte oldLevel = loadLevelState(EEPROM_DIM_LEVEL_LAST);
|
||||
Serial.print("Sending in last known light level to controller: ");
|
||||
Serial.println(oldLevel);
|
||||
send(dimmerMsg.set(oldLevel), true);
|
||||
|
||||
Serial.println("Ready to receive messages...");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Check if someone turned the rotary encode
|
||||
checkRotaryEncoder();
|
||||
|
||||
// Check if someone has pressed the knob button
|
||||
checkButtonClick();
|
||||
|
||||
// Fade light to new dim value
|
||||
fadeStep();
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message)
|
||||
{
|
||||
if (message.type == V_LIGHT) {
|
||||
// Incoming on/off command sent from controller ("1" or "0")
|
||||
int lightState = message.getString()[0] == '1';
|
||||
int newLevel = 0;
|
||||
if (lightState==LIGHT_ON) {
|
||||
// Pick up last saved dimmer level from the eeprom
|
||||
newLevel = loadLevelState(EEPROM_DIM_LEVEL_SAVE);
|
||||
}
|
||||
// Send dimmer level back to controller with ack enabled
|
||||
send(dimmerMsg.set(newLevel), true);
|
||||
// We do not change any levels here until ack comes back from gateway
|
||||
return;
|
||||
} else if (message.type == V_DIMMER) {
|
||||
// Incoming dim-level command sent from controller (or ack message)
|
||||
fadeTo = atoi(message.getString(convBuffer));
|
||||
// Save received dim value to eeprom (unless turned off). Will be
|
||||
// retreived when a on command comes in
|
||||
if (fadeTo != 0)
|
||||
saveLevelState(EEPROM_DIM_LEVEL_SAVE, fadeTo);
|
||||
}
|
||||
saveLevelState(EEPROM_DIM_LEVEL_LAST, fadeTo);
|
||||
|
||||
Serial.print("New light level received: ");
|
||||
Serial.println(fadeTo);
|
||||
|
||||
if (!changedByKnob)
|
||||
knob.write(fadeTo);
|
||||
|
||||
// Cancel send if user turns knob while message comes in
|
||||
changedByKnob = false;
|
||||
sendDimValue = false;
|
||||
|
||||
// Stard fading to new light level
|
||||
startFade();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void checkRotaryEncoder() {
|
||||
long encoderValue = knob.read();
|
||||
|
||||
if (encoderValue > 100) {
|
||||
encoderValue = 100;
|
||||
knob.write(100);
|
||||
} else if (encoderValue < 0) {
|
||||
encoderValue = 0;
|
||||
knob.write(0);
|
||||
}
|
||||
|
||||
if (encoderValue != fadeTo) {
|
||||
fadeTo = encoderValue;
|
||||
changedByKnob = true;
|
||||
startFade();
|
||||
}
|
||||
}
|
||||
|
||||
void checkButtonClick() {
|
||||
debouncer.update();
|
||||
byte buttonVal = debouncer.read();
|
||||
byte newLevel = 0;
|
||||
if (buttonVal != oldButtonVal && buttonVal == LOW) {
|
||||
if (dimValue==0) {
|
||||
// Turn on light. Set the level to last saved dim value
|
||||
int saved = loadLevelState(EEPROM_DIM_LEVEL_SAVE);
|
||||
newLevel = saved > 0 ? saved : 100;
|
||||
}
|
||||
send(dimmerMsg.set(newLevel),true);
|
||||
}
|
||||
oldButtonVal = buttonVal;
|
||||
}
|
||||
|
||||
void startFade() {
|
||||
fadeDelta = ( fadeTo - dimValue ) < 0 ? -1 : 1;
|
||||
lastFadeStep = millis();
|
||||
}
|
||||
|
||||
// This method provides a graceful none-blocking fade up/down effect
|
||||
void fadeStep() {
|
||||
unsigned long currentTime = millis();
|
||||
if ( dimValue != fadeTo && currentTime > lastFadeStep + FADE_DELAY) {
|
||||
dimValue += fadeDelta;
|
||||
analogWrite( LED_PIN, (int)(dimValue / 100. * 255) );
|
||||
lastFadeStep = currentTime;
|
||||
|
||||
Serial.print("Fading level: ");
|
||||
Serial.println(dimValue);
|
||||
|
||||
if (fadeTo == dimValue && changedByKnob) {
|
||||
sendDimValue = true;
|
||||
sendDimTimeout = currentTime;
|
||||
}
|
||||
}
|
||||
// Wait a few millisecs before sending in new value (if user still turns the knob)
|
||||
if (sendDimValue && currentTime > sendDimTimeout + SEND_THROTTLE_DELAY) {
|
||||
// We're done fading.. send in new dim-value to controller.
|
||||
// Send in new dim value with ack (will be picked up in incomingMessage)
|
||||
send(dimmerMsg.set(dimValue), true); // Send new dimmer value and request ack back
|
||||
sendDimValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure only to store/fetch values in the range 0-100 from eeprom
|
||||
int loadLevelState(byte pos) {
|
||||
return min(max(loadState(pos),0),100);
|
||||
}
|
||||
void saveLevelState(byte pos, byte data) {
|
||||
saveState(pos,min(max(data,0),100));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik EKblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This sketch provides an example how to implement a distance sensor using HC-SR04
|
||||
* http://www.mysensors.org/build/distance
|
||||
*/
|
||||
|
||||
// Enable debug prints
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <NewPing.h>
|
||||
|
||||
#define CHILD_ID 1
|
||||
#define TRIGGER_PIN 6 // Arduino pin tied to trigger pin on the ultrasonic sensor.
|
||||
#define ECHO_PIN 5 // Arduino pin tied to echo pin on the ultrasonic sensor.
|
||||
#define MAX_DISTANCE 300 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
|
||||
unsigned long SLEEP_TIME = 5000; // Sleep time between reads (in milliseconds)
|
||||
|
||||
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
|
||||
MyMessage msg(CHILD_ID, V_DISTANCE);
|
||||
int lastDist;
|
||||
boolean metric = true;
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Distance Sensor", "1.0");
|
||||
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
present(CHILD_ID, S_DISTANCE);
|
||||
metric = getConfig().isMetric;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
int dist = metric?sonar.ping_cm():sonar.ping_in();
|
||||
Serial.print("Ping: ");
|
||||
Serial.print(dist); // Convert ping time to distance in cm and print result (0 = outside set distance range)
|
||||
Serial.println(metric?" cm":" in");
|
||||
|
||||
if (dist != lastDist) {
|
||||
send(msg.set(dist));
|
||||
lastDist = dist;
|
||||
}
|
||||
|
||||
sleep(SLEEP_TIME);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - epierre
|
||||
* Converted to 1.4 by Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Arduino Dust Sensort
|
||||
*
|
||||
* connect the sensor as follows :
|
||||
*
|
||||
* VCC >>> 5V
|
||||
* A >>> A0
|
||||
* GND >>> GND
|
||||
*
|
||||
* Based on: http://www.dfrobot.com/wiki/index.php/Sharp_GP2Y1010AU
|
||||
* Authors: Cyrille Médard de Chardon (serialC), Christophe Trefois (Trefex)
|
||||
*
|
||||
* http://www.mysensors.org/build/dust
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable debug prints
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define CHILD_ID_DUST 0
|
||||
#define DUST_SENSOR_ANALOG_PIN 1
|
||||
|
||||
unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds)
|
||||
//VARIABLES
|
||||
int val = 0; // variable to store the value coming from the sensor
|
||||
float valDUST =0.0;
|
||||
float lastDUST =0.0;
|
||||
int samplingTime = 280;
|
||||
int deltaTime = 40;
|
||||
int sleepTime = 9680;
|
||||
float voMeasured = 0;
|
||||
float calcVoltage = 0;
|
||||
float dustDensity = 0;
|
||||
|
||||
MyMessage dustMsg(CHILD_ID_DUST, V_LEVEL);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Dust Sensor", "1.1");
|
||||
|
||||
// Register all sensors to gateway (they will be created as child devices)
|
||||
present(CHILD_ID_DUST, S_DUST);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint16_t voMeasured = analogRead(DUST_SENSOR_ANALOG_PIN);// Get DUST value
|
||||
|
||||
// 0 - 5V mapped to 0 - 1023 integer values
|
||||
// recover voltage
|
||||
calcVoltage = voMeasured * (5.0 / 1024.0);
|
||||
|
||||
// linear eqaution taken from http://www.howmuchsnow.com/arduino/airquality/
|
||||
// Chris Nafis (c) 2012
|
||||
dustDensity = (0.17 * calcVoltage - 0.1)*1000;
|
||||
|
||||
Serial.print("Raw Signal Value (0-1023): ");
|
||||
Serial.print(voMeasured);
|
||||
|
||||
Serial.print(" - Voltage: ");
|
||||
Serial.print(calcVoltage);
|
||||
|
||||
Serial.print(" - Dust Density: ");
|
||||
Serial.println(dustDensity); // unit: ug/m3
|
||||
|
||||
if (ceil(dustDensity) != lastDUST) {
|
||||
send(dustMsg.set((int)ceil(dustDensity)));
|
||||
lastDUST = ceil(dustDensity);
|
||||
}
|
||||
|
||||
sleep(SLEEP_TIME);
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Dust Sensor for SamYoung DSM501
|
||||
* connect the sensor as follows :
|
||||
* Pin 2 of dust sensor PM1 -> Digital 3 (PMW)
|
||||
* Pin 3 of dust sensor -> +5V
|
||||
* Pin 4 of dust sensor PM2.5 -> Digital 6 (PWM)
|
||||
* Pin 5 of dust sensor -> Ground
|
||||
* Datasheet: http://www.samyoungsnc.com/products/3-1%20Specification%20DSM501.pdf
|
||||
* Contributor: epierre
|
||||
**/
|
||||
|
||||
// Enable debug prints
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define CHILD_ID_DUST_PM10 0
|
||||
#define CHILD_ID_DUST_PM25 1
|
||||
#define DUST_SENSOR_DIGITAL_PIN_PM10 6
|
||||
#define DUST_SENSOR_DIGITAL_PIN_PM25 3
|
||||
|
||||
unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds)
|
||||
//VARIABLES
|
||||
int val = 0; // variable to store the value coming from the sensor
|
||||
float valDUSTPM25 =0.0;
|
||||
float lastDUSTPM25 =0.0;
|
||||
float valDUSTPM10 =0.0;
|
||||
float lastDUSTPM10 =0.0;
|
||||
unsigned long duration;
|
||||
unsigned long starttime;
|
||||
unsigned long endtime;
|
||||
unsigned long sampletime_ms = 30000;
|
||||
unsigned long lowpulseoccupancy = 0;
|
||||
float ratio = 0;
|
||||
long concentrationPM25 = 0;
|
||||
long concentrationPM10 = 0;
|
||||
|
||||
MyMessage dustMsgPM10(CHILD_ID_DUST_PM10, V_LEVEL);
|
||||
MyMessage msgPM10(CHILD_ID_DUST_PM10, V_UNIT_PREFIX);
|
||||
MyMessage dustMsgPM25(CHILD_ID_DUST_PM25, V_LEVEL);
|
||||
MyMessage msgPM25(CHILD_ID_DUST_PM25, V_UNIT_PREFIX);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Dust Sensor DSM501", "1.4");
|
||||
|
||||
// Register all sensors to gateway (they will be created as child devices)
|
||||
present(CHILD_ID_DUST_PM10, S_DUST);
|
||||
send(msgPM10.set("ppm"));
|
||||
present(CHILD_ID_DUST_PM25, S_DUST);
|
||||
send(msgPM25.set("ppm"));
|
||||
|
||||
pinMode(DUST_SENSOR_DIGITAL_PIN_PM10,INPUT);
|
||||
pinMode(DUST_SENSOR_DIGITAL_PIN_PM25,INPUT);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
//get PM 2.5 density of particles over 2.5 μm.
|
||||
concentrationPM25=(long)getPM(DUST_SENSOR_DIGITAL_PIN_PM25);
|
||||
Serial.print("PM25: ");
|
||||
Serial.println(concentrationPM25);
|
||||
Serial.print("\n");
|
||||
|
||||
if ((concentrationPM25 != lastDUSTPM25)&&(concentrationPM25>0)) {
|
||||
send(dustMsgPM25.set((long)ceil(concentrationPM25)));
|
||||
lastDUSTPM25 = ceil(concentrationPM25);
|
||||
}
|
||||
|
||||
//get PM 1.0 - density of particles over 1 μm.
|
||||
concentrationPM10=getPM(DUST_SENSOR_DIGITAL_PIN_PM10);
|
||||
Serial.print("PM10: ");
|
||||
Serial.println(concentrationPM10);
|
||||
Serial.print("\n");
|
||||
//ppmv=mg/m3 * (0.08205*Tmp)/Molecular_mass
|
||||
//0.08205 = Universal gas constant in atm·m3/(kmol·K)
|
||||
int temp=20; //external temperature, if you can replace this with a DHT11 or better
|
||||
long ppmv=(concentrationPM10*0.0283168/100/1000) * (0.08205*temp)/0.01;
|
||||
|
||||
if ((ceil(concentrationPM10) != lastDUSTPM10)&&((long)concentrationPM10>0)) {
|
||||
send(dustMsgPM10.set((long)ppmv));
|
||||
lastDUSTPM10 = ceil(concentrationPM10);
|
||||
}
|
||||
|
||||
//sleep to save on radio
|
||||
sleep(SLEEP_TIME);
|
||||
|
||||
}
|
||||
|
||||
|
||||
long getPM(int DUST_SENSOR_DIGITAL_PIN) {
|
||||
|
||||
starttime = millis();
|
||||
|
||||
while (1) {
|
||||
|
||||
duration = pulseIn(DUST_SENSOR_DIGITAL_PIN, LOW);
|
||||
lowpulseoccupancy += duration;
|
||||
endtime = millis();
|
||||
|
||||
if ((endtime-starttime) > sampletime_ms)
|
||||
{
|
||||
ratio = (lowpulseoccupancy-endtime+starttime)/(sampletime_ms*10.0); // Integer percentage 0=>100
|
||||
long concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve
|
||||
//Serial.print("lowpulseoccupancy:");
|
||||
//Serial.print(lowpulseoccupancy);
|
||||
//Serial.print("\n");
|
||||
//Serial.print("ratio:");
|
||||
//Serial.print(ratio);
|
||||
//Serial.print("\n");
|
||||
//Serial.print("DSM501A:");
|
||||
//Serial.println(concentration);
|
||||
//Serial.print("\n");
|
||||
|
||||
lowpulseoccupancy = 0;
|
||||
return(concentration);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik EKblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This sketch provides an example how to implement a distance sensor using HC-SR04
|
||||
* Use this sensor to measure KWH and Watt of your house meeter
|
||||
* You need to set the correct pulsefactor of your meeter (blinks per KWH).
|
||||
* The sensor starts by fetching current KWH value from gateway.
|
||||
* Reports both KWH and Watt back to gateway.
|
||||
*
|
||||
* Unfortunately millis() won't increment when the Arduino is in
|
||||
* sleepmode. So we cannot make this sensor sleep if we also want
|
||||
* to calculate/report watt-number.
|
||||
* http://www.mysensors.org/build/pulse_power
|
||||
*/
|
||||
|
||||
// Enable debug prints
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your light sensor. (Only 2 and 3 generates interrupt!)
|
||||
#define PULSE_FACTOR 1000 // Nummber of blinks per KWH of your meeter
|
||||
#define SLEEP_MODE false // Watt-value can only be reported when sleep mode is false.
|
||||
#define MAX_WATT 10000 // Max watt value to report. This filetrs outliers.
|
||||
#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
|
||||
#define CHILD_ID 1 // Id of the sensor child
|
||||
|
||||
unsigned long SEND_FREQUENCY = 20000; // Minimum time between send (in milliseconds). We don't wnat to spam the gateway.
|
||||
double ppwh = ((double)PULSE_FACTOR)/1000; // Pulses per watt hour
|
||||
boolean pcReceived = false;
|
||||
volatile unsigned long pulseCount = 0;
|
||||
volatile unsigned long lastBlink = 0;
|
||||
volatile unsigned long watt = 0;
|
||||
unsigned long oldPulseCount = 0;
|
||||
unsigned long oldWatt = 0;
|
||||
double oldKwh;
|
||||
unsigned long lastSend;
|
||||
MyMessage wattMsg(CHILD_ID,V_WATT);
|
||||
MyMessage kwhMsg(CHILD_ID,V_KWH);
|
||||
MyMessage pcMsg(CHILD_ID,V_VAR1);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Initialize library and add callback for incoming messages (signing is required)
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Energy Meter", "1.0");
|
||||
|
||||
// Register this device as power sensor
|
||||
present(CHILD_ID, S_POWER);
|
||||
|
||||
// Fetch last known pulse count value from gw
|
||||
request(CHILD_ID, V_VAR1);
|
||||
|
||||
attachInterrupt(INTERRUPT, onPulse, RISING);
|
||||
lastSend=millis();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long now = millis();
|
||||
// Only send values at a maximum frequency or woken up from sleep
|
||||
bool sendTime = now - lastSend > SEND_FREQUENCY;
|
||||
if (pcReceived && (SLEEP_MODE || sendTime)) {
|
||||
// New watt value has been calculated
|
||||
if (!SLEEP_MODE && watt != oldWatt) {
|
||||
// Check that we dont get unresonable large watt value.
|
||||
// could hapen when long wraps or false interrupt triggered
|
||||
if (watt<((unsigned long)MAX_WATT)) {
|
||||
send(wattMsg.set(watt)); // Send watt value to gw
|
||||
}
|
||||
Serial.print("Watt:");
|
||||
Serial.println(watt);
|
||||
oldWatt = watt;
|
||||
}
|
||||
|
||||
// Pulse cout has changed
|
||||
if (pulseCount != oldPulseCount) {
|
||||
send(pcMsg.set(pulseCount)); // Send pulse count value to gw
|
||||
double kwh = ((double)pulseCount/((double)PULSE_FACTOR));
|
||||
oldPulseCount = pulseCount;
|
||||
if (kwh != oldKwh) {
|
||||
send(kwhMsg.set(kwh, 4)); // Send kwh value to gw
|
||||
oldKwh = kwh;
|
||||
}
|
||||
}
|
||||
lastSend = now;
|
||||
} else if (sendTime && !pcReceived) {
|
||||
// No count received. Try requesting it again
|
||||
request(CHILD_ID, V_VAR1);
|
||||
lastSend=now;
|
||||
}
|
||||
|
||||
if (SLEEP_MODE) {
|
||||
sleep(SEND_FREQUENCY);
|
||||
}
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
if (message.type==V_VAR1) {
|
||||
pulseCount = oldPulseCount = message.getLong();
|
||||
Serial.print("Received last pulse count from gw:");
|
||||
Serial.println(pulseCount);
|
||||
pcReceived = true;
|
||||
}
|
||||
}
|
||||
|
||||
void onPulse()
|
||||
{
|
||||
if (!SLEEP_MODE) {
|
||||
unsigned long newBlink = micros();
|
||||
unsigned long interval = newBlink-lastBlink;
|
||||
if (interval<10000L) { // Sometimes we get interrupt on RISING
|
||||
return;
|
||||
}
|
||||
watt = (3600000000.0 /interval) / ppwh;
|
||||
lastBlink = newBlink;
|
||||
}
|
||||
pulseCount++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik EKblad
|
||||
* Contribution by a-lurker and Anticimex,
|
||||
* Contribution by Norbert Truchsess <norbert.truchsess@t-online.de>
|
||||
* Contribution by Ivo Pullens (ESP8266 support)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The EthernetGateway sends data received from sensors to the WiFi link.
|
||||
* The gateway also accepts input on ethernet interface, which is then sent out to the radio network.
|
||||
*
|
||||
* VERA CONFIGURATION:
|
||||
* Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin.
|
||||
* E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003
|
||||
*
|
||||
* LED purposes:
|
||||
* - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h
|
||||
* - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
|
||||
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
|
||||
* - ERR (red) - fast blink on error during transmission error or recieve crc error
|
||||
*
|
||||
* See http://www.mysensors.org/build/ethernet_gateway for wiring instructions.
|
||||
* The ESP8266 however requires different wiring:
|
||||
* nRF24L01+ ESP8266
|
||||
* VCC VCC
|
||||
* CE GPIO4
|
||||
* CSN/CS GPIO15
|
||||
* SCK GPIO14
|
||||
* MISO GPIO12
|
||||
* MOSI GPIO13
|
||||
*
|
||||
* Not all ESP8266 modules have all pins available on their external interface.
|
||||
* This code has been tested on an ESP-12 module.
|
||||
* The ESP8266 requires a certain pin configuration to download code, and another one to run code:
|
||||
* - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch')
|
||||
* - Connect GPIO15 via 10K pulldown resistor to GND
|
||||
* - Connect CH_PD via 10K resistor to VCC
|
||||
* - Connect GPIO2 via 10K resistor to VCC
|
||||
* - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch')
|
||||
*
|
||||
* Inclusion mode button:
|
||||
* - Connect GPIO5 via switch to GND ('inclusion switch')
|
||||
*
|
||||
* Hardware SHA204 signing is currently not supported!
|
||||
*
|
||||
* Make sure to fill in your ssid and WiFi password below for ssid & pass.
|
||||
*/
|
||||
#define NO_PORTB_PINCHANGES
|
||||
|
||||
#include <SPI.h>
|
||||
|
||||
#include <MySigningNone.h>
|
||||
#include <MySigningAtsha204Soft.h>
|
||||
#include <MyTransportNRF24.h>
|
||||
#include <MyTransportRFM69.h>
|
||||
#include <EEPROM.h>
|
||||
#include <MyHwESP8266.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
#include <MyParserSerial.h>
|
||||
#include <MySensor.h>
|
||||
#include <stdarg.h>
|
||||
#include "GatewayUtil.h"
|
||||
|
||||
const char *ssid = "MySSID"; // cannot be longer than 32 characters!
|
||||
const char *pass = "MyVerySecretPassword"; //
|
||||
|
||||
#define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled
|
||||
#define INCLUSION_MODE_PIN 5 // Digital pin used for inclusion mode button
|
||||
|
||||
#define RADIO_CE_PIN 4 // radio chip enable
|
||||
#define RADIO_SPI_SS_PIN 15 // radio SPI serial select
|
||||
|
||||
#ifdef WITH_LEDS_BLINKING
|
||||
#define RADIO_ERROR_LED_PIN 7 // Error led pin
|
||||
#define RADIO_RX_LED_PIN 8 // Receive led pin
|
||||
#define RADIO_TX_LED_PIN 9 // the PCB, on board LED
|
||||
#endif
|
||||
|
||||
|
||||
// NRFRF24L01 radio driver (set low transmit power by default)
|
||||
MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW);
|
||||
//MyTransportRFM69 transport;
|
||||
|
||||
|
||||
// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h)
|
||||
#ifdef MY_SIGNING_FEATURE
|
||||
MySigningNone signer;
|
||||
//MySigningAtsha204Soft signer;
|
||||
#endif
|
||||
|
||||
// Hardware profile
|
||||
MyHwESP8266 hw;
|
||||
|
||||
// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h)
|
||||
// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h
|
||||
MySensor gw(transport, hw
|
||||
#ifdef MY_SIGNING_FEATURE
|
||||
, signer
|
||||
#endif
|
||||
#ifdef WITH_LEDS_BLINKING
|
||||
, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN
|
||||
#endif
|
||||
);
|
||||
|
||||
|
||||
#define IP_PORT 5003 // The port you want to open
|
||||
#define MAX_SRV_CLIENTS 5 // how many clients should be able to telnet to this ESP8266
|
||||
|
||||
// a R/W server on the port
|
||||
static WiFiServer server(IP_PORT);
|
||||
static WiFiClient clients[MAX_SRV_CLIENTS];
|
||||
static bool clientsConnected[MAX_SRV_CLIENTS];
|
||||
static inputBuffer inputString[MAX_SRV_CLIENTS];
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
|
||||
void output(const char *fmt, ... )
|
||||
{
|
||||
char serialBuffer[MAX_SEND_LENGTH];
|
||||
va_list args;
|
||||
va_start (args, fmt );
|
||||
vsnprintf_P(serialBuffer, MAX_SEND_LENGTH, fmt, args);
|
||||
va_end (args);
|
||||
Serial.print(serialBuffer);
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
|
||||
{
|
||||
if (clients[i] && clients[i].connected())
|
||||
{
|
||||
// Serial.print("Client "); Serial.print(i); Serial.println(" write");
|
||||
clients[i].write((uint8_t*)serialBuffer, strlen(serialBuffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Setup console
|
||||
hw_init();
|
||||
|
||||
Serial.println(); Serial.println();
|
||||
Serial.println("ESP8266 MySensors Gateway");
|
||||
Serial.print("Connecting to "); Serial.println(ssid);
|
||||
|
||||
(void)WiFi.begin(ssid, pass);
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("Connected!");
|
||||
Serial.print("IP: "); Serial.println(WiFi.localIP());
|
||||
Serial.flush();
|
||||
|
||||
setupGateway(INCLUSION_MODE_PIN, INCLUSION_MODE_TIME, output);
|
||||
|
||||
// Initialize gateway at maximum PA level, channel 70 and callback for write operations
|
||||
gw.begin(incomingMessage, 0, true, 0);
|
||||
|
||||
// start listening for clients
|
||||
server.begin();
|
||||
server.setNoDelay(true);
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
gw.process();
|
||||
|
||||
checkButtonTriggeredInclusion();
|
||||
checkInclusionFinished();
|
||||
|
||||
// Go over list of clients and stop any that are no longer connected.
|
||||
// If the server has a new client connection it will be assigned to a free slot.
|
||||
bool allSlotsOccupied = true;
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
|
||||
{
|
||||
if (!clients[i].connected())
|
||||
{
|
||||
if (clientsConnected[i])
|
||||
{
|
||||
Serial.print("Client "); Serial.print(i); Serial.println(" disconnected");
|
||||
clients[i].stop();
|
||||
}
|
||||
//check if there are any new clients
|
||||
if (server.hasClient())
|
||||
{
|
||||
clients[i] = server.available();
|
||||
inputString[i].idx = 0;
|
||||
Serial.print("Client "); Serial.print(i); Serial.println(" connected");
|
||||
output(PSTR("0;0;%d;0;%d;Gateway startup complete.\n"), C_INTERNAL, I_GATEWAY_READY);
|
||||
}
|
||||
}
|
||||
bool connected = clients[i].connected();
|
||||
clientsConnected[i] = connected;
|
||||
allSlotsOccupied &= connected;
|
||||
}
|
||||
if (allSlotsOccupied && server.hasClient())
|
||||
{
|
||||
//no free/disconnected spot so reject
|
||||
Serial.println("No free slot available");
|
||||
WiFiClient c = server.available();
|
||||
c.stop();
|
||||
}
|
||||
|
||||
// Loop over clients connect and read available data
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++)
|
||||
{
|
||||
while(clients[i].connected() && clients[i].available())
|
||||
{
|
||||
char inChar = clients[i].read();
|
||||
if ( inputString[i].idx < MAX_RECEIVE_LENGTH - 1 )
|
||||
{
|
||||
// if newline then command is complete
|
||||
if (inChar == '\n')
|
||||
{
|
||||
// a command was issued by the client
|
||||
// we will now try to send it to the actuator
|
||||
inputString[i].string[inputString[i].idx] = 0;
|
||||
|
||||
// echo the string to the serial port
|
||||
Serial.print("Client "); Serial.print(i); Serial.print(": "); Serial.println(inputString[i].string);
|
||||
|
||||
parseAndSend(gw, inputString[i].string);
|
||||
|
||||
// clear the string:
|
||||
inputString[i].idx = 0;
|
||||
// Finished with this client's message. Next loop() we'll see if there's more to read.
|
||||
break;
|
||||
} else {
|
||||
// add it to the inputString:
|
||||
inputString[i].string[inputString[i].idx++] = inChar;
|
||||
}
|
||||
} else {
|
||||
// Incoming message too long. Throw away
|
||||
Serial.print("Client "); Serial.print(i); Serial.println(": Message too long");
|
||||
inputString[i].idx = 0;
|
||||
// Finished with this client's message. Next loop() we'll see if there's more to read.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
#ifndef __GATEWAYUTIL_H__
|
||||
#define __GATEWAYUTIL_H__
|
||||
|
||||
#ifdef ARDUINO
|
||||
|
||||
static uint8_t inclusionTime = 1; // Number of minutes inclusion mode is enabled
|
||||
static uint8_t pinInclusion = 3; // Input pin that should trigger inclusion mode
|
||||
|
||||
#define MAX_RECEIVE_LENGTH 100 // Max buffersize needed for messages coming from controller
|
||||
#define MAX_SEND_LENGTH 120 // Max buffersize needed for messages destined for controller
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char string[MAX_RECEIVE_LENGTH];
|
||||
uint8_t idx;
|
||||
} inputBuffer;
|
||||
|
||||
static volatile boolean buttonTriggeredInclusion;
|
||||
static boolean inclusionMode; // Keeps track on inclusion mode
|
||||
bool inclusionButtonSupported = false;
|
||||
void (*serial)(const char *fmt, ... );
|
||||
|
||||
MyParserSerial parser;
|
||||
|
||||
void setInclusionMode(boolean newMode);
|
||||
|
||||
char convBuf[MAX_PAYLOAD*2+1];
|
||||
unsigned long inclusionStartTime;
|
||||
|
||||
|
||||
void startInclusionInterrupt() {
|
||||
buttonTriggeredInclusion = true;
|
||||
}
|
||||
|
||||
void setupGateway(uint8_t _inc, uint8_t _incTime, void (* _serial)(const char *, ... )) {
|
||||
inclusionMode = 0;
|
||||
buttonTriggeredInclusion = false;
|
||||
serial = _serial;
|
||||
|
||||
inclusionTime = _incTime;
|
||||
inclusionButtonSupported = (_inc != 255);
|
||||
if (inclusionButtonSupported)
|
||||
{
|
||||
pinInclusion = _inc;
|
||||
|
||||
// Setup digital in that triggers inclusion mode
|
||||
pinMode(pinInclusion, INPUT_PULLUP);
|
||||
|
||||
// Add interrupt for inclusion button to pin
|
||||
attachInterrupt(pinInclusion, startInclusionInterrupt, FALLING);
|
||||
}
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
// if (mGetCommand(message) == C_PRESENTATION && inclusionMode) {
|
||||
// gw.rxBlink(3);
|
||||
// } else {
|
||||
// gw.rxBlink(1);
|
||||
// }
|
||||
// Pass along the message from sensors to serial line
|
||||
serial(PSTR("%d;%d;%d;%d;%d;%s\n"),message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type, message.getString(convBuf));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void checkButtonTriggeredInclusion() {
|
||||
if (inclusionButtonSupported)
|
||||
{
|
||||
if (buttonTriggeredInclusion) {
|
||||
// Ok, someone pressed the inclusion button on the gateway
|
||||
// start inclusion mode for 1 munute.
|
||||
#ifdef DEBUG
|
||||
serial(PSTR("0;0;%d;0;%d;Inclusion started by button.\n"), C_INTERNAL, I_LOG_MESSAGE);
|
||||
#endif
|
||||
buttonTriggeredInclusion = false;
|
||||
setInclusionMode(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkInclusionFinished() {
|
||||
if (inclusionMode && millis()-inclusionStartTime>60000UL*inclusionTime) {
|
||||
// inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode
|
||||
setInclusionMode(false);
|
||||
}
|
||||
}
|
||||
|
||||
void parseAndSend(MySensor &gw, char *commandBuffer) {
|
||||
boolean ok;
|
||||
MyMessage &msg = gw.getLastMessage();
|
||||
|
||||
if (parser.parse(msg, commandBuffer)) {
|
||||
uint8_t command = mGetCommand(msg);
|
||||
|
||||
if (msg.destination==GATEWAY_ADDRESS && command==C_INTERNAL) {
|
||||
// Handle messages directed to gateway
|
||||
if (msg.type == I_VERSION) {
|
||||
// Request for version
|
||||
serial(PSTR("0;0;%d;0;%d;%s\n"), C_INTERNAL, I_VERSION, LIBRARY_VERSION);
|
||||
} else if (msg.type == I_INCLUSION_MODE) {
|
||||
// Request to change inclusion mode
|
||||
setInclusionMode(atoi(msg.data) == 1);
|
||||
}
|
||||
} else {
|
||||
#ifdef WITH_LEDS_BLINKING
|
||||
gw.txBlink(1);
|
||||
#endif
|
||||
ok = gw.sendRoute(msg);
|
||||
if (!ok) {
|
||||
#ifdef WITH_LEDS_BLINKING
|
||||
gw.errBlink(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setInclusionMode(boolean newMode) {
|
||||
if (newMode != inclusionMode) {
|
||||
inclusionMode = newMode;
|
||||
// Send back mode change on serial line to ack command
|
||||
serial(PSTR("0;0;%d;0;%d;%d\n"), C_INTERNAL, I_INCLUSION_MODE, inclusionMode?1:0);
|
||||
|
||||
if (inclusionMode) {
|
||||
inclusionStartTime = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#error This example is only for use on Arduino.
|
||||
#endif // ARDUINO
|
||||
|
||||
#endif
|
||||
@@ -1,125 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik EKblad
|
||||
* Contribution by a-lurker and Anticimex,
|
||||
* Contribution by Norbert Truchsess <norbert.truchsess@t-online.de>
|
||||
* Contribution by Tomas Hozza <thozza@gmail.com>
|
||||
*
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The EthernetGateway sends data received from sensors to the ethernet link.
|
||||
* The gateway also accepts input on ethernet interface, which is then sent out to the radio network.
|
||||
*
|
||||
* The GW code is designed for Arduino 328p / 16MHz. ATmega168 does not have enough memory to run this program.
|
||||
*
|
||||
*
|
||||
* COMPILING WIZNET (W5100) ETHERNET MODULE
|
||||
* > Edit MyConfig.h in (libraries\MySensors\) to enable softspi (remove // before "#define SOFTSPI").
|
||||
*
|
||||
* COMPILING ENC28J60 ETHERNET MODULE
|
||||
* > Use Arduino IDE 1.5.7 (or later)
|
||||
* > Disable DEBUG in Sensor.h before compiling this sketch. Othervise the sketch will probably not fit in program space when downloading.
|
||||
* > Remove Ethernet.h include below and include UIPEthernet.h
|
||||
* > Remove DigitalIO include
|
||||
* Note that I had to disable UDP and DHCP support in uipethernet-conf.h to reduce space. (which means you have to choose a static IP for that module)
|
||||
*
|
||||
* VERA CONFIGURATION:
|
||||
* Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin.
|
||||
* E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003
|
||||
*
|
||||
* LED purposes:
|
||||
* - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h
|
||||
* - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
|
||||
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
|
||||
* - ERR (red) - fast blink on error during transmission error or recieve crc error
|
||||
*
|
||||
* See http://www.mysensors.org/build/ethernet_gateway for wiring instructions.
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
// Enable gateway transportation type
|
||||
#define MY_GATEWAY_W5100
|
||||
//#define MY_GATEWAY_ENC28J60
|
||||
|
||||
// Enable Soft SPI for radio (note different radio wiring required)
|
||||
// Useful for W5100 which sometimes have hard time co-operate with radio on the same spi bus.
|
||||
//#define MY_SOFTSPI
|
||||
//#define MY_SOFT_SPI_SCK_PIN 14
|
||||
//#define MY_SOFT_SPI_MISO_PIN 16
|
||||
//#define MY_SOFT_SPI_MOSI_PIN 15
|
||||
|
||||
|
||||
// Enable to use UDP
|
||||
#define MY_USE_UDP
|
||||
|
||||
#define MY_IP_ADDRESS 192,168,178,66 // If this is disabled, DHCP is used to retrieve address
|
||||
// Renewal period if using DHCP
|
||||
//#define MY_IP_RENEWAL_INTERVAL 60000
|
||||
// The port to keep open on node server mode / or port to contact in client mode
|
||||
#define MY_PORT 5003
|
||||
|
||||
// Controller ip address (enables client mode). Undefine this to act as sever.
|
||||
#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 254
|
||||
|
||||
// The MAC address can be anything you want but should be unique on your network.
|
||||
// Newer boards have a MAC address printed on the underside of the PCB, which you can (optionally) use.
|
||||
// Note that most of the Ardunio examples use "DEAD BEEF FEED" for the MAC address.
|
||||
#define MY_MAC_ADDRESS 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
|
||||
|
||||
// Flash leds on rx/tx/err
|
||||
#define MY_LEDS_BLINKING_FEATURE
|
||||
// Set blinking period
|
||||
#define MY_DEFAULT_LED_BLINK_PERIOD 300
|
||||
|
||||
// Enable inclusion mode
|
||||
#define MY_INCLUSION_MODE_FEATURE
|
||||
// Enable Inclusion mode button on gateway
|
||||
#define MY_INCLUSION_BUTTON_FEATURE
|
||||
// Set inclusion mode duration (in seconds)
|
||||
#define MY_INCLUSION_MODE_DURATION 60
|
||||
// Digital pin used for inclusion mode button
|
||||
#define MY_INCLUSION_MODE_BUTTON_PIN 3
|
||||
|
||||
#define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin
|
||||
#define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin
|
||||
#define MY_DEFAULT_TX_LED_PIN 9 // the PCB, on board LED
|
||||
|
||||
#define MY_RADIO_CE_PIN 5 // radio chip enable
|
||||
#define MY_RADIO_SPI_SS_PIN 6 // radio SPI serial select
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik EKblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This sketch provides an example how to implement a humidity/temperature
|
||||
* sensor using DHT11/DHT-22
|
||||
* http://www.mysensors.org/build/humidity
|
||||
*/
|
||||
|
||||
// Enable debug prints
|
||||
//#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <DHT.h>
|
||||
|
||||
#define CHILD_ID_HUM 0
|
||||
#define CHILD_ID_TEMP 1
|
||||
#define HUMIDITY_SENSOR_DIGITAL_PIN 3
|
||||
unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
|
||||
|
||||
DHT dht;
|
||||
float lastTemp;
|
||||
float lastHum;
|
||||
boolean metric = true;
|
||||
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
|
||||
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
|
||||
|
||||
// Send the Sketch Version Information to the Gateway
|
||||
sendSketchInfo("Humidity", "1.0");
|
||||
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
present(CHILD_ID_HUM, S_HUM);
|
||||
present(CHILD_ID_TEMP, S_TEMP);
|
||||
|
||||
metric = getConfig().isMetric;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
delay(dht.getMinimumSamplingPeriod());
|
||||
|
||||
float temperature = dht.getTemperature();
|
||||
if (isnan(temperature)) {
|
||||
Serial.println("Failed reading temperature from DHT");
|
||||
} else if (temperature != lastTemp) {
|
||||
lastTemp = temperature;
|
||||
if (!metric) {
|
||||
temperature = dht.toFahrenheit(temperature);
|
||||
}
|
||||
send(msgTemp.set(temperature, 1));
|
||||
Serial.print("T: ");
|
||||
Serial.println(temperature);
|
||||
}
|
||||
|
||||
float humidity = dht.getHumidity();
|
||||
if (isnan(humidity)) {
|
||||
Serial.println("Failed reading humidity from DHT");
|
||||
} else if (humidity != lastHum) {
|
||||
lastHum = humidity;
|
||||
send(msgHum.set(humidity, 1));
|
||||
Serial.print("H: ");
|
||||
Serial.println(humidity);
|
||||
}
|
||||
|
||||
sleep(SLEEP_TIME); //sleep a bit
|
||||
}
|
||||
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik EKblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Example sketch showing how to control ir devices
|
||||
* An IR LED must be connected to Arduino PWM pin 3.
|
||||
* An optional ir receiver can be connected to PWM pin 8.
|
||||
* All receied ir signals will be sent to gateway device stored in VAR_1.
|
||||
* When binary light on is clicked - sketch will send volume up ir command
|
||||
* When binary light off is clicked - sketch will send volume down ir command
|
||||
* http://www.mysensors.org/build/ir
|
||||
*/
|
||||
|
||||
// Enable debug prints
|
||||
//#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <IRLib.h>
|
||||
|
||||
int RECV_PIN = 8;
|
||||
|
||||
#define CHILD_1 3 // childId
|
||||
|
||||
IRsend irsend;
|
||||
IRrecv irrecv(RECV_PIN);
|
||||
IRdecode decoder;
|
||||
//decode_results results;
|
||||
unsigned int Buffer[RAWBUF];
|
||||
MyMessage msg(CHILD_1, V_VAR1);
|
||||
|
||||
void setup()
|
||||
{
|
||||
irrecv.enableIRIn(); // Start the ir receiver
|
||||
decoder.UseExtnBuf(Buffer);
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("IR Sensor", "1.0");
|
||||
|
||||
// Register a sensors to Use binary light for test purposes.
|
||||
present(CHILD_1, S_LIGHT);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (irrecv.GetResults(&decoder)) {
|
||||
irrecv.resume();
|
||||
decoder.decode();
|
||||
decoder.DumpResults();
|
||||
|
||||
char buffer[10];
|
||||
sprintf(buffer, "%08lx", decoder.value);
|
||||
// Send ir result to gw
|
||||
send(msg.set(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
// We only expect one type of message from controller. But we better check anyway.
|
||||
if (message.type==V_LIGHT) {
|
||||
int incomingRelayStatus = message.getInt();
|
||||
if (incomingRelayStatus == 1) {
|
||||
irsend.send(NEC, 0x1EE17887, 32); // Vol up yamaha ysp-900
|
||||
} else {
|
||||
irsend.send(NEC, 0x1EE1F807, 32); // Vol down yamaha ysp-900
|
||||
}
|
||||
// Start receiving ir again...
|
||||
irrecv.enableIRIn();
|
||||
}
|
||||
}
|
||||
|
||||
// Dumps out the decode_results structure.
|
||||
// Call this after IRrecv::decode()
|
||||
// void * to work around compiler issue
|
||||
//void dump(void *v) {
|
||||
// decode_results *results = (decode_results *)v
|
||||
/*void dump(decode_results *results) {
|
||||
int count = results->rawlen;
|
||||
if (results->decode_type == UNKNOWN) {
|
||||
Serial.print("Unknown encoding: ");
|
||||
}
|
||||
else if (results->decode_type == NEC) {
|
||||
Serial.print("Decoded NEC: ");
|
||||
}
|
||||
else if (results->decode_type == SONY) {
|
||||
Serial.print("Decoded SONY: ");
|
||||
}
|
||||
else if (results->decode_type == RC5) {
|
||||
Serial.print("Decoded RC5: ");
|
||||
}
|
||||
else if (results->decode_type == RC6) {
|
||||
Serial.print("Decoded RC6: ");
|
||||
}
|
||||
else if (results->decode_type == PANASONIC) {
|
||||
Serial.print("Decoded PANASONIC - Address: ");
|
||||
Serial.print(results->panasonicAddress,HEX);
|
||||
Serial.print(" Value: ");
|
||||
}
|
||||
else if (results->decode_type == JVC) {
|
||||
Serial.print("Decoded JVC: ");
|
||||
}
|
||||
Serial.print(results->value, HEX);
|
||||
Serial.print(" (");
|
||||
Serial.print(results->bits, DEC);
|
||||
Serial.println(" bits)");
|
||||
Serial.print("Raw (");
|
||||
Serial.print(count, DEC);
|
||||
Serial.print("): ");
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if ((i % 2) == 1) {
|
||||
Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
|
||||
}
|
||||
else {
|
||||
Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
|
||||
}
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.println("");
|
||||
}
|
||||
*/
|
||||
@@ -1,876 +0,0 @@
|
||||
/*
|
||||
MySprinkler for MySensors
|
||||
|
||||
Arduino Multi-Zone Sprinkler Control
|
||||
|
||||
May 31, 2015
|
||||
|
||||
*** Version 2.0
|
||||
|
||||
*** Upgraded to http://MySensors.org version 1.4.1
|
||||
*** Expanded for up to 16 Valves
|
||||
*** Setup for active low relay board or comment out #define ACTIVE_LOW to switch to active high
|
||||
*** Switch to bitshift method vs byte arrays
|
||||
*** Changed RUN_ALL_ZONES Vera device to 0 (was highest valve)
|
||||
*** Added optional LCD display featuring remaining time, date last ran & current time
|
||||
*** Features 'raindrop' and 'clock' icons which indicate sensor is updating valve data and clock respectively
|
||||
*** Added single pushbutton menu to manually select which program to run (All Zones or a Single Zone)
|
||||
*** Added option of naming your Zones programmatically or with Vera (V_VAR3 used to store names)
|
||||
|
||||
Utilizing your Vera home automation controller and the MySensors.org gateway you can
|
||||
control up to a sixteen zone irrigation system with only three digital pins. This sketch
|
||||
will create NUMBER_OF_VALVES + 1 devices on your Vera controller
|
||||
|
||||
This sketch features the following:
|
||||
|
||||
* Allows you to cycle through All zones (RUN_ALL_ZONES) or individual zone (RUN_SINGLE_ZONE) control.
|
||||
* Use the 0th controller to activate RUN_ALL_ZONES (each zone in numeric sequence 1 to n)
|
||||
using Variable1 as the "ON" time in minutes in each of the vera devices created.
|
||||
* Use the individual zone controller to activate a single zone. This feature uses
|
||||
Variable2 as the "ON" time for each individual device/zone.
|
||||
* Connect according to pinout below and uses Shift Registers as to allow the MySensors
|
||||
standard radio configuration and still leave available digital pins
|
||||
* Turning on any zone will stop the current process and begin that particular process.
|
||||
* Turning off any zone will stop the current process and turn off all zones.
|
||||
* To push your new time intervals for your zones, simply change the variable on your Vera and
|
||||
your arduino will call to Vera once a minute and update accordingly. Variables will also be
|
||||
requested when the device is first powered on.
|
||||
* Pushbutton activation to RUN_ALL_ZONES, RUN_SINGLE_ZONE or halt the current program
|
||||
* LED status indicator
|
||||
|
||||
PARTS LIST:
|
||||
Available from the MySensors store - http://www.mysensors.org/store/
|
||||
* Relays (8 channel)
|
||||
* Female Pin Header Connector Strip
|
||||
* Prototype Universal Printed Circuit Boards (PCB)
|
||||
* NRF24L01 Radio
|
||||
* Arduino (I used a Pro Mini)
|
||||
* FTDI USB to TTL Serial Adapter
|
||||
* Capacitors (10uf and .1uf)
|
||||
* 3.3v voltage regulator
|
||||
* Resistors (270 & 10K)
|
||||
* Female Dupont Cables
|
||||
* 1602 LCD (with I2C Interface)
|
||||
* LED
|
||||
* Push button
|
||||
* Shift Register (SN74HC595)
|
||||
* 2 Pole 5mm Pitch PCB Mount Screw Terminal Block
|
||||
* 3 Pole 5mm Pitch PCB Mount Screw Terminal Block
|
||||
* 22-24 gauge wire or similar (I used Cat5/Cat6 cable)
|
||||
* 18 gauge wire (for relay)
|
||||
* Irrigation Power Supply (24-Volt/750 mA Transformer)
|
||||
|
||||
|
||||
INSTRUCTIONS:
|
||||
|
||||
* A step-by-step setup video is available here: http://youtu.be/l4GPRTsuHkI
|
||||
* After assembling your arduino, radio, decoupling capacitors, shift register(s), status LED, pushbutton LCD (I2C connected to
|
||||
A4 and A5) and relays, and load the sketch.
|
||||
* Following the instructions at https://MySensors.org include the device to your MySensors Gateway.
|
||||
* Verify that each new device has a Variable1, Variable2 and Variable3. Populate data accordingly with whole minutes for
|
||||
the RUN_ALL_ZONES routine (Variable1) and the RUN_SINGLE_ZONE routines (Variable 2). The values entered for times may be zero and
|
||||
you may use the defaulet zone names by leaving Variable3 blank.
|
||||
* Once you have entered values for each zone and each variable, save the settings by pressing the red save button on your Vera.
|
||||
* Restart your arduino; verify the settings are loaded into your arduino with the serial monitor; the array will be printed
|
||||
on the serial monitor.
|
||||
* Your arduino should slow-flash, indicating that it is in ready mode.
|
||||
* There are multiple debug serial prints that can be monitored to assure that it is operating properly.
|
||||
* ***THIS SHOULD NO LONGER BE NEEDED*** The standard MySensors library now works. https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads for the I2C library, or use yours
|
||||
|
||||
Contributed by Jim (BulldogLowell@gmail.com) with much contribution from Pete (pete.will@mysensors.org) and is released to the public domain
|
||||
*/
|
||||
//
|
||||
|
||||
// Enable debug prints
|
||||
//#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
//#define MY_NODE_ID 1 // Set this to fix your Radio ID or use Auto
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Time.h>
|
||||
#include <MySensor.h>
|
||||
#include <LiquidCrystal.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
|
||||
#define NUMBER_OF_VALVES 8 // Change this to set your valve count up to 16.
|
||||
#define VALVE_RESET_TIME 7500UL // Change this (in milliseconds) for the time you need your valves to hydraulically reset and change state
|
||||
|
||||
#define SKETCH_NAME "MySprinkler"
|
||||
#define SKETCH_VERSION "2.0"
|
||||
//
|
||||
#define CHILD_ID_SPRINKLER 0
|
||||
//
|
||||
#define ACTIVE_LOW // comment out this line if your relays are active high
|
||||
//
|
||||
#define DEBUG_ON // comment out to supress serial monitor output
|
||||
//
|
||||
#ifdef ACTIVE_LOW
|
||||
#define BITSHIFT_VALVE_NUMBER ~(1U << (valveNumber-1))
|
||||
#define ALL_VALVES_OFF 0xFFFF
|
||||
#else
|
||||
#define BITSHIFT_VALVE_NUMBER (1U << (valveNumber-1))
|
||||
#define ALL_VALVES_OFF 0U
|
||||
#endif
|
||||
//
|
||||
#ifdef DEBUG_ON
|
||||
#define DEBUG_PRINT(x) Serial.print(x)
|
||||
#define DEBUG_PRINTLN(x) Serial.println(x)
|
||||
#else
|
||||
#define DEBUG_PRINT(x)
|
||||
#define DEBUG_PRINTLN(x)
|
||||
#define SERIAL_START(x)
|
||||
#endif
|
||||
//
|
||||
typedef enum {
|
||||
STAND_BY_ALL_OFF, RUN_SINGLE_ZONE, RUN_ALL_ZONES, CYCLE_COMPLETE, ZONE_SELECT_MENU
|
||||
}
|
||||
SprinklerStates;
|
||||
//
|
||||
SprinklerStates state = STAND_BY_ALL_OFF;
|
||||
SprinklerStates lastState;
|
||||
byte menuState = 0;
|
||||
unsigned long menuTimer;
|
||||
byte countDownTime = 10;
|
||||
//
|
||||
int allZoneTime [NUMBER_OF_VALVES + 1];
|
||||
int valveSoloTime [NUMBER_OF_VALVES + 1];
|
||||
int valveNumber;
|
||||
int lastValve;
|
||||
unsigned long startMillis;
|
||||
const int ledPin = 5;
|
||||
const int waterButtonPin = 3;
|
||||
boolean buttonPushed = false;
|
||||
boolean showTime = true;
|
||||
boolean clockUpdating = false;
|
||||
boolean recentUpdate = true;
|
||||
const char *dayOfWeek[] = {
|
||||
"Null", "Sunday ", "Monday ", "Tuesday ", "Wednesday ", "Thursday ", "Friday ", "Saturday "
|
||||
};
|
||||
// Name your Zones here or use Vera to edit them by adding a name in Variable3...
|
||||
String valveNickName[17] = {
|
||||
"All Zones", "Zone 1", "Zone 2", "Zone 3", "Zone 4", "Zone 5", "Zone 6", "Zone 7", "Zone 8", "Zone 9", "Zone 10", "Zone 11", "Zone 12", "Zone 13", "Zone 14", "Zone 15", "Zone 16"
|
||||
};
|
||||
//
|
||||
time_t lastTimeRun = 0;
|
||||
//Setup Shift Register...
|
||||
const int latchPin = 8;
|
||||
const int clockPin = 4;
|
||||
const int dataPin = 7;
|
||||
//
|
||||
byte clock[8] = {0x0, 0xe, 0x15, 0x17, 0x11, 0xe, 0x0}; // fetching time indicator
|
||||
byte raindrop[8] = {0x4, 0x4, 0xA, 0xA, 0x11, 0xE, 0x0,}; // fetching Valve Data indicator
|
||||
// Set the pins on the I2C chip used for LCD connections:
|
||||
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
|
||||
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address to 0x27
|
||||
//
|
||||
MyMessage msg1valve(CHILD_ID_SPRINKLER, V_LIGHT);
|
||||
MyMessage var1valve(CHILD_ID_SPRINKLER, V_VAR1);
|
||||
MyMessage var2valve(CHILD_ID_SPRINKLER, V_VAR2);
|
||||
|
||||
bool receivedInitialValue = false;
|
||||
//
|
||||
void setup()
|
||||
{
|
||||
DEBUG_PRINTLN(F("Initialising..."));
|
||||
pinMode(latchPin, OUTPUT);
|
||||
pinMode(clockPin, OUTPUT);
|
||||
pinMode(dataPin, OUTPUT);
|
||||
pinMode(ledPin, OUTPUT);
|
||||
pinMode(waterButtonPin, INPUT_PULLUP);
|
||||
//pinMode(waterButtonPin, INPUT);
|
||||
attachInterrupt(1, PushButton, RISING); //May need to change for your Arduino model
|
||||
digitalWrite (ledPin, HIGH);
|
||||
DEBUG_PRINTLN(F("Turning All Valves Off..."));
|
||||
updateRelays(ALL_VALVES_OFF);
|
||||
//delay(5000);
|
||||
lcd.begin(16, 2); //(16 characters and 2 line display)
|
||||
lcd.clear();
|
||||
lcd.backlight();
|
||||
lcd.createChar(0, clock);
|
||||
lcd.createChar(1, raindrop);
|
||||
//
|
||||
//check for saved date in EEPROM
|
||||
DEBUG_PRINTLN(F("Checking EEPROM for stored date:"));
|
||||
delay(500);
|
||||
if (loadState(0) == 0xFF) // EEPROM flag
|
||||
{
|
||||
DEBUG_PRINTLN(F("Retreiving last run time from EEPROM..."));
|
||||
for (int i = 0; i < 4 ; i++)
|
||||
{
|
||||
lastTimeRun = lastTimeRun << 8;
|
||||
lastTimeRun = lastTimeRun | loadState(i + 1); // assemble 4 bytes into an ussigned long epoch timestamp
|
||||
}
|
||||
}
|
||||
setIncomingCallback(getVariables);
|
||||
sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
|
||||
for (byte i = 0; i <= NUMBER_OF_VALVES; i++)
|
||||
{
|
||||
present(i, S_LIGHT);
|
||||
}
|
||||
DEBUG_PRINTLN(F("Sensor Presentation Complete"));
|
||||
//
|
||||
digitalWrite (ledPin, LOW);
|
||||
DEBUG_PRINTLN(F("Ready..."));
|
||||
//
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print(F(" Syncing Time "));
|
||||
lcd.setCursor(15, 0);
|
||||
lcd.write(byte(0));
|
||||
lcd.setCursor(0, 1);
|
||||
int clockCounter = 0;
|
||||
while (timeStatus() == timeNotSet && clockCounter < 21)
|
||||
{
|
||||
requestTime(receiveTime);
|
||||
DEBUG_PRINTLN(F("Requesting time from Gateway:"));
|
||||
wait(1000);
|
||||
lcd.print(".");
|
||||
clockCounter++;
|
||||
if (clockCounter > 16)
|
||||
{
|
||||
DEBUG_PRINTLN(F("Failed initial clock synchronization!"));
|
||||
lcd.clear();
|
||||
lcd.print(F(" Failed Clock "));
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(F(" Syncronization "));
|
||||
wait(2000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
lcd.clear();
|
||||
//Update valve data when first powered on
|
||||
for (byte i = 0; i <= NUMBER_OF_VALVES; i++)
|
||||
{
|
||||
lcd.print(F(" Updating "));
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(F(" Valve Data: "));
|
||||
lcd.print(i);
|
||||
boolean flashIcon = false;
|
||||
DEBUG_PRINT(F("Calling for Valve "));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F(" Data..."));
|
||||
while (!receivedInitialValue)
|
||||
{
|
||||
lcd.setCursor(15, 0);
|
||||
flashIcon = !flashIcon;
|
||||
flashIcon ? lcd.write(byte(1)) : lcd.print(F(" "));
|
||||
request(i, V_VAR1);
|
||||
wait(500);
|
||||
}
|
||||
receivedInitialValue = false;
|
||||
while (!receivedInitialValue)
|
||||
{
|
||||
lcd.setCursor(15, 0);
|
||||
flashIcon = !flashIcon;
|
||||
flashIcon ? lcd.write(byte(1)) : lcd.print(F(" "));
|
||||
request(i, V_VAR2);
|
||||
wait(500);
|
||||
}
|
||||
receivedInitialValue = false;
|
||||
while (!receivedInitialValue)
|
||||
{
|
||||
lcd.setCursor(15, 0);
|
||||
flashIcon = !flashIcon;
|
||||
flashIcon ? lcd.write(byte(1)) : lcd.print(F(" "));
|
||||
request(i, V_VAR3);
|
||||
wait(500);
|
||||
}
|
||||
}
|
||||
lcd.clear();
|
||||
}
|
||||
//
|
||||
void loop()
|
||||
{
|
||||
updateClock();
|
||||
updateDisplay();
|
||||
goGetValveTimes();
|
||||
//
|
||||
if (buttonPushed)
|
||||
{
|
||||
menuTimer = millis();
|
||||
DEBUG_PRINTLN(F("Button Pressed"));
|
||||
if (state == STAND_BY_ALL_OFF)
|
||||
{
|
||||
state = ZONE_SELECT_MENU;
|
||||
menuState = 0;
|
||||
}
|
||||
else if (state == ZONE_SELECT_MENU)
|
||||
{
|
||||
menuState++;
|
||||
if (menuState > NUMBER_OF_VALVES)
|
||||
{
|
||||
menuState = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state = STAND_BY_ALL_OFF;
|
||||
}
|
||||
buttonPushed = false;
|
||||
}
|
||||
if (state == STAND_BY_ALL_OFF)
|
||||
{
|
||||
slowToggleLED ();
|
||||
if (state != lastState)
|
||||
{
|
||||
updateRelays(ALL_VALVES_OFF);
|
||||
DEBUG_PRINTLN(F("State Changed... all Zones off"));
|
||||
for (byte i = 0; i <= NUMBER_OF_VALVES; i++)
|
||||
{
|
||||
wait(50);
|
||||
send(msg1valve.setSensor(i).set(false), false);
|
||||
}
|
||||
lcd.clear();
|
||||
lcd.setCursor(0,0);
|
||||
lcd.print(F("** Irrigation **"));
|
||||
lcd.setCursor(0,1);
|
||||
lcd.print(F("** Halted **"));
|
||||
wait(2000);
|
||||
lastValve = -1;
|
||||
}
|
||||
}
|
||||
//
|
||||
else if (state == RUN_ALL_ZONES)
|
||||
{
|
||||
if (lastValve != valveNumber)
|
||||
{
|
||||
for (byte i = 0; i <= NUMBER_OF_VALVES; i++)
|
||||
{
|
||||
if (i == 0 || i == valveNumber)
|
||||
{
|
||||
send(msg1valve.setSensor(i).set(true), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
send(msg1valve.setSensor(i).set(false), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
lastValve = valveNumber;
|
||||
fastToggleLed();
|
||||
if (state != lastState)
|
||||
{
|
||||
valveNumber = 1;
|
||||
updateRelays(ALL_VALVES_OFF);
|
||||
DEBUG_PRINTLN(F("State Changed, Running All Zones..."));
|
||||
}
|
||||
unsigned long nowMillis = millis();
|
||||
if (nowMillis - startMillis < VALVE_RESET_TIME)
|
||||
{
|
||||
updateRelays(ALL_VALVES_OFF);
|
||||
}
|
||||
else if (nowMillis - startMillis < (allZoneTime[valveNumber] * 60000UL))
|
||||
{
|
||||
updateRelays(BITSHIFT_VALVE_NUMBER);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_PRINTLN(F("Changing Valves..."));
|
||||
updateRelays(ALL_VALVES_OFF);
|
||||
startMillis = millis();
|
||||
valveNumber++;
|
||||
if (valveNumber > NUMBER_OF_VALVES)
|
||||
{
|
||||
state = CYCLE_COMPLETE;
|
||||
startMillis = millis();
|
||||
lastValve = -1;
|
||||
lastTimeRun = now();
|
||||
saveDateToEEPROM(lastTimeRun);
|
||||
for (byte i = 0; i <= NUMBER_OF_VALVES; i++)
|
||||
{
|
||||
send(msg1valve.setSensor(i).set(false), false);
|
||||
}
|
||||
DEBUG_PRINT(F("State = "));
|
||||
DEBUG_PRINTLN(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
else if (state == RUN_SINGLE_ZONE)
|
||||
{
|
||||
fastToggleLed();
|
||||
if (state != lastState)
|
||||
{
|
||||
for (byte i = 0; i <= NUMBER_OF_VALVES; i++)
|
||||
{
|
||||
if (i == 0 || i == valveNumber)
|
||||
{
|
||||
send(msg1valve.setSensor(i).set(true), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
send(msg1valve.setSensor(i).set(false), false);
|
||||
}
|
||||
}
|
||||
DEBUG_PRINTLN(F("State Changed, Single Zone Running..."));
|
||||
DEBUG_PRINT(F("Zone: "));
|
||||
DEBUG_PRINTLN(valveNumber);
|
||||
}
|
||||
unsigned long nowMillis = millis();
|
||||
if (nowMillis - startMillis < VALVE_RESET_TIME)
|
||||
{
|
||||
updateRelays(ALL_VALVES_OFF);
|
||||
}
|
||||
else if (nowMillis - startMillis < (valveSoloTime [valveNumber] * 60000UL))
|
||||
{
|
||||
updateRelays(BITSHIFT_VALVE_NUMBER);
|
||||
}
|
||||
else
|
||||
{
|
||||
updateRelays(ALL_VALVES_OFF);
|
||||
for (byte i = 0; i <= NUMBER_OF_VALVES; i++)
|
||||
{
|
||||
send(msg1valve.setSensor(i).set(false), false);
|
||||
}
|
||||
state = CYCLE_COMPLETE;
|
||||
startMillis = millis();
|
||||
DEBUG_PRINT(F("State = "));
|
||||
DEBUG_PRINTLN(state);
|
||||
}
|
||||
lastTimeRun = now();
|
||||
}
|
||||
else if (state == CYCLE_COMPLETE)
|
||||
{
|
||||
if (millis() - startMillis < 30000UL)
|
||||
{
|
||||
fastToggleLed();
|
||||
}
|
||||
else
|
||||
{
|
||||
state = STAND_BY_ALL_OFF;
|
||||
}
|
||||
}
|
||||
else if (state == ZONE_SELECT_MENU)
|
||||
{
|
||||
displayMenu();
|
||||
}
|
||||
lastState = state;
|
||||
}
|
||||
//
|
||||
void displayMenu(void)
|
||||
{
|
||||
static byte lastMenuState = -1;
|
||||
static int lastSecond;
|
||||
if (menuState != lastMenuState)
|
||||
{
|
||||
lcd.clear();
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print(valveNickName[menuState]);
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(F("Starting"));
|
||||
DEBUG_PRINT(valveNickName[menuState]);
|
||||
Serial.print(F(" Starting Shortly"));
|
||||
}
|
||||
int thisSecond = (millis() - menuTimer) / 1000UL;
|
||||
if (thisSecond != lastSecond && thisSecond < 8)
|
||||
{
|
||||
lcd.print(F("."));
|
||||
Serial.print(".");
|
||||
}
|
||||
lastSecond = thisSecond;
|
||||
if (millis() - menuTimer > 10000UL)
|
||||
{
|
||||
startMillis = millis();
|
||||
if (menuState == 0)
|
||||
{
|
||||
valveNumber = 1;
|
||||
state = RUN_ALL_ZONES;
|
||||
}
|
||||
else
|
||||
{
|
||||
valveNumber = menuState;
|
||||
state = RUN_SINGLE_ZONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
lastMenuState = menuState;
|
||||
}
|
||||
//
|
||||
void updateRelays(int value)
|
||||
{
|
||||
digitalWrite(latchPin, LOW);
|
||||
shiftOut(dataPin, clockPin, MSBFIRST, highByte(value));
|
||||
shiftOut(dataPin, clockPin, MSBFIRST, lowByte(value));
|
||||
digitalWrite(latchPin, HIGH);
|
||||
}
|
||||
//
|
||||
void PushButton() //interrupt with debounce
|
||||
{
|
||||
static unsigned long last_interrupt_time = 0;
|
||||
unsigned long interrupt_time = millis();
|
||||
if (interrupt_time - last_interrupt_time > 200)
|
||||
{
|
||||
buttonPushed = true;
|
||||
}
|
||||
last_interrupt_time = interrupt_time;
|
||||
}
|
||||
//
|
||||
void fastToggleLed()
|
||||
{
|
||||
static unsigned long fastLedTimer;
|
||||
if (millis() - fastLedTimer >= 100UL)
|
||||
{
|
||||
digitalWrite(ledPin, !digitalRead(ledPin));
|
||||
fastLedTimer = millis ();
|
||||
}
|
||||
}
|
||||
//
|
||||
void slowToggleLED ()
|
||||
{
|
||||
static unsigned long slowLedTimer;
|
||||
if (millis() - slowLedTimer >= 1250UL)
|
||||
{
|
||||
digitalWrite(ledPin, !digitalRead(ledPin));
|
||||
slowLedTimer = millis ();
|
||||
}
|
||||
}
|
||||
//
|
||||
void getVariables(const MyMessage &message)
|
||||
{
|
||||
boolean zoneTimeUpdate = false;
|
||||
if (message.isAck())
|
||||
{
|
||||
DEBUG_PRINTLN(F("This is an ack from gateway"));
|
||||
}
|
||||
for (byte i = 0; i <= NUMBER_OF_VALVES; i++)
|
||||
{
|
||||
if (message.sensor == i)
|
||||
{
|
||||
if (message.type == V_LIGHT)
|
||||
{
|
||||
int switchState = atoi(message.data);
|
||||
if (switchState == 0)
|
||||
{
|
||||
state = STAND_BY_ALL_OFF;
|
||||
DEBUG_PRINTLN(F("Recieved Instruction to Cancel..."));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
state = RUN_ALL_ZONES;
|
||||
valveNumber = 1;
|
||||
DEBUG_PRINTLN(F("Recieved Instruction to Run All Zones..."));
|
||||
}
|
||||
else
|
||||
{
|
||||
state = RUN_SINGLE_ZONE;
|
||||
valveNumber = i;
|
||||
DEBUG_PRINT(F("Recieved Instruction to Activate Zone: "));
|
||||
DEBUG_PRINTLN(i);
|
||||
}
|
||||
}
|
||||
startMillis = millis();
|
||||
}
|
||||
else if (message.type == V_VAR1)
|
||||
{
|
||||
int variable1 = atoi(message.data);// RUN_ALL_ZONES time
|
||||
DEBUG_PRINT(F("Recieved variable1 valve:"));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINT(F(" = "));
|
||||
DEBUG_PRINTLN(variable1);
|
||||
if (variable1 != allZoneTime[i])
|
||||
{
|
||||
allZoneTime[i] = variable1;
|
||||
|
||||
zoneTimeUpdate = true;
|
||||
}
|
||||
receivedInitialValue = true;
|
||||
}
|
||||
else if (message.type == V_VAR2)
|
||||
{
|
||||
int variable2 = atoi(message.data);// RUN_SINGLE_ZONE time
|
||||
DEBUG_PRINT(F("Recieved variable2 valve:"));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINT(F(" = "));
|
||||
DEBUG_PRINTLN(variable2);
|
||||
if (variable2 != valveSoloTime[i])
|
||||
{
|
||||
valveSoloTime[i] = variable2;
|
||||
zoneTimeUpdate = true;
|
||||
}
|
||||
receivedInitialValue = true;
|
||||
}
|
||||
else if (message.type == V_VAR3)
|
||||
{
|
||||
String newMessage = String(message.data);
|
||||
if (newMessage.length() == 0)
|
||||
{
|
||||
DEBUG_PRINT(F("No Name Recieved for zone "));
|
||||
DEBUG_PRINTLN(i);
|
||||
break;
|
||||
}
|
||||
if (newMessage.length() > 16)
|
||||
{
|
||||
newMessage.substring(0, 16);
|
||||
}
|
||||
valveNickName[i] = "";
|
||||
valveNickName[i] += newMessage;
|
||||
DEBUG_PRINT(F("Recieved new name for zone "));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINT(F(" and it is now called: "));
|
||||
DEBUG_PRINTLN(valveNickName[i]);
|
||||
}
|
||||
receivedInitialValue = true;
|
||||
}
|
||||
}
|
||||
if (zoneTimeUpdate)
|
||||
{
|
||||
//
|
||||
DEBUG_PRINTLN(F("New Zone Times Recieved..."));
|
||||
for (byte i = 0; i <= NUMBER_OF_VALVES; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
DEBUG_PRINT(F("Zone "));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINT(F(" individual time: "));
|
||||
DEBUG_PRINT(valveSoloTime[i]);
|
||||
DEBUG_PRINT(F(" group time: "));
|
||||
DEBUG_PRINTLN(allZoneTime[i]);
|
||||
recentUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
recentUpdate = false;
|
||||
}
|
||||
}
|
||||
//
|
||||
void updateDisplay()
|
||||
{
|
||||
static unsigned long lastUpdateTime;
|
||||
static boolean displayToggle = false;
|
||||
//static byte toggleCounter = 0;
|
||||
static SprinklerStates lastDisplayState;
|
||||
if (state != lastDisplayState || millis() - lastUpdateTime >= 3000UL)
|
||||
{
|
||||
displayToggle = !displayToggle;
|
||||
switch (state) {
|
||||
case STAND_BY_ALL_OFF:
|
||||
//
|
||||
fastClear();
|
||||
lcd.setCursor(0, 0);
|
||||
if (displayToggle)
|
||||
{
|
||||
lcd.print(F(" System Ready "));
|
||||
if (clockUpdating)
|
||||
{
|
||||
lcd.setCursor(15, 0);
|
||||
lcd.write(byte(0));
|
||||
}
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(hourFormat12() < 10 ? F(" ") : F(""));
|
||||
lcd.print(hourFormat12());
|
||||
lcd.print(minute() < 10 ? F(":0") : F(":"));
|
||||
lcd.print(minute());
|
||||
lcd.print(isAM() ? F("am") : F("pm"));
|
||||
lcd.print(month() < 10 ? F(" 0") : F(" "));
|
||||
lcd.print(month());
|
||||
lcd.print(day() < 10 ? F("/0") : F("/"));
|
||||
lcd.print(day());
|
||||
lcd.print(F("/"));
|
||||
lcd.print(year() % 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd.print(F(" Last Watered "));
|
||||
if (clockUpdating)
|
||||
{
|
||||
lcd.setCursor(15, 0);
|
||||
lcd.write(byte(0));
|
||||
}
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(dayOfWeek[weekday(lastTimeRun)]);
|
||||
lcd.setCursor(11, 1);
|
||||
lcd.print(month(lastTimeRun) < 10 ? F(" ") : F(""));
|
||||
lcd.print(month(lastTimeRun));
|
||||
lcd.print(day(lastTimeRun) < 10 ? F("/0") : F("/"));
|
||||
lcd.print(day(lastTimeRun));
|
||||
}
|
||||
break;
|
||||
case RUN_SINGLE_ZONE:
|
||||
//
|
||||
fastClear();
|
||||
lcd.setCursor(0, 0);
|
||||
if (displayToggle)
|
||||
{
|
||||
lcd.print(F("Single Zone Mode"));
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(F(" Zone:"));
|
||||
if (valveNumber < 10) lcd.print(F("0"));
|
||||
lcd.print(valveNumber);
|
||||
lcd.print(F(" Active"));
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd.print(F(" Time Remaining "));
|
||||
lcd.setCursor(0, 1);
|
||||
if (valveSoloTime[valveNumber] == 0)
|
||||
{
|
||||
lcd.print(F(" No Valve Time "));
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long timeRemaining = (valveSoloTime[valveNumber] * 60) - ((millis() - startMillis) / 1000);
|
||||
lcd.print(timeRemaining / 60 < 10 ? " 0" : " ");
|
||||
lcd.print(timeRemaining / 60);
|
||||
lcd.print("min");
|
||||
lcd.print(timeRemaining % 60 < 10 ? " 0" : " ");
|
||||
lcd.print(timeRemaining % 60);
|
||||
lcd.print("sec ");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RUN_ALL_ZONES:
|
||||
//
|
||||
fastClear();
|
||||
lcd.setCursor(0, 0);
|
||||
if (displayToggle)
|
||||
{
|
||||
lcd.print(F(" All-Zone Mode "));
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(F(" Zone:"));
|
||||
if (valveNumber < 10) lcd.print(F("0"));
|
||||
lcd.print(valveNumber);
|
||||
lcd.print(F(" Active "));
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd.print(F(" Time Remaining "));
|
||||
lcd.setCursor(0, 1);
|
||||
int timeRemaining = (allZoneTime[valveNumber] * 60) - ((millis() - startMillis) / 1000);
|
||||
lcd.print((timeRemaining / 60) < 10 ? " 0" : " ");
|
||||
lcd.print(timeRemaining / 60);
|
||||
lcd.print("min");
|
||||
lcd.print(timeRemaining % 60 < 10 ? " 0" : " ");
|
||||
lcd.print(timeRemaining % 60);
|
||||
lcd.print("sec ");
|
||||
}
|
||||
break;
|
||||
case CYCLE_COMPLETE:
|
||||
//
|
||||
if (displayToggle)
|
||||
{
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print(F(" Watering Cycle "));
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(F(" Complete "));
|
||||
}
|
||||
else
|
||||
{
|
||||
int totalTimeRan = 0;
|
||||
for (int i = 1; i < NUMBER_OF_VALVES + 1; i++)
|
||||
{
|
||||
totalTimeRan += allZoneTime[i];
|
||||
}
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print(F(" Total Time Run "));
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(totalTimeRan < 10 ? " 0" : " ");
|
||||
lcd.print(totalTimeRan);
|
||||
lcd.print(" Minutes ");
|
||||
}
|
||||
default:
|
||||
// what of ZONE_SELECT_MENU?
|
||||
break;
|
||||
}
|
||||
lastUpdateTime = millis();
|
||||
}
|
||||
lastDisplayState = state;
|
||||
}
|
||||
void receiveTime(time_t newTime)
|
||||
{
|
||||
DEBUG_PRINTLN(F("Time value received and updated..."));
|
||||
int lastSecond = second();
|
||||
int lastMinute = minute();
|
||||
int lastHour = hour();
|
||||
setTime(newTime);
|
||||
if (((second() != lastSecond) || (minute() != lastMinute) || (hour() != lastHour)) || showTime)
|
||||
{
|
||||
DEBUG_PRINTLN(F("Clock updated...."));
|
||||
DEBUG_PRINT(F("Sensor's time currently set to:"));
|
||||
DEBUG_PRINT(hourFormat12() < 10 ? F(" 0") : F(" "));
|
||||
DEBUG_PRINT(hourFormat12());
|
||||
DEBUG_PRINT(minute() < 10 ? F(":0") : F(":"));
|
||||
DEBUG_PRINT(minute());
|
||||
DEBUG_PRINTLN(isAM() ? F("am") : F("pm"));
|
||||
DEBUG_PRINT(month());
|
||||
DEBUG_PRINT(F("/"));
|
||||
DEBUG_PRINT(day());
|
||||
DEBUG_PRINT(F("/"));
|
||||
DEBUG_PRINTLN(year());
|
||||
DEBUG_PRINTLN(dayOfWeek[weekday()]);
|
||||
showTime = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_PRINTLN(F("Sensor's time did NOT need adjustment greater than 1 second."));
|
||||
}
|
||||
clockUpdating = false;
|
||||
}
|
||||
void fastClear()
|
||||
{
|
||||
lcd.setCursor(0, 0);
|
||||
lcd.print(F(" "));
|
||||
lcd.setCursor(0, 1);
|
||||
lcd.print(F(" "));
|
||||
}
|
||||
//
|
||||
void updateClock()
|
||||
{
|
||||
static unsigned long lastVeraGetTime;
|
||||
if (millis() - lastVeraGetTime >= 3600000UL) // updates clock time and gets zone times from vera once every hour
|
||||
{
|
||||
DEBUG_PRINTLN(F("Requesting time and valve data from Gateway..."));
|
||||
lcd.setCursor(15, 0);
|
||||
lcd.write(byte(0));
|
||||
clockUpdating = true;
|
||||
requestTime(receiveTime);
|
||||
lastVeraGetTime = millis();
|
||||
}
|
||||
}
|
||||
//
|
||||
void saveDateToEEPROM(unsigned long theDate)
|
||||
{
|
||||
DEBUG_PRINTLN(F("Saving Last Run date"));
|
||||
if (loadState(0) != 0xFF)
|
||||
{
|
||||
saveState(0, 0xFF); // EEPROM flag for last date saved stored in EEPROM (location zero)
|
||||
}
|
||||
//
|
||||
for (int i = 1; i < 5; i++)
|
||||
{
|
||||
saveState(5 - i, byte(theDate >> 8 * (i - 1))); // store epoch datestamp in 4 bytes of EEPROM starting in location one
|
||||
}
|
||||
}
|
||||
//
|
||||
void goGetValveTimes()
|
||||
{
|
||||
static unsigned long valveUpdateTime;
|
||||
static byte valveIndex = 1;
|
||||
if (millis() - valveUpdateTime >= 300000UL / NUMBER_OF_VALVES)// update each valve once every 5 mins (distributes the traffic)
|
||||
{
|
||||
DEBUG_PRINTLN(F("Calling for Valve Data..."));
|
||||
lcd.setCursor(15, 0);
|
||||
lcd.write(byte(1)); //lcd.write(1);
|
||||
request(valveIndex, V_VAR1);
|
||||
request(valveIndex, V_VAR2);
|
||||
request(valveIndex, V_VAR3);
|
||||
valveUpdateTime = millis();
|
||||
valveIndex++;
|
||||
if (valveIndex > NUMBER_OF_VALVES + 1)
|
||||
{
|
||||
valveIndex = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - idefix
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Arduino BH1750FVI Light sensor
|
||||
* communicate using I2C Protocol
|
||||
* this library enable 2 slave device addresses
|
||||
* Main address 0x23
|
||||
* secondary address 0x5C
|
||||
* connect the sensor as follows :
|
||||
*
|
||||
* VCC >>> 5V
|
||||
* Gnd >>> Gnd
|
||||
* ADDR >>> NC or GND
|
||||
* SCL >>> A5
|
||||
* SDA >>> A4
|
||||
* http://www.mysensors.org/build/light
|
||||
*/
|
||||
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <BH1750.h>
|
||||
#include <Wire.h>
|
||||
|
||||
#define CHILD_ID_LIGHT 0
|
||||
unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
|
||||
|
||||
BH1750 lightSensor;
|
||||
|
||||
// V_LIGHT_LEVEL should only be used for uncalibrated light level 0-100%.
|
||||
// If your controller supports the new V_LEVEL variable, use this instead for
|
||||
// transmitting LUX light level.
|
||||
MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
|
||||
// MyMessage msg(CHILD_ID_LIGHT, V_LEVEL);
|
||||
uint16_t lastlux;
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Light Lux Sensor", "1.0");
|
||||
|
||||
// Register all sensors to gateway (they will be created as child devices)
|
||||
present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
|
||||
|
||||
lightSensor.begin();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint16_t lux = lightSensor.readLightLevel();// Get Lux value
|
||||
Serial.println(lux);
|
||||
if (lux != lastlux) {
|
||||
send(msg.set(lux));
|
||||
lastlux = lux;
|
||||
}
|
||||
|
||||
sleep(SLEEP_TIME);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik EKblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Example sketch showing how to measue light level using a LM393 photo-resistor
|
||||
* http://www.mysensors.org/build/light
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define CHILD_ID_LIGHT 0
|
||||
#define LIGHT_SENSOR_ANALOG_PIN 0
|
||||
|
||||
unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
|
||||
|
||||
MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
|
||||
int lastLightLevel;
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Light Sensor", "1.0");
|
||||
|
||||
// Register all sensors to gateway (they will be created as child devices)
|
||||
present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
int lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23;
|
||||
Serial.println(lightLevel);
|
||||
if (lightLevel != lastLightLevel) {
|
||||
send(msg.set(lightLevel));
|
||||
lastLightLevel = lightLevel;
|
||||
}
|
||||
sleep(SLEEP_TIME);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
// This sketch is to integrate the Playing With Fusion AXS3935 Lightning Sensor Breakout Board
|
||||
// with the MySensors environment and is based on a sketch provided by Playing With Fusion
|
||||
// http://playingwithfusion.com/productview.php?pdid=22&catid=1001
|
||||
//
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include "MySensor.h"
|
||||
// include Playing With Fusion AXS3935 libraries
|
||||
#include "PWFusion_AS3935.h"
|
||||
|
||||
// setup CS pins used for the connection with the lightning sensor
|
||||
// other connections are controlled by the SPI library)
|
||||
int8_t CS_PIN = 8;
|
||||
int8_t SI_PIN = 7;
|
||||
int8_t IRQ_PIN = 3;
|
||||
volatile int8_t AS3935_ISR_Trig = 0;
|
||||
|
||||
// #defines
|
||||
#define AS3935_INDOORS 1
|
||||
#define AS3935_OUTDOORS 0
|
||||
#define AS3935_DIST_DIS 0
|
||||
#define AS3935_DIST_EN 1
|
||||
#define AS3935_CAPACITANCE 96 // <-- SET THIS VALUE TO THE NUMBER LISTED ON YOUR BOARD
|
||||
// prototypes
|
||||
void AS3935_ISR();
|
||||
|
||||
PWF_AS3935 lightning0(CS_PIN, IRQ_PIN, SI_PIN);
|
||||
|
||||
#define CHILD_ID_DISTANCE 1
|
||||
#define CHILD_ID_INTENSITY 2
|
||||
MyMessage msgDist(CHILD_ID_DISTANCE, V_DISTANCE);
|
||||
MyMessage msgInt(CHILD_ID_INTENSITY, V_VAR1);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Lightning Sensor", "1.1");
|
||||
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
present(CHILD_ID_DISTANCE, S_DISTANCE);
|
||||
present(CHILD_ID_INTENSITY, S_CUSTOM);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println("Playing With Fusion: AS3935 Lightning Sensor, SEN-39001");
|
||||
Serial.println("beginning boot procedure....");
|
||||
|
||||
// setup for the the SPI library:
|
||||
SPI.begin(); // begin SPI
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV4); // SPI speed to SPI_CLOCK_DIV16/1MHz (max 2MHz, NEVER 500kHz!)
|
||||
SPI.setDataMode(SPI_MODE1); // MAX31855 is a Mode 1 device
|
||||
// --> clock starts low, read on rising edge
|
||||
SPI.setBitOrder(MSBFIRST); // data sent to chip MSb first
|
||||
|
||||
lightning0.AS3935_DefInit(); // set registers to default
|
||||
// now update sensor cal for your application and power up chip
|
||||
lightning0.AS3935_ManualCal(AS3935_CAPACITANCE, AS3935_OUTDOORS, AS3935_DIST_EN);
|
||||
// AS3935_ManualCal Parameters:
|
||||
// --> capacitance, in pF (marked on package)
|
||||
// --> indoors/outdoors (AS3935_INDOORS:0 / AS3935_OUTDOORS:1)
|
||||
// --> disturbers (AS3935_DIST_EN:1 / AS3935_DIST_DIS:2)
|
||||
// function also powers up the chip
|
||||
|
||||
// enable interrupt (hook IRQ pin to Arduino Uno/Mega interrupt input: 1 -> pin 3 )
|
||||
attachInterrupt(1, AS3935_ISR, RISING);
|
||||
// dump the registry data to the serial port for troubleshooting purposes
|
||||
lightning0.AS3935_PrintAllRegs();
|
||||
|
||||
// delay execution to allow chip to stabilize.
|
||||
delay(1000);
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
// This program only handles an AS3935 lightning sensor. It does nothing until
|
||||
// an interrupt is detected on the IRQ pin.
|
||||
while(0 == AS3935_ISR_Trig){}
|
||||
|
||||
// reset interrupt flag
|
||||
AS3935_ISR_Trig = 0;
|
||||
|
||||
// now get interrupt source
|
||||
uint8_t int_src = lightning0.AS3935_GetInterruptSrc();
|
||||
if(0 == int_src)
|
||||
{
|
||||
Serial.println("Unknown interrupt source");
|
||||
}
|
||||
else if(1 == int_src)
|
||||
{
|
||||
uint8_t lightning_dist_km = lightning0.AS3935_GetLightningDistKm();
|
||||
uint32_t lightning_intensity = lightning0.AS3935_GetStrikeEnergyRaw();
|
||||
|
||||
Serial.print("Lightning detected! Distance to strike: ");
|
||||
Serial.print(lightning_dist_km);
|
||||
Serial.println(" kilometers");
|
||||
Serial.print("Lightning detected! Lightning Intensity: ");
|
||||
Serial.println(lightning_intensity);
|
||||
send(msgDist.set(lightning_dist_km));
|
||||
send(msgInt.set(lightning_intensity));
|
||||
}
|
||||
else if(2 == int_src)
|
||||
{
|
||||
Serial.println("Disturber detected");
|
||||
}
|
||||
else if(3 == int_src)
|
||||
{
|
||||
Serial.println("Noise level too high");
|
||||
}
|
||||
}
|
||||
|
||||
// this is irq handler for AS3935 interrupts, has to return void and take no arguments
|
||||
// always make code in interrupt handlers fast and short
|
||||
void AS3935_ISR()
|
||||
{
|
||||
AS3935_ISR_Trig = 1;
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - MrLynx
|
||||
*
|
||||
* DESCRIPTION
|
||||
* MAX6875 High temperature sensor with range: -200 degC - +1300 degC
|
||||
* http://forum.mysensors.org/topic/641/max6675
|
||||
*
|
||||
* Connect MAX6675 - Arduino
|
||||
* CS0 - 4
|
||||
* SO - 3
|
||||
* SCLK - 5
|
||||
* VCC - 5V
|
||||
* GND - GND
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <MAX6675.h>
|
||||
|
||||
uint8_t CS0 = 4; // CS pin on MAX6675
|
||||
uint8_t SO = 3; // SO pin of MAX6675
|
||||
uint8_t SCLK = 5; // SCK pin of MAX6675
|
||||
uint8_t units = 1; // Units to readout temp (0 = ˚F, 1 = ˚C)
|
||||
float temperature = 0.0; // Temperature output variable
|
||||
float lastTemperature;
|
||||
unsigned long SLEEP_TIME = 30000;
|
||||
boolean metric = true;
|
||||
|
||||
MyMessage msg(0, V_TEMP);
|
||||
|
||||
// Initialize the MAX6675 Library for our chip
|
||||
|
||||
MAX6675 temp0(CS0, SO, SCLK, units);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Max6675 Temp Sensor", "1.0");
|
||||
|
||||
// Present all sensors to controller
|
||||
present(0, S_TEMP);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
temperature = temp0.read_temp(); // Read the temp
|
||||
|
||||
if (temperature < 0) { // If there is an error with the TC, temperature will be < 0
|
||||
Serial.println("Thermocouple Error!!"); // There is a thermocouple error
|
||||
} else {
|
||||
Serial.print("Current Temperature: ");
|
||||
Serial.println( temperature ); // Print the temperature to Serial
|
||||
if (temperature != lastTemperature)
|
||||
send(msg.setSensor(0).set(temperature, 1));
|
||||
lastTemperature = temperature;
|
||||
}
|
||||
|
||||
sleep(SLEEP_TIME);
|
||||
}
|
||||
@@ -1,614 +0,0 @@
|
||||
/* MyMQTT Client Gateway 0.1b
|
||||
Created by Norbert Truchsess <norbert.truchsess@t-online.de>
|
||||
Based on MyMQTT-broker gateway created by Daniel Wiegert <daniel.wiegert@gmail.com>
|
||||
Based on MySensors Ethernet Gateway by Henrik Ekblad <henrik.ekblad@gmail.com>
|
||||
http://www.mysensors.org
|
||||
|
||||
Changes by Thomas Krebs <thkrebs@gmx.de>
|
||||
- Add signing support from MySensors 1.5 and update for MySensors 1.5;
|
||||
- Restructured code back to a C like implementation following the existing MQTTGateway
|
||||
Requires MySensors lib 1.5
|
||||
|
||||
* Change below; TCP_IP, TCP_PORT, TCP_MAC
|
||||
This will listen on your selected TCP_IP:TCP_PORT below, Please change TCP_MAC your liking also.
|
||||
*1 -> NOTE: Keep first byte at x2, x6, xA or xE (replace x with any hex value) for using Local Ranges.
|
||||
*2 You can use standard pin set-up as MySensors recommends or if you own a IBOARD you may change
|
||||
the radio-pins below if you hardware mod your iBoard. see [URL BELOW] for more details.
|
||||
http://forum.mysensors.org/topic/224/iboard-cheap-single-board-ethernet-arduino-with-radio/5
|
||||
* Don't forget to look at the definitions in libraries\MySensors\MyMQTT.h!
|
||||
define TCPDUMP and connect serial interface if you have problems, please write on
|
||||
http://forum.mysensors.org/ and explain your problem, include serial output. Don't forget to
|
||||
turn on DEBUG in libraries\MySensors\MyConfig.h also.
|
||||
MQTT_FIRST_SENSORID is for 'DHCP' server in MyMQTT. You may limit the ID's with FIRST and LAST definition.
|
||||
If you want your manually configured below 20 set MQTT_FIRST_SENSORID to 20.
|
||||
To disable: set MQTT_FIRST_SENSORID to 255.
|
||||
MQTT_BROKER_PREFIX is the leading prefix for your nodes. This can be only one char if like.
|
||||
MQTT_SEND_SUBSCRIPTION is if you want the MyMQTT to send a empty payload message to your nodes.
|
||||
This can be useful if you want to send latest state back to the MQTT client. Just check if incoming
|
||||
message has any length or not.
|
||||
Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things.
|
||||
* Address-layout is : [MQTT_BROKER_PREFIX]/[NodeID]/[SensorID]/V_[SensorType][/set | /get]
|
||||
NodeID and SensorID is uint8 (0-255) number.
|
||||
Segment after SensorID is translation of the sensor type, look inside MyMQTT.cpp for the definitions.
|
||||
User can change this to their needs. We have also left some space for custom types.
|
||||
Special: (sensor 255 reserved for special commands)
|
||||
|
||||
The last seqment is a command to to be send down to the sensor. The gateway is subscribed to topics which have
|
||||
a command present! This is to avoid that a publish by the gateway will end up in the gateway via it subsription.
|
||||
You can receive a node sketch name with MyMQTT/20/255/V_Sketch_name (or version with _version)
|
||||
|
||||
So far tested in openhab and MyMQTT for Android (Not my creation)
|
||||
- http://www.openhab.org/
|
||||
* How to set-up Openhab and MQTTGateway:
|
||||
http://forum.mysensors.org/topic/303/mqtt-broker-gateway
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <MySensor.h>
|
||||
#include <MyTransport.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <Ethernet.h>
|
||||
#include <DigitalIO.h>
|
||||
#include <MsTimer2.h>
|
||||
#include <Time.h>
|
||||
|
||||
#include "MyMQTTClient.h"
|
||||
|
||||
#ifdef MY_SIGNING_FEATURE
|
||||
#include <MySigningNone.h>
|
||||
#include <MySigningAtsha204Soft.h>
|
||||
#include <MySigningAtsha204.h>
|
||||
#endif
|
||||
|
||||
//#define DSRTC
|
||||
#ifdef DSRTC
|
||||
#include <Wire.h>
|
||||
#include <DS1307RTC.h> // a basic DS1307 library that returns time as a time_t
|
||||
#endif
|
||||
|
||||
/*
|
||||
* To configure MQTTClientGateway.ino to use an ENC28J60 based board include
|
||||
* 'UIPEthernet.h' (SPI.h required for MySensors anyway). The UIPEthernet-library can be downloaded
|
||||
* from: https://github.com/ntruchsess/arduino_uip
|
||||
*/
|
||||
|
||||
//#include <UIPEthernet.h>
|
||||
/*
|
||||
* To execute MQTTClientGateway.ino on Yun uncomment Bridge.h and YunClient.h.
|
||||
* Do not include Ethernet.h or SPI.h in this case.
|
||||
* On Yun there's no need to configure local_ip and mac in the sketch
|
||||
* as this is configured on the linux-side of Yun.
|
||||
*/
|
||||
|
||||
//#include <Bridge.h>
|
||||
//#include <YunClient.h>
|
||||
// * Use this for IBOARD modded to use standard MISO/MOSI/SCK, see note *1 above!
|
||||
/*
|
||||
#define RADIO_CE_PIN 3 // radio chip enable
|
||||
#define RADIO_SPI_SS_PIN 8 // radio SPI serial select
|
||||
#define RADIO_ERROR_LED_PIN A2 // Error led pin
|
||||
#define RADIO_RX_LED_PIN A1 // Receive led pin
|
||||
#define RADIO_TX_LED_PIN A0 // the PCB, on board LED*/
|
||||
|
||||
// * Use this for default configured pro mini / nano etc :
|
||||
//
|
||||
|
||||
//#define RADIO_CE_PIN 5 // radio chip enable
|
||||
//#define RADIO_SPI_SS_PIN 6 // radio SPI serial select
|
||||
//#define RADIO_ERROR_LED_PIN 7 // Error led pin
|
||||
//#define RADIO_RX_LED_PIN 8 // Receive led pin
|
||||
//#define RADIO_TX_LED_PIN 9 // the PCB, on board LED*/
|
||||
|
||||
// CE_PIN and SPI_SS_PIN for Mega
|
||||
#define RADIO_CE_PIN 48 // radio chip enable
|
||||
#define RADIO_SPI_SS_PIN 49 // radio SPI serial select
|
||||
#define RADIO_ERROR_LED_PIN A2 // Error led pin
|
||||
#define RADIO_RX_LED_PIN A1 // Receive led pin
|
||||
#define RADIO_TX_LED_PIN A0 // the PCB, on board LED*/
|
||||
|
||||
//replace with ip of server you want to connect to, comment out if using 'remote_host'
|
||||
uint8_t remote_ip[] = { 192, 168, 178, 74 }; // Mosquitto broker
|
||||
|
||||
//replace with hostname of server you want to connect to, comment out if using 'remote_ip'
|
||||
//char* remote_ip = "server.local";
|
||||
//replace with the port that your server is listening on
|
||||
#define remote_port 1883
|
||||
//replace with arduinos ip-address. Comment out if Ethernet-startup should use dhcp. Is ignored on Yun
|
||||
uint8_t local_ip[] = {192, 168, 178, 11};
|
||||
//replace with ethernet shield mac. It's mandatory every device is assigned a unique mac. Is ignored on Yun
|
||||
uint8_t mac[] = { 0xA2, 0xAE, 0xAD, 0xA0, 0xA0, 0xA2 };
|
||||
|
||||
#if defined remote_ip && defined remote_host
|
||||
#error "cannot define both remote_ip and remote_host at the same time!"
|
||||
#endif
|
||||
|
||||
#ifdef _YUN_CLIENT_H_
|
||||
YunClient ethClient;
|
||||
#else
|
||||
EthernetClient ethClient;
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// NRFRF24L01 radio driver (set low transmit power by default)
|
||||
MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW);
|
||||
//MyTransportRFM69 transport;
|
||||
|
||||
// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h)
|
||||
//MySigningNone signer;
|
||||
//MySigningAtsha204Soft signer(true);
|
||||
//MySigningAtsha204 signer;
|
||||
|
||||
// Hardware profile
|
||||
MyHwATMega328 hw;
|
||||
|
||||
MyMessage msg;
|
||||
char convBuf[MAX_PAYLOAD * 2 + 1];
|
||||
uint8_t buffsize;
|
||||
char buffer[MQTT_MAX_PACKET_SIZE];
|
||||
char user[sizeof(MQTT_USER)]; // introduced the bufs to get rid of compiler warnings
|
||||
char pwd[sizeof(MQTT_PWD)]; // see above
|
||||
char connID[sizeof(MQTT_CONN_ID)]; // see above
|
||||
char mqttTopicMask[sizeof(MQTT_TOPIC_MASK)]; // see above
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
volatile uint8_t countRx;
|
||||
volatile uint8_t countTx;
|
||||
volatile uint8_t countErr;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void processMQTTMessages(char* topic, byte* payload, unsigned int length);
|
||||
PubSubClient client(remote_ip, remote_port, processMQTTMessages, ethClient);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Declare and initialize MySensor instance
|
||||
// Construct MyMQTTClient (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h, if signing
|
||||
// feature not to be used, uncomment)
|
||||
// To use LEDs blinking, uncomment WITH_LEDS_BLINKING in MyConfig.h
|
||||
MySensor gw(transport, hw
|
||||
#ifdef MY_SIGNING_FEATURE
|
||||
, signer
|
||||
#endif
|
||||
#ifdef WITH_LEDS_BLINKING
|
||||
, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN
|
||||
#endif
|
||||
);
|
||||
|
||||
/*
|
||||
* setup
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
strcpy(connID,MQTT_CONN_ID);
|
||||
strcpy(mqttTopicMask,MQTT_TOPIC_MASK);
|
||||
|
||||
countRx = 0;
|
||||
countTx = 0;
|
||||
countErr = 0;
|
||||
|
||||
Ethernet.begin(mac, local_ip);
|
||||
//Bridge.begin();
|
||||
delay(1000); // Wait for Ethernet to get configured.
|
||||
|
||||
begin();
|
||||
}
|
||||
|
||||
/*
|
||||
* loop
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
if (!client.connected())
|
||||
{
|
||||
boolean ret;
|
||||
#ifdef MQTT_AUTH_REQUIRED
|
||||
strcpy(user, MQTT_USER);
|
||||
strcpy(pwd, MQTT_PWD);
|
||||
ret = client.connect(connID, user,pwd);
|
||||
#else
|
||||
ret = client.connect(connID);
|
||||
#endif
|
||||
if (ret) {
|
||||
Serial.println("Connected to MQTT broker");
|
||||
} else {
|
||||
Serial.println("Connection to MQTT broker failed");
|
||||
}
|
||||
client.subscribe(mqttTopicMask);
|
||||
}
|
||||
client.loop();
|
||||
gw.process();
|
||||
}
|
||||
|
||||
/*
|
||||
* processRadioMessage
|
||||
*
|
||||
* Receives radio message, parses it and forwards it to the MQTT broker
|
||||
*/
|
||||
void processRadioMessage(const MyMessage &message)
|
||||
{
|
||||
rxBlink(1);
|
||||
sendMQTT(message);
|
||||
}
|
||||
|
||||
/*
|
||||
* sendMQTT
|
||||
* Handles processing of radio messages and eventually publishes it to the MQTT broker
|
||||
*/
|
||||
void sendMQTT(const MyMessage &inMsg)
|
||||
{
|
||||
MyMessage msg = inMsg;
|
||||
buffsize = 0;
|
||||
if (!client.connected())
|
||||
return; //We have no connections - return
|
||||
if (msg.isAck())
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Serial.println("msg is ack!");
|
||||
#endif
|
||||
if (msg.sender == 255 && mGetCommand(msg) == C_INTERNAL
|
||||
&& msg.type == I_ID_REQUEST)
|
||||
{
|
||||
// TODO: sending ACK request on id_response fucks node up. doesn't work.
|
||||
// The idea was to confirm id and save to EEPROM_LATEST_NODE_ADDRESS.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have to check every message if its a newly assigned id or not.
|
||||
// Ack on I_ID_RESPONSE does not work, and checking on C_PRESENTATION isn't reliable.
|
||||
uint8_t newNodeID = gw.loadState(EEPROM_LATEST_NODE_ADDRESS) + 1;
|
||||
if (newNodeID <= MQTT_FIRST_SENSORID)
|
||||
newNodeID = MQTT_FIRST_SENSORID;
|
||||
if (msg.sender == newNodeID)
|
||||
{
|
||||
gw.saveState(EEPROM_LATEST_NODE_ADDRESS, newNodeID);
|
||||
}
|
||||
if (mGetCommand(msg) == C_INTERNAL)
|
||||
{
|
||||
if (msg.type == I_CONFIG)
|
||||
{
|
||||
txBlink(1);
|
||||
if (!gw.sendRoute(
|
||||
build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL,
|
||||
I_CONFIG, 0).set("M")))
|
||||
errBlink(1);
|
||||
}
|
||||
else if (msg.type == I_TIME)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Serial.println("I_TIME requested!");
|
||||
#endif
|
||||
txBlink(1);
|
||||
if (!gw.sendRoute(
|
||||
build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL,
|
||||
I_TIME, 0).set(now())))
|
||||
errBlink(1);
|
||||
}
|
||||
else if (msg.type == I_ID_REQUEST && msg.sender == 255)
|
||||
{
|
||||
uint8_t newNodeID = gw.loadState(EEPROM_LATEST_NODE_ADDRESS) + 1;
|
||||
if (newNodeID <= MQTT_FIRST_SENSORID)
|
||||
newNodeID = MQTT_FIRST_SENSORID;
|
||||
if (newNodeID >= MQTT_LAST_SENSORID)
|
||||
return; // Sorry no more id's left :(
|
||||
txBlink(1);
|
||||
if (!gw.sendRoute(
|
||||
build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL,
|
||||
I_ID_RESPONSE, 0).set(newNodeID)))
|
||||
errBlink(1);
|
||||
}
|
||||
else if (msg.type == I_BATTERY_LEVEL)
|
||||
{
|
||||
strcpy_P(buffer, mqtt_prefix);
|
||||
buffsize += strlen_P(mqtt_prefix);
|
||||
buffsize += sprintf(&buffer[buffsize], "/%i/255/BATTERY_LEVEL", msg.sender );
|
||||
msg.getString(convBuf);
|
||||
#ifdef DEBUG
|
||||
Serial.print("publish: ");
|
||||
Serial.print((char*) buffer);
|
||||
Serial.print(" ");
|
||||
Serial.println((char*) convBuf);
|
||||
#endif
|
||||
client.publish(buffer, convBuf);
|
||||
}
|
||||
else if (msg.type == I_SKETCH_NAME)
|
||||
{
|
||||
strcpy_P(buffer, mqtt_prefix);
|
||||
buffsize += strlen_P(mqtt_prefix);
|
||||
buffsize += sprintf(&buffer[buffsize], "/%i/255/SKETCH_NAME", msg.sender );
|
||||
msg.getString(convBuf);
|
||||
#ifdef DEBUG
|
||||
Serial.print("publish: ");
|
||||
Serial.print((char*) buffer);
|
||||
Serial.print(" ");
|
||||
Serial.println((char*) convBuf);
|
||||
#endif
|
||||
client.publish(buffer, convBuf);
|
||||
}
|
||||
else if (msg.type == I_SKETCH_VERSION)
|
||||
{
|
||||
strcpy_P(buffer, mqtt_prefix);
|
||||
buffsize += strlen_P(mqtt_prefix);
|
||||
buffsize += sprintf(&buffer[buffsize], "/%i/255/SKETCH_VERSION", msg.sender );
|
||||
msg.getString(convBuf);
|
||||
#ifdef DEBUG
|
||||
Serial.print("publish: ");
|
||||
Serial.print((char*) buffer);
|
||||
Serial.print(" ");
|
||||
Serial.println((char*) convBuf);
|
||||
#endif
|
||||
client.publish(buffer, convBuf);
|
||||
}
|
||||
|
||||
}
|
||||
else if (mGetCommand(msg) != 0)
|
||||
{
|
||||
if (mGetCommand(msg) == 3)
|
||||
msg.type = msg.type + (S_FIRSTCUSTOM - 10); //Special message
|
||||
|
||||
if (msg.type > VAR_TOTAL)
|
||||
msg.type = VAR_TOTAL; // If type > defined types set to unknown.
|
||||
strcpy_P(buffer, mqtt_prefix);
|
||||
buffsize += strlen_P(mqtt_prefix);
|
||||
buffsize += sprintf(&buffer[buffsize], "/%i/%i/V_%s", msg.sender,
|
||||
msg.sensor, getType(convBuf, &VAR_Type[msg.type]));
|
||||
msg.getString(convBuf);
|
||||
#ifdef DEBUG
|
||||
Serial.print("publish: ");
|
||||
Serial.print((char*) buffer);
|
||||
Serial.print(" ");
|
||||
Serial.println((char*) convBuf);
|
||||
#endif
|
||||
client.publish(buffer, convBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* build
|
||||
* Constructs a radio message
|
||||
*/
|
||||
inline MyMessage& build(MyMessage &msg, uint8_t sender, uint8_t destination, uint8_t sensor,
|
||||
uint8_t command, uint8_t type, bool enableAck)
|
||||
{
|
||||
msg.destination = destination;
|
||||
msg.sender = sender;
|
||||
msg.sensor = sensor;
|
||||
msg.type = type;
|
||||
mSetCommand(msg, command);
|
||||
mSetRequestAck(msg, enableAck);
|
||||
mSetAck(msg, false);
|
||||
return msg;
|
||||
}
|
||||
|
||||
/*
|
||||
* getType
|
||||
*/
|
||||
char *getType(char *b, const char **index)
|
||||
{
|
||||
char *q = b;
|
||||
char *p = (char *) pgm_read_word(index);
|
||||
while (*q++ = pgm_read_byte(p++))
|
||||
;
|
||||
*q = 0;
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
* begin
|
||||
* wraps MySensors begin method; setup of RTC and led timers interrupt
|
||||
*/
|
||||
void begin()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Serial.begin(BAUD_RATE);
|
||||
#endif
|
||||
#ifdef DSRTC
|
||||
// Attach RTC
|
||||
setSyncProvider(RTC.get); // the function to get the time from the RTC
|
||||
setSyncInterval(60);
|
||||
#endif
|
||||
|
||||
gw.begin(processRadioMessage, 0, true, 0);
|
||||
|
||||
MsTimer2::set(200, ledTimersInterrupt);
|
||||
MsTimer2::start();
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print(getType(convBuf, &VAR_Type[S_FIRSTCUSTOM]));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* processMQTTMessages
|
||||
* message handler for the PubSubClient
|
||||
*/
|
||||
void processMQTTMessages(char* topic, byte* payload, unsigned int length)
|
||||
{
|
||||
processMQTTMessage(topic, payload, length);
|
||||
}
|
||||
|
||||
/*
|
||||
* processMQTTMessage
|
||||
* processes MQTT messages, parses the topic, extracts radio address out of topic and sends them
|
||||
* to the respective radio
|
||||
*/
|
||||
void processMQTTMessage(char* topic, byte* payload,
|
||||
unsigned int length)
|
||||
{
|
||||
char *str, *p;
|
||||
uint8_t i = 0;
|
||||
buffer[0] = 0;
|
||||
buffsize = 0;
|
||||
int8_t cmd = -1;
|
||||
|
||||
for (str = strtok_r(topic, "/", &p); str && i < 5;
|
||||
str = strtok_r(NULL, "/", &p))
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (strcmp_P(str, mqtt_prefix) != 0)
|
||||
{ //look for MQTT_PREFIX
|
||||
return; //Message not for us or malformatted!
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
msg.destination = atoi(str); //NodeID
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
msg.sensor = atoi(str); //SensorID
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
char match = 0; //SensorType
|
||||
//strcpy(str,(char*)&str[2]); //Strip VAR_
|
||||
|
||||
for (uint8_t j = 0;
|
||||
strcpy_P(convBuf, (char*) pgm_read_word(&(VAR_Type[j]))); j++)
|
||||
{
|
||||
if (strcmp((char*) &str[2], convBuf) == 0)
|
||||
{ //Strip VAR_ and compare
|
||||
match = j;
|
||||
break;
|
||||
}
|
||||
if (j >= VAR_TOTAL)
|
||||
{ // No match found!
|
||||
match = VAR_TOTAL; // last item.
|
||||
break;
|
||||
}
|
||||
}
|
||||
msg.type = match;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
// support the command get and set; get will be mapped to a C_REQ and set to C_SET
|
||||
if (strcmp(str,MQTT_CMD_SET) == 0)
|
||||
{
|
||||
cmd = C_SET;
|
||||
}
|
||||
else if (strcmp(str,MQTT_CMD_GET) == 0) {
|
||||
cmd = C_REQ;
|
||||
}
|
||||
else {
|
||||
#ifdef DEBUG
|
||||
Serial.print("Received unsupported command - ignore: ");
|
||||
Serial.println(str);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} //Check if packge has payload
|
||||
|
||||
if (cmd != -1) {
|
||||
char* ca;
|
||||
ca = (char *)payload;
|
||||
ca += length;
|
||||
*ca = '\0';
|
||||
|
||||
msg.set((const char*)payload); //Payload
|
||||
|
||||
txBlink(1);
|
||||
// inject time
|
||||
if ((msg.destination == 0) && (msg.sensor == 199)) {
|
||||
unsigned long epoch = atol((char*)payload);
|
||||
if (epoch > 10000) {
|
||||
#ifdef DSRTC
|
||||
RTC.set(epoch); // this sets the RTC to the time from controller - which we do want periodically
|
||||
#endif
|
||||
setTime(epoch);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
Serial.print("Time received ");
|
||||
Serial.println(epoch);
|
||||
#endif
|
||||
}
|
||||
//
|
||||
if (!gw.sendRoute(
|
||||
build(msg, GATEWAY_ADDRESS, msg.destination, msg.sensor, C_SET, msg.type,
|
||||
0)))
|
||||
errBlink(1);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Led handling
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* ledTimersIntterupt
|
||||
*/
|
||||
void ledTimersInterrupt() {
|
||||
if (countRx && countRx != 255) {
|
||||
// switch led on
|
||||
digitalWrite(RADIO_RX_LED_PIN, LOW);
|
||||
} else if (!countRx) {
|
||||
// switching off
|
||||
digitalWrite(RADIO_RX_LED_PIN, HIGH);
|
||||
}
|
||||
if (countRx != 255) {
|
||||
countRx--;
|
||||
}
|
||||
|
||||
if (countTx && countTx != 255) {
|
||||
// switch led on
|
||||
digitalWrite(RADIO_TX_LED_PIN, LOW);
|
||||
} else if (!countTx) {
|
||||
// switching off
|
||||
digitalWrite(RADIO_TX_LED_PIN, HIGH);
|
||||
}
|
||||
if (countTx != 255) {
|
||||
countTx--;
|
||||
}
|
||||
|
||||
if (countErr && countErr != 255) {
|
||||
// switch led on
|
||||
digitalWrite(RADIO_ERROR_LED_PIN, LOW);
|
||||
} else if (!countErr) {
|
||||
// switching off
|
||||
digitalWrite(RADIO_ERROR_LED_PIN, HIGH);
|
||||
}
|
||||
if (countErr != 255) {
|
||||
countErr--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rxBlink(uint8_t cnt)
|
||||
{
|
||||
if (countRx == 255)
|
||||
{
|
||||
countRx = cnt;
|
||||
}
|
||||
}
|
||||
|
||||
void txBlink(uint8_t cnt)
|
||||
{
|
||||
if (countTx == 255)
|
||||
{
|
||||
countTx = cnt;
|
||||
}
|
||||
}
|
||||
|
||||
void errBlink(uint8_t cnt)
|
||||
{
|
||||
if (countErr == 255)
|
||||
{
|
||||
countErr = cnt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
The MySensors library adds a new layer on top of the RF24 library.
|
||||
It handles radio network routing, relaying and ids.
|
||||
Created by Henrik Ekblad <henrik.ekblad@gmail.com>
|
||||
Modified by Daniel Wiegert
|
||||
Modified by Norbert Truchsess <norbert.truchsess@t-online.de>
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MyMQTTClient_h
|
||||
#define MyMQTTClient_h
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef DEBUG
|
||||
#define TCPDUMP // Dump TCP packages.
|
||||
#endif
|
||||
#define MQTT_FIRST_SENSORID 20 // If you want manually configured nodes below this value. 255 = Disable
|
||||
#define MQTT_LAST_SENSORID 254 // 254 is max! 255 reserved.
|
||||
#define MQTT_PREFIX "MyMQTT" // First prefix in MQTT tree, keep short!
|
||||
#define MQTT_TOPIC_MASK "MyMQTT/+/+/+/+" // Topic mask the client will subscribe to. This ensures that it will not receive any sensor data send by sensors
|
||||
// the following topic structure is assumed: MyMQTT/<node-id>/<child_id>/<sensor-type>/<cmd>
|
||||
#define MQTT_SEND_SUBSCRIPTION 1 // Send empty payload (request) to node upon MQTT client subscribe request.
|
||||
#define MQTT_CMD_SET "set" // command (see MQTT_TOPIC_MASK); mapped to C_SET command type of sensor network
|
||||
#define MQTT_CMD_GET "get" // command (see MQTT_TOPIC_MASK); mapped to C_REQ command type of sensor network
|
||||
|
||||
|
||||
#define MQTT_AUTH_REQUIRED // if your broker has anonymous access uncomment
|
||||
#define MQTT_USER "user" // username on MQTT broker
|
||||
#define MQTT_PWD "pwd" // password for MQTT username above
|
||||
#define MQTT_CONN_ID "MySensors" // passed as id to the MQTT broker
|
||||
|
||||
|
||||
// NOTE above : Beware to check if there is any length on payload in your incommingMessage code:
|
||||
// Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things.
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
char VAR_0[] PROGMEM = "TEMP"; //V_TEMP
|
||||
char VAR_1[] PROGMEM = "HUM"; //V_HUM
|
||||
char VAR_2[] PROGMEM = "LIGHT"; //V_LIGHT
|
||||
char VAR_3[] PROGMEM = "DIMMER"; //V_DIMMER
|
||||
char VAR_4[] PROGMEM = "PRESSURE"; //V_PRESSURE
|
||||
char VAR_5[] PROGMEM = "FORECAST"; //V_FORECAST
|
||||
char VAR_6[] PROGMEM = "RAIN"; //V_RAIN
|
||||
char VAR_7[] PROGMEM = "RAINRATE"; //V_RAINRATE
|
||||
char VAR_8[] PROGMEM = "WIND"; //V_WIND
|
||||
char VAR_9[] PROGMEM = "GUST"; //V_GUST
|
||||
char VAR_10[] PROGMEM = "DIRECTON"; //V_DIRECTON
|
||||
char VAR_11[] PROGMEM = "UV"; //V_UV
|
||||
char VAR_12[] PROGMEM = "WEIGHT"; //V_WEIGHT
|
||||
char VAR_13[] PROGMEM = "DISTANCE"; //V_DISTANCE
|
||||
char VAR_14[] PROGMEM = "IMPEDANCE"; //V_IMPEDANCE
|
||||
char VAR_15[] PROGMEM = "ARMED"; //V_ARMED
|
||||
char VAR_16[] PROGMEM = "TRIPPED"; //V_TRIPPED
|
||||
char VAR_17[] PROGMEM = "WATT"; //V_WATT
|
||||
char VAR_18[] PROGMEM = "KWH"; //V_KWH
|
||||
char VAR_19[] PROGMEM = "SCENE_ON"; //V_SCENE_ON
|
||||
char VAR_20[] PROGMEM = "SCENE_OFF"; //V_SCENE_OFF
|
||||
char VAR_21[] PROGMEM = "HEATER"; //V_HEATER
|
||||
char VAR_22[] PROGMEM = "HEATER_SW"; //V_HEATER_SW
|
||||
char VAR_23[] PROGMEM = "LIGHT_LEVEL"; //V_LIGHT_LEVEL
|
||||
char VAR_24[] PROGMEM = "VAR1"; //V_VAR1
|
||||
char VAR_25[] PROGMEM = "VAR2"; //V_VAR2
|
||||
char VAR_26[] PROGMEM = "VAR3"; //V_VAR3
|
||||
char VAR_27[] PROGMEM = "VAR4"; //V_VAR4
|
||||
char VAR_28[] PROGMEM = "VAR5"; //V_VAR5
|
||||
char VAR_29[] PROGMEM = "UP"; //V_UP
|
||||
char VAR_30[] PROGMEM = "DOWN"; //V_DOWN
|
||||
char VAR_31[] PROGMEM = "STOP"; //V_STOP
|
||||
char VAR_32[] PROGMEM = "IR_SEND"; //V_IR_SEND
|
||||
char VAR_33[] PROGMEM = "IR_RECEIVE"; //V_IR_RECEIVE
|
||||
char VAR_34[] PROGMEM = "FLOW"; //V_FLOW
|
||||
char VAR_35[] PROGMEM = "VOLUME"; //V_VOLUME
|
||||
char VAR_36[] PROGMEM = "LOCK_STATUS"; //V_LOCK_STATUS
|
||||
char VAR_37[] PROGMEM = "LEVEL"; // S_DUST, S_LIGHT_LEVEL, ...
|
||||
char VAR_38[] PROGMEM = "VOLTAGE"; //V_VOLTAGE
|
||||
char VAR_39[] PROGMEM = "CURRENT"; //V_CURRENT
|
||||
char VAR_40[] PROGMEM = "RGB"; //V_RGB
|
||||
char VAR_41[] PROGMEM = ""; //
|
||||
char VAR_42[] PROGMEM = ""; //
|
||||
char VAR_43[] PROGMEM = ""; //
|
||||
char VAR_44[] PROGMEM = ""; //
|
||||
char VAR_45[] PROGMEM = ""; //
|
||||
char VAR_46[] PROGMEM = ""; //
|
||||
char VAR_47[] PROGMEM = ""; //
|
||||
char VAR_48[] PROGMEM = ""; //
|
||||
char VAR_49[] PROGMEM = ""; //
|
||||
char VAR_50[] PROGMEM = ""; //
|
||||
char VAR_51[] PROGMEM = ""; //
|
||||
char VAR_52[] PROGMEM = ""; //
|
||||
char VAR_53[] PROGMEM = ""; //
|
||||
char VAR_54[] PROGMEM = ""; //
|
||||
char VAR_55[] PROGMEM = ""; //
|
||||
char VAR_56[] PROGMEM = ""; //
|
||||
char VAR_57[] PROGMEM = ""; //
|
||||
char VAR_58[] PROGMEM = ""; //
|
||||
char VAR_59[] PROGMEM = ""; //
|
||||
char VAR_60[] PROGMEM = "Started!\n"; //Custom for MQTTGateway
|
||||
char VAR_61[] PROGMEM = "SKETCH_NAME"; //Custom for MQTTGateway
|
||||
char VAR_62[] PROGMEM = "SKETCH_VERSION"; //Custom for MQTTGateway
|
||||
char VAR_63[] PROGMEM = "UNKNOWN"; //Custom for MQTTGateway
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
PROGMEM const char *VAR_Type[] =
|
||||
{ VAR_0, VAR_1, VAR_2, VAR_3, VAR_4, VAR_5, VAR_6, VAR_7, VAR_8, VAR_9, VAR_10, VAR_11, VAR_12, VAR_13,
|
||||
VAR_14, VAR_15, VAR_16, VAR_17, VAR_18, VAR_19, VAR_20, VAR_21, VAR_22, VAR_23, VAR_24, VAR_25,
|
||||
VAR_26, VAR_27, VAR_28, VAR_29, VAR_30, VAR_31, VAR_32, VAR_33, VAR_34, VAR_35, VAR_36, VAR_37,
|
||||
VAR_38, VAR_39, VAR_40, VAR_41, VAR_42, VAR_43, VAR_44, VAR_45, VAR_46, VAR_47, VAR_48, VAR_49,
|
||||
VAR_50, VAR_51, VAR_52, VAR_53, VAR_54, VAR_55, VAR_56, VAR_57, VAR_58, VAR_59, VAR_60, VAR_61,
|
||||
VAR_62, VAR_63
|
||||
};
|
||||
|
||||
char mqtt_prefix[] PROGMEM = MQTT_PREFIX;
|
||||
|
||||
#define S_FIRSTCUSTOM 60
|
||||
#define TYPEMAXLEN 20
|
||||
#define VAR_TOTAL (sizeof(VAR_Type)/sizeof(char *))-1
|
||||
|
||||
|
||||
#define EEPROM_LATEST_NODE_ADDRESS ((uint8_t)EEPROM_LOCAL_CONFIG_ADDRESS)
|
||||
|
||||
//#define DSRTC // RTC Dallas support -> disable debug and use isp programmer to free memory
|
||||
#endif
|
||||
@@ -1,474 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Created by Daniel Wiegert <daniel.wiegert@gmail.com>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* MyMQTT Broker Gateway 0.1b
|
||||
* Latest instructions found here:
|
||||
* http://www.mysensors.org/build/mqtt_gateway
|
||||
* http://www.mysensors.org/build/ethernet_gateway
|
||||
*
|
||||
* Change below; TCP_IP, TCP_PORT, TCP_MAC
|
||||
* This will listen on your selected TCP_IP:TCP_PORT below, Please change TCP_MAC your liking also.
|
||||
* 1 -> NOTE: Keep first byte at x2, x6, xA or xE (replace x with any hex value) for using Local Ranges.
|
||||
* 2 You can use standard pin set-up as MySensors recommends or if you own a IBOARD you may change
|
||||
* the radio-pins below if you hardware mod your iBoard. see [URL BELOW] for more details.
|
||||
* http://forum.mysensors.org/topic/224/iboard-cheap-single-board-ethernet-arduino-with-radio/5
|
||||
*
|
||||
* Don't forget to look at the definitions in MyMQTT.h!
|
||||
*
|
||||
* define TCPDUMP and connect serial interface if you have problems, please write on
|
||||
* http://forum.mysensors.org/ and explain your problem, include serial output. Don't forget to
|
||||
* turn on DEBUG in libraries\MySensors\MyConfig.h also.
|
||||
*
|
||||
* MQTT_FIRST_SENSORID is for 'DHCP' server in MyMQTT. You may limit the ID's with FIRST and LAST definition.
|
||||
* If you want your manually configured below 20 set MQTT_FIRST_SENSORID to 20.
|
||||
* To disable: set MQTT_FIRST_SENSORID to 255.
|
||||
*
|
||||
* MQTT_BROKER_PREFIX is the leading prefix for your nodes. This can be only one char if like.
|
||||
*
|
||||
* MQTT_SEND_SUBSCRIPTION is if you want the MyMQTT to send a empty payload message to your nodes.
|
||||
* This can be useful if you want to send latest state back to the MQTT client. Just check if incoming
|
||||
* message has any length or not.
|
||||
* Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things.
|
||||
*
|
||||
* (*) Address-layout is : [MQTT_BROKER_PREFIX]/[NodeID]/[SensorID]/V_[SensorType]
|
||||
* NodeID and SensorID is uint8 (0-255) number.
|
||||
* Last segment is translation of the sensor type, look inside MyMQTT.cpp for the definitions.
|
||||
* User can change this to their needs. We have also left some space for custom types.
|
||||
*
|
||||
* Special: (sensor 255 reserved for special commands)
|
||||
* You can receive a node sketch name with MyMQTT/20/255/V_Sketch_name (or version with _version)
|
||||
*
|
||||
* To-do:
|
||||
* Special commands : clear or set EEPROM Values, Send REBOOT and Receive reboot for MyMQTT itself.
|
||||
* Be able to send ACK so client returns the data being sent.
|
||||
* ... Please come with ideas!
|
||||
* What to do with publish messages.
|
||||
*
|
||||
* Test in more MQTT clients, So far tested in openhab and MyMQTT for Android (Not my creation)
|
||||
* - http://www.openhab.org/
|
||||
* - https://play.google.com/store/apps/details?id=at.tripwire.mqtt.client&hl=en
|
||||
* ... Please notify me if you use this broker with other software.
|
||||
*
|
||||
* How to set-up Openhab and MQTTGateway:
|
||||
* http://forum.mysensors.org/topic/303/mqtt-broker-gateway
|
||||
*/
|
||||
|
||||
#include <DigitalIO.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include <MySigningNone.h>
|
||||
#include <MyTransportRFM69.h>
|
||||
#include <MyTransportNRF24.h>
|
||||
#include <MyHwATMega328.h>
|
||||
#include <MySigningAtsha204Soft.h>
|
||||
#include <MySigningAtsha204.h>
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <MsTimer2.h>
|
||||
#include <Ethernet.h>
|
||||
#include "MyMQTT.h"
|
||||
|
||||
|
||||
#define INCLUSION_MODE_TIME 1 // Number of minutes inclusion mode is enabled
|
||||
#define INCLUSION_MODE_PIN 3 // Digital pin used for inclusion mode button
|
||||
|
||||
// * Use this for IBOARD modded to use standard MISO/MOSI/SCK, see note *1 above!
|
||||
/*
|
||||
#define RADIO_CE_PIN 3 // radio chip enable
|
||||
#define RADIO_SPI_SS_PIN 8 // radio SPI serial select
|
||||
#define RADIO_ERROR_LED_PIN A2 // Error led pin
|
||||
#define RADIO_RX_LED_PIN A1 // Receive led pin
|
||||
#define RADIO_TX_LED_PIN A0 // the PCB, on board LED
|
||||
*/
|
||||
|
||||
// * Use this for default configured pro mini / nano etc :
|
||||
///*
|
||||
|
||||
#define RADIO_CE_PIN 5 // radio chip enable
|
||||
#define RADIO_SPI_SS_PIN 6 // radio SPI serial select
|
||||
#define RADIO_ERROR_LED_PIN 7 // Error led pin
|
||||
#define RADIO_RX_LED_PIN 8 // Receive led pin
|
||||
#define RADIO_TX_LED_PIN 9 // the PCB, on board LED*/
|
||||
|
||||
#define TCP_PORT 1883 // Set your MQTT Broker Listening port.
|
||||
IPAddress TCP_IP ( 192, 168, 0, 234 ); // Configure your static ip-address here
|
||||
byte TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You should change this! see note *2 above!
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// NRFRF24L01 radio driver (set low transmit power by default)
|
||||
MyTransportNRF24 transport(RADIO_CE_PIN, RADIO_SPI_SS_PIN, RF24_PA_LEVEL_GW);
|
||||
//MyTransportRFM69 transport;
|
||||
|
||||
// Message signing driver (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h)
|
||||
//MySigningNone signer;
|
||||
//MySigningAtsha204Soft signer;
|
||||
//MySigningAtsha204 signer;
|
||||
|
||||
// Hardware profile
|
||||
MyHwATMega328 hw;
|
||||
|
||||
// Construct MySensors library (signer needed if MY_SIGNING_FEATURE is turned on in MyConfig.h)
|
||||
MySensor gw(transport, hw /*, signer*/);
|
||||
|
||||
|
||||
EthernetServer server = EthernetServer(TCP_PORT);
|
||||
EthernetClient *currentClient = NULL;
|
||||
MyMessage msg;
|
||||
char convBuf[MAX_PAYLOAD*2+1];
|
||||
char broker[] PROGMEM = MQTT_BROKER_PREFIX;
|
||||
bool MQTTClientConnected = false;
|
||||
uint8_t buffsize;
|
||||
char buffer[MQTT_MAX_PACKET_SIZE];
|
||||
volatile uint8_t countRx;
|
||||
volatile uint8_t countTx;
|
||||
volatile uint8_t countErr;
|
||||
|
||||
|
||||
void writeEthernet(const char *writeBuffer, uint8_t *writeSize) {
|
||||
#ifdef TCPDUMP
|
||||
Serial.print(">>");
|
||||
char buf[4];
|
||||
for (uint8_t a=0; a<*writeSize; a++) { sprintf(buf,"%02X ",(uint8_t)writeBuffer[a]); Serial.print(buf); } Serial.println("");
|
||||
#endif
|
||||
server.write((const uint8_t *)writeBuffer, *writeSize);
|
||||
}
|
||||
|
||||
|
||||
void processEthernetMessages() {
|
||||
char inputString[MQTT_MAX_PACKET_SIZE] = "";
|
||||
byte inputSize = 0;
|
||||
byte readCnt = 0;
|
||||
byte length = 0;
|
||||
|
||||
EthernetClient client = server.available();
|
||||
if (client) {
|
||||
while (client.available()) {
|
||||
// Save the current client we are talking with
|
||||
currentClient = &client;
|
||||
byte inByte = client.read();
|
||||
readCnt++;
|
||||
|
||||
if (inputSize < MQTT_MAX_PACKET_SIZE) {
|
||||
inputString[inputSize] = (char)inByte;
|
||||
inputSize++;
|
||||
}
|
||||
|
||||
if (readCnt == 2) {
|
||||
length = (inByte & 127) * 1;
|
||||
}
|
||||
if (readCnt == (length+2)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef TCPDUMP
|
||||
Serial.print("<<");
|
||||
char buf[4];
|
||||
for (byte a=0; a<inputSize; a++) { sprintf(buf, "%02X ", (byte)inputString[a]); Serial.print(buf); } Serial.println();
|
||||
#endif
|
||||
processMQTTMessage(inputString, inputSize);
|
||||
currentClient = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
rxBlink(1);
|
||||
sendMQTT(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Ethernet.begin(TCP_MAC, TCP_IP);
|
||||
|
||||
|
||||
countRx = 0;
|
||||
countTx = 0;
|
||||
countErr = 0;
|
||||
|
||||
// Setup led pins
|
||||
pinMode(RADIO_RX_LED_PIN, OUTPUT);
|
||||
pinMode(RADIO_TX_LED_PIN, OUTPUT);
|
||||
pinMode(RADIO_ERROR_LED_PIN, OUTPUT);
|
||||
digitalWrite(RADIO_RX_LED_PIN, LOW);
|
||||
digitalWrite(RADIO_TX_LED_PIN, LOW);
|
||||
digitalWrite(RADIO_ERROR_LED_PIN, LOW);
|
||||
|
||||
|
||||
// Set initial state of leds
|
||||
digitalWrite(RADIO_RX_LED_PIN, HIGH);
|
||||
digitalWrite(RADIO_TX_LED_PIN, HIGH);
|
||||
digitalWrite(RADIO_ERROR_LED_PIN, HIGH);
|
||||
|
||||
|
||||
// Add led timer interrupt
|
||||
MsTimer2::set(300, ledTimersInterrupt);
|
||||
MsTimer2::start();
|
||||
|
||||
|
||||
// give the Ethernet interface a second to initialize
|
||||
delay(1000);
|
||||
|
||||
|
||||
// Initialize gateway at maximum PA level, channel 70 and callback for write operations
|
||||
gw.begin(incomingMessage, 0, true, 0);
|
||||
|
||||
// start listening for clients
|
||||
server.begin();
|
||||
|
||||
Serial.println("Ok!");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
gw.process();
|
||||
|
||||
processEthernetMessages();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline MyMessage& build (MyMessage &msg, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type, bool enableAck) {
|
||||
msg.destination = destination;
|
||||
msg.sender = GATEWAY_ADDRESS;
|
||||
msg.sensor = sensor;
|
||||
msg.type = type;
|
||||
mSetCommand(msg,command);
|
||||
mSetRequestAck(msg,enableAck);
|
||||
mSetAck(msg,false);
|
||||
return msg;
|
||||
}
|
||||
|
||||
char *getType(char *b, const char **index) {
|
||||
char *q = b;
|
||||
char *p = (char *)pgm_read_word(index);
|
||||
while (*q++ = pgm_read_byte(p++));
|
||||
*q=0;
|
||||
return b;
|
||||
}
|
||||
|
||||
void processMQTTMessage(char *inputString, uint8_t inputPos) {
|
||||
char *str, *p;
|
||||
uint8_t i = 0;
|
||||
buffer[0]= 0;
|
||||
buffsize = 0;
|
||||
(void)inputPos;
|
||||
|
||||
if ((uint8_t)inputString[0] >> 4 == MQTTCONNECT) {
|
||||
buffer[buffsize++] = MQTTCONNACK << 4;
|
||||
buffer[buffsize++] = 0x02; // Remaining length
|
||||
buffer[buffsize++] = 0x00; // Connection accepted
|
||||
buffer[buffsize++] = 0x00; // Reserved
|
||||
MQTTClientConnected=true; // We have connection!
|
||||
}
|
||||
if ((uint8_t)inputString[0] >> 4 == MQTTPINGREQ) {
|
||||
buffer[buffsize++] = MQTTPINGRESP << 4;
|
||||
buffer[buffsize++] = 0x00;
|
||||
}
|
||||
if ((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE) {
|
||||
buffer[buffsize++] = MQTTSUBACK << 4; // Just ack everything, we actually dont really care!
|
||||
buffer[buffsize++] = 0x03; // Remaining length
|
||||
buffer[buffsize++] = (uint8_t)inputString[2]; // Message ID MSB
|
||||
buffer[buffsize++] = (uint8_t)inputString[3]; // Message ID LSB
|
||||
buffer[buffsize++] = MQTTQOS0; // QOS level
|
||||
}
|
||||
if ((uint8_t)inputString[0] >> 4 == MQTTUNSUBSCRIBE) {
|
||||
buffer[buffsize++] = MQTTUNSUBACK << 4;
|
||||
buffer[buffsize++] = 0x02; // Remaining length
|
||||
buffer[buffsize++] = (uint8_t)inputString[2]; // Message ID MSB
|
||||
buffer[buffsize++] = (uint8_t)inputString[3]; // Message ID LSB
|
||||
}
|
||||
if ((uint8_t)inputString[0] >> 4 == MQTTDISCONNECT) {
|
||||
MQTTClientConnected=false; // We lost connection!
|
||||
}
|
||||
if (buffsize > 0) {
|
||||
writeEthernet(buffer,&buffsize);
|
||||
}
|
||||
|
||||
// We publish everything we get, we dont care if its subscribed or not!
|
||||
if ((uint8_t)inputString[0] >> 4 == MQTTPUBLISH || (MQTT_SEND_SUBSCRIPTION && (uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE)) {
|
||||
buffer[0]= 0;
|
||||
buffsize = 0;
|
||||
// Cut out address and payload depending on message type.
|
||||
if ((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE) {
|
||||
strncat(buffer,inputString+6,inputString[5]);
|
||||
} else {
|
||||
strncat(buffer,inputString+4,inputString[3]);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.println(buffer);
|
||||
#endif
|
||||
// TODO: Check if we should send ack or not.
|
||||
for (str = strtok_r(buffer,"/",&p) ; str && i<4 ; str = strtok_r(NULL,"/",&p)) {
|
||||
if (i == 0) {
|
||||
if (strcmp_P(str,broker)!=0) { //look for MQTT_BROKER_PREFIX
|
||||
return; //Message not for us or malformatted!
|
||||
}
|
||||
} else if (i==1) {
|
||||
msg.destination = atoi(str); //NodeID
|
||||
} else if (i==2) {
|
||||
msg.sensor = atoi(str); //SensorID
|
||||
} else if (i==3) {
|
||||
unsigned char match=255; //SensorType
|
||||
#ifdef MQTT_TRANSLATE_TYPES
|
||||
|
||||
for (uint8_t j=0; strcpy_P(convBuf, (char*)pgm_read_word(&(vType[j]))) ; j++) {
|
||||
if (strcmp((char*)&str[2],convBuf)==0) { //Strip V_ and compare
|
||||
match=j;
|
||||
break;
|
||||
}
|
||||
if (j >= V_TOTAL) break;
|
||||
}
|
||||
|
||||
#endif
|
||||
if ( atoi(str)!=0 || (str[0]=='0' && str[1] =='\0') ) {
|
||||
match=atoi(str);
|
||||
}
|
||||
|
||||
if (match==255) {
|
||||
match=V_UNKNOWN;
|
||||
}
|
||||
msg.type = match;
|
||||
}
|
||||
i++;
|
||||
} //Check if packge has payload
|
||||
if ((uint8_t)inputString[1] > (uint8_t)(inputString[3]+2) && !((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE)) {
|
||||
strcpy(convBuf,inputString+(inputString[3]+4));
|
||||
msg.set(convBuf); //Payload
|
||||
} else {
|
||||
msg.set(""); //No payload
|
||||
}
|
||||
txBlink(1);
|
||||
if (!gw.sendRoute(build(msg, msg.destination, msg.sensor, C_SET, msg.type, 0))) errBlink(1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void sendMQTT(const MyMessage &inMsg) {
|
||||
MyMessage msg = inMsg;
|
||||
buffsize = 0;
|
||||
if (!MQTTClientConnected) return; //We have no connections - return
|
||||
if (msg.isAck()) {
|
||||
// if (msg.sender==255 && mGetCommand(msg)==C_INTERNAL && msg.type==I_ID_REQUEST) {
|
||||
// TODO: sending ACK request on id_response fucks node up. doesn't work.
|
||||
// The idea was to confirm id and save to EEPROM_LATEST_NODE_ADDRESS.
|
||||
// }
|
||||
} else {
|
||||
// we have to check every message if its a newly assigned id or not.
|
||||
// Ack on I_ID_RESPONSE does not work, and checking on C_PRESENTATION isn't reliable.
|
||||
uint8_t newNodeID = gw.loadState(EEPROM_LATEST_NODE_ADDRESS)+1;
|
||||
if (newNodeID <= MQTT_FIRST_SENSORID) newNodeID = MQTT_FIRST_SENSORID;
|
||||
if (msg.sender==newNodeID) {
|
||||
gw.saveState(EEPROM_LATEST_NODE_ADDRESS,newNodeID);
|
||||
}
|
||||
if (mGetCommand(msg)==C_INTERNAL) {
|
||||
if (msg.type==I_CONFIG) {
|
||||
txBlink(1);
|
||||
if (!gw.sendRoute(build(msg, msg.sender, 255, C_INTERNAL, I_CONFIG, 0).set(MQTT_UNIT))) errBlink(1);
|
||||
return;
|
||||
} else if (msg.type==I_ID_REQUEST && msg.sender==255) {
|
||||
uint8_t newNodeID = gw.loadState(EEPROM_LATEST_NODE_ADDRESS)+1;
|
||||
if (newNodeID <= MQTT_FIRST_SENSORID) newNodeID = MQTT_FIRST_SENSORID;
|
||||
if (newNodeID >= MQTT_LAST_SENSORID) return; // Sorry no more id's left :(
|
||||
txBlink(1);
|
||||
if (!gw.sendRoute(build(msg, msg.sender, 255, C_INTERNAL, I_ID_RESPONSE, 0).set(newNodeID))) errBlink(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mGetCommand(msg)!=C_PRESENTATION) {
|
||||
if (mGetCommand(msg)==C_INTERNAL) msg.type=msg.type+(S_FIRSTCUSTOM-10); //Special message
|
||||
buffer[buffsize++] = MQTTPUBLISH << 4; // 0:
|
||||
buffer[buffsize++] = 0x09; // 1: Remaining length with no payload, we'll set this later to correct value, buffsize -2
|
||||
buffer[buffsize++] = 0x00; // 2: Length MSB (Remaing length can never exceed ff,so MSB must be 0!)
|
||||
buffer[buffsize++] = 0x08; // 3: Length LSB (ADDR), We'll set this later
|
||||
strcpy_P(buffer+4, broker);
|
||||
buffsize+=strlen_P(broker);
|
||||
#ifdef MQTT_TRANSLATE_TYPES
|
||||
if (msg.type > V_TOTAL) msg.type=V_UNKNOWN;// If type > defined types set to unknown.
|
||||
buffsize+=sprintf(&buffer[buffsize],"/%i/%i/V_%s",msg.sender,msg.sensor,getType(convBuf, &vType[msg.type]));
|
||||
#else
|
||||
buffsize+=sprintf(&buffer[buffsize],"/%i/%i/%i",msg.sender,msg.sensor,msg.type);
|
||||
#endif
|
||||
buffer[3]=buffsize-4; // Set correct address length on byte 4.
|
||||
#ifdef DEBUG
|
||||
Serial.println((char*)&buffer[4]);
|
||||
#endif
|
||||
msg.getString(convBuf);
|
||||
for (uint8_t a=0; a<strlen(convBuf); a++) {// Payload
|
||||
buffer[buffsize++] = convBuf[a];
|
||||
}
|
||||
buffer[1]=buffsize-2; // Set correct Remaining length on byte 2.
|
||||
writeEthernet(buffer,&buffsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ledTimersInterrupt() {
|
||||
if(countRx && countRx != 255) {
|
||||
// switch led on
|
||||
digitalWrite(RADIO_RX_LED_PIN, LOW);
|
||||
} else if(!countRx) {
|
||||
// switching off
|
||||
digitalWrite(RADIO_RX_LED_PIN, HIGH);
|
||||
}
|
||||
if(countRx != 255) { countRx--; }
|
||||
|
||||
if(countTx && countTx != 255) {
|
||||
// switch led on
|
||||
digitalWrite(RADIO_TX_LED_PIN, LOW);
|
||||
} else if(!countTx) {
|
||||
// switching off
|
||||
digitalWrite(RADIO_TX_LED_PIN, HIGH);
|
||||
}
|
||||
if(countTx != 255) { countTx--; }
|
||||
|
||||
if(countErr && countErr != 255) {
|
||||
// switch led on
|
||||
digitalWrite(RADIO_ERROR_LED_PIN, LOW);
|
||||
} else if(!countErr) {
|
||||
// switching off
|
||||
digitalWrite(RADIO_ERROR_LED_PIN, HIGH);
|
||||
}
|
||||
if(countErr != 255) { countErr--; }
|
||||
|
||||
}
|
||||
|
||||
void rxBlink(uint8_t cnt) {
|
||||
if(countRx == 255) { countRx = cnt; }
|
||||
}
|
||||
void txBlink(uint8_t cnt) {
|
||||
if(countTx == 255) { countTx = cnt; }
|
||||
}
|
||||
void errBlink(uint8_t cnt) {
|
||||
if(countErr == 255) { countErr = cnt; }
|
||||
}
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
The MySensors library adds a new layer on top of the RF24 library.
|
||||
It handles radio network routing, relaying and ids.
|
||||
|
||||
Created by Henrik Ekblad <henrik.ekblad@gmail.com>
|
||||
Modified by Daniel Wiegert
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
#define TCPDUMP // Dump TCP packages
|
||||
#endif
|
||||
|
||||
#define MQTT_FIRST_SENSORID 20 // If you want manually configured nodes below this value. 255 = Disable
|
||||
#define MQTT_LAST_SENSORID 254 // 254 is max! 255 reserved.
|
||||
#define MQTT_BROKER_PREFIX "MyMQTT" // First prefix in MQTT tree, keep short!
|
||||
#define MQTT_SEND_SUBSCRIPTION 1 // Send empty payload (request) to node upon MQTT client subscribe request.
|
||||
// NOTE above : Beware to check if there is any length on payload in your incommingMessage code:
|
||||
// Example: if (msg.type==V_LIGHT && strlen(msg.getString())>0) otherwise the code might do strange things.
|
||||
#define MQTT_UNIT "M" // Select M for metric or I for imperial.
|
||||
#define MQTT_TRANSLATE_TYPES // V_TYPE in address, Comment if you want all numbers (MyMQTT/01/01/01)
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
#define EEPROM_LATEST_NODE_ADDRESS ((uint8_t)EEPROM_LOCAL_CONFIG_ADDRESS)
|
||||
#define MQTT_MAX_PACKET_SIZE 100
|
||||
|
||||
#define MQTTPROTOCOLVERSION 3
|
||||
#define MQTTCONNECT 1 // Client request to connect to Server
|
||||
#define MQTTCONNACK 2 // Connect Acknowledgment
|
||||
#define MQTTPUBLISH 3 // Publish message
|
||||
#define MQTTPUBACK 4 // Publish Acknowledgment
|
||||
#define MQTTPUBREC 5 // Publish Received (assured delivery part 1)
|
||||
#define MQTTPUBREL 6 // Publish Release (assured delivery part 2)
|
||||
#define MQTTPUBCOMP 7 // Publish Complete (assured delivery part 3)
|
||||
#define MQTTSUBSCRIBE 8 // Client Subscribe request
|
||||
#define MQTTSUBACK 9 // Subscribe Acknowledgment
|
||||
#define MQTTUNSUBSCRIBE 10 // Client Unsubscribe request
|
||||
#define MQTTUNSUBACK 11 // Unsubscribe Acknowledgment
|
||||
#define MQTTPINGREQ 12 // PING Request
|
||||
#define MQTTPINGRESP 13 // PING Response
|
||||
#define MQTTDISCONNECT 14 // Client is Disconnecting
|
||||
#define MQTTReserved 15 // Reserved
|
||||
|
||||
#define MQTTQOS0 (0 << 1)
|
||||
#define MQTTQOS1 (1 << 1)
|
||||
#define MQTTQOS2 (2 << 1)
|
||||
|
||||
#ifdef MQTT_TRANSLATE_TYPES
|
||||
|
||||
char V_0[] PROGMEM = "TEMP"; //V_TEMP
|
||||
char V_1[] PROGMEM = "HUM"; //V_HUM
|
||||
char V_2[] PROGMEM = "LIGHT"; //V_LIGHT
|
||||
char V_3[] PROGMEM = "DIMMER"; //V_DIMMER
|
||||
char V_4[] PROGMEM = "PRESSURE"; //V_PRESSURE
|
||||
char V_5[] PROGMEM = "FORECAST"; //V_FORECAST
|
||||
char V_6[] PROGMEM = "RAIN"; //V_RAIN
|
||||
char V_7[] PROGMEM = "RAINRATE"; //V_RAINRATE
|
||||
char V_8[] PROGMEM = "WIND"; //V_WIND
|
||||
char V_9[] PROGMEM = "GUST"; //V_GUST
|
||||
char V_10[] PROGMEM = "DIRECTON"; //V_DIRECTON
|
||||
char V_11[] PROGMEM = "UV"; //V_UV
|
||||
char V_12[] PROGMEM = "WEIGHT"; //V_WEIGHT
|
||||
char V_13[] PROGMEM = "DISTANCE"; //V_DISTANCE
|
||||
char V_14[] PROGMEM = "IMPEDANCE"; //V_IMPEDANCE
|
||||
char V_15[] PROGMEM = "ARMED"; //V_ARMED
|
||||
char V_16[] PROGMEM = "TRIPPED"; //V_TRIPPED
|
||||
char V_17[] PROGMEM = "WATT"; //V_WATT
|
||||
char V_18[] PROGMEM = "KWH"; //V_KWH
|
||||
char V_19[] PROGMEM = "SCENE_ON"; //V_SCENE_ON
|
||||
char V_20[] PROGMEM = "SCENE_OFF"; //V_SCENE_OFF
|
||||
char V_21[] PROGMEM = "HEATER"; //V_HEATER
|
||||
char V_22[] PROGMEM = "HEATER_SW"; //V_HEATER_SW
|
||||
char V_23[] PROGMEM = "LIGHT_LEVEL"; //V_LIGHT_LEVEL
|
||||
char V_24[] PROGMEM = "VAR1"; //V_VAR1
|
||||
char V_25[] PROGMEM = "VAR2"; //V_VAR2
|
||||
char V_26[] PROGMEM = "VAR3"; //V_VAR3
|
||||
char V_27[] PROGMEM = "VAR4"; //V_VAR4
|
||||
char V_28[] PROGMEM = "VAR5"; //V_VAR5
|
||||
char V_29[] PROGMEM = "UP"; //V_UP
|
||||
char V_30[] PROGMEM = "DOWN"; //V_DOWN
|
||||
char V_31[] PROGMEM = "STOP"; //V_STOP
|
||||
char V_32[] PROGMEM = "IR_SEND"; //V_IR_SEND
|
||||
char V_33[] PROGMEM = "IR_RECEIVE"; //V_IR_RECEIVE
|
||||
char V_34[] PROGMEM = "FLOW"; //V_FLOW
|
||||
char V_35[] PROGMEM = "VOLUME"; //V_VOLUME
|
||||
char V_36[] PROGMEM = "LOCK_STATUS"; //V_LOCK_STATUS
|
||||
char V_37[] PROGMEM = "DUST_LEVEL"; //V_DUST_LEVEL
|
||||
char V_38[] PROGMEM = "VOLTAGE"; //V_VOLTAGE
|
||||
char V_39[] PROGMEM = "CURRENT"; //V_CURRENT
|
||||
char V_40[] PROGMEM = ""; //
|
||||
char V_41[] PROGMEM = ""; //
|
||||
char V_42[] PROGMEM = ""; //
|
||||
char V_43[] PROGMEM = ""; //
|
||||
char V_44[] PROGMEM = ""; //
|
||||
char V_45[] PROGMEM = ""; //
|
||||
char V_46[] PROGMEM = ""; //
|
||||
char V_47[] PROGMEM = ""; //
|
||||
char V_48[] PROGMEM = ""; //
|
||||
char V_49[] PROGMEM = ""; //
|
||||
char V_50[] PROGMEM = ""; //
|
||||
char V_51[] PROGMEM = ""; //
|
||||
char V_52[] PROGMEM = ""; //
|
||||
char V_53[] PROGMEM = ""; //
|
||||
char V_54[] PROGMEM = ""; //
|
||||
char V_55[] PROGMEM = ""; //
|
||||
char V_56[] PROGMEM = ""; //
|
||||
char V_57[] PROGMEM = ""; //
|
||||
char V_58[] PROGMEM = ""; //
|
||||
char V_59[] PROGMEM = ""; //
|
||||
char V_60[] PROGMEM = "DEFAULT"; //Custom for MQTTGateway
|
||||
char V_61[] PROGMEM = "SKETCH_NAME"; //Custom for MQTTGateway
|
||||
char V_62[] PROGMEM = "SKETCH_VERSION"; //Custom for MQTTGateway
|
||||
char V_63[] PROGMEM = "UNKNOWN"; //Custom for MQTTGateway
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
PROGMEM const char *vType[] = {
|
||||
V_0, V_1, V_2, V_3, V_4, V_5, V_6, V_7, V_8, V_9, V_10,
|
||||
V_11, V_12, V_13, V_14, V_15, V_16, V_17, V_18, V_19, V_20,
|
||||
V_21, V_22, V_23, V_24, V_25, V_26, V_27, V_28, V_29, V_30,
|
||||
V_31, V_32, V_33, V_34, V_35, V_36, V_37, V_38, V_39, V_40,
|
||||
V_41, V_42, V_43, V_44, V_45, V_46, V_47, V_48, V_49, V_50,
|
||||
V_51, V_52, V_53, V_54, V_55, V_56, V_57, V_58, V_59, V_60,
|
||||
V_61, V_62, V_63
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define S_FIRSTCUSTOM 60
|
||||
#define V_TOTAL (sizeof(vType)/sizeof(char *))-1
|
||||
|
||||
#endif
|
||||
|
||||
#define S_FIRSTCUSTOM 60
|
||||
#define V_UNKNOWN 63
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,40 +0,0 @@
|
||||
# MockMySensors
|
||||
Arduino sketch to fake sensor for the MySensors Library
|
||||
|
||||
This skecth is intended to crate fake sensors which register and respond to the controller
|
||||
|
||||
Barduino, GizMoCuz 2015
|
||||
-----------------
|
||||
|
||||
Comment/Uncomment the sensors you would like to test
|
||||
|
||||
Arduino Uno R3 can support about 12 sensors before it runs out of memory.
|
||||
(turning off the MySensors debug helps if you are memory limited)
|
||||
|
||||
With a Mega you can have them all
|
||||
|
||||
|
||||
Changes Log
|
||||
-----------------
|
||||
|
||||
2015-09-07
|
||||
Five more sensors
|
||||
S_RGB_LIGHT
|
||||
S_RGBW_LIGHT
|
||||
S_COLOR_SENSOR
|
||||
S_HVAC
|
||||
S_MULTIMETER
|
||||
Consolidated HVAC and HEATER incoming message
|
||||
|
||||
2015-09-06
|
||||
|
||||
Merge with Gizmocuz (implementation of S_HEATER & S_MOISTURE
|
||||
Implementation of S_COVER, S_IR, S_SCENE_CONTROLLER
|
||||
|
||||
|
||||
2015-08-19
|
||||
|
||||
Removed the load/save to eeprom
|
||||
Touched the heater sensor
|
||||
Created a pseudo sensor to handle the V_ARMED message.
|
||||
All sensors which support V_ARMED will arm/disarm at the same time
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Motion Sensor example using HC-SR501
|
||||
* http://www.mysensors.org/build/motion
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable debug prints
|
||||
//#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds)
|
||||
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!)
|
||||
#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
|
||||
#define CHILD_ID 1 // Id of the sensor child
|
||||
|
||||
// Initialize motion message
|
||||
MyMessage msg(CHILD_ID, V_TRIPPED);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Motion Sensor", "1.0");
|
||||
|
||||
pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
present(CHILD_ID, S_MOTION);
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Read digital motion value
|
||||
boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH;
|
||||
|
||||
Serial.println(tripped);
|
||||
send(msg.set(tripped?"1":"0")); // Send tripped value to gw
|
||||
|
||||
// Sleep until interrupt comes in on motion sensor. Send update every two minute.
|
||||
sleep(INTERRUPT,CHANGE, SLEEP_TIME);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Created by Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Parking sensor using a neopixel led ring and distance sensor (HC-SR04).
|
||||
* Configure the digital pins used for distance sensor and neopixels below.
|
||||
* NOTE! Remeber to feed leds and distance sensor serparatly from your Arduino.
|
||||
* It will probably not survive feeding more than a couple of LEDs. You
|
||||
* can also adjust intesity below to reduce the power requirements.
|
||||
*
|
||||
* Sends parking status to the controller as a DOOR sensor if SEND_STATUS_TO_CONTROLLER
|
||||
* is defined below. You can also use this _standalone_ without any radio by
|
||||
* removing the SEND_STATUS_TO_CONTROLLER define.
|
||||
*/
|
||||
|
||||
#define SEND_STATUS_TO_CONTROLLER // Put a comment on this line for standalone mode
|
||||
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#include <NewPing.h>
|
||||
|
||||
#ifdef SEND_STATUS_TO_CONTROLLER
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#endif
|
||||
|
||||
#define NEO_PIN 4 // NeoPixels input pin
|
||||
|
||||
#define TRIGGER_PIN 6 // Arduino pin tied to trigger pin on the ultrasonic sensor.
|
||||
#define ECHO_PIN 5 // Arduino pin tied to echo pin on the ultrasonic sensor.
|
||||
|
||||
#define NUMPIXELS 24 // Number of nexpixels in ring/strip
|
||||
#define MAX_INTESITY 20 // Intesity of leds (in percentage). Remeber more intesity requires more power.
|
||||
|
||||
// The maximum rated measuring range for the HC-SR04 is about 400-500cm.
|
||||
#define MAX_DISTANCE 100 // Max distance we want to start indicating green (in cm)
|
||||
#define PANIC_DISTANCE 5 // Mix distance we red warning indication should be active (in cm)
|
||||
#define PARKED_DISTANCE 20 // Distance when "parked signal" should be sent to controller (in cm)
|
||||
|
||||
#define PARK_OFF_TIMEOUT 20000 // Number of milliseconds until turning off light when parked.
|
||||
|
||||
// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
|
||||
// example for more information on possible values.
|
||||
|
||||
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, NEO_PIN, NEO_GRB + NEO_KHZ400);
|
||||
|
||||
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
|
||||
|
||||
#ifdef SEND_STATUS_TO_CONTROLLER
|
||||
#define CHILD_ID 1
|
||||
MyMessage msg(CHILD_ID,V_TRIPPED);
|
||||
#endif
|
||||
unsigned long sendInterval = 5000; // Send park status at maximum every 5 second.
|
||||
unsigned long lastSend;
|
||||
|
||||
int oldParkedStatus=-1;
|
||||
|
||||
unsigned long blinkInterval = 100; // blink interval (milliseconds)
|
||||
unsigned long lastBlinkPeriod;
|
||||
bool blinkColor = true;
|
||||
|
||||
// To make a fading motion on the led ring/tape we only move one pixel/distDebounce time
|
||||
unsigned long distDebounce = 30;
|
||||
unsigned long lastDebouncePeriod;
|
||||
int numLightPixels=0;
|
||||
int skipZero=0;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Starting distance sensor");
|
||||
pixels.begin(); // This initializes the NeoPixel library.
|
||||
Serial.println("Neopixels initialized");
|
||||
#ifdef SEND_STATUS_TO_CONTROLLER
|
||||
sendSketchInfo("Parking Sensor", "1.0");
|
||||
present(CHILD_ID, S_DOOR, "Parking Status");
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
unsigned long now = millis();
|
||||
|
||||
unsigned int fullDist = (sonar.ping_median() / US_ROUNDTRIP_CM);
|
||||
// Serial.println(fullDist);
|
||||
int displayDist = min(fullDist, MAX_DISTANCE);
|
||||
if (displayDist == 0 && skipZero<10) {
|
||||
// Try to filter zero readings
|
||||
skipZero++;
|
||||
return;
|
||||
}
|
||||
// Check if it is time to alter the leds
|
||||
if (now-lastDebouncePeriod > distDebounce) {
|
||||
lastDebouncePeriod = now;
|
||||
|
||||
// Update parked status
|
||||
int parked = displayDist != 0 && displayDist<PARKED_DISTANCE;
|
||||
if (parked != oldParkedStatus && now-lastSend > sendInterval) {
|
||||
if (parked)
|
||||
Serial.println("Car Parked");
|
||||
else
|
||||
Serial.println("Car Gone");
|
||||
#ifdef SEND_STATUS_TO_CONTROLLER
|
||||
send(msg.set(parked));
|
||||
#endif
|
||||
oldParkedStatus = parked;
|
||||
lastSend = now;
|
||||
}
|
||||
|
||||
if (parked && now-lastSend > PARK_OFF_TIMEOUT) {
|
||||
// We've been parked for a while now. Turn off all pixels
|
||||
for(int i=0;i<NUMPIXELS;i++){
|
||||
pixels.setPixelColor(i, pixels.Color(0,0,0));
|
||||
}
|
||||
} else {
|
||||
if (displayDist == 0) {
|
||||
// No reading from sensor, assume no object found
|
||||
numLightPixels--;
|
||||
} else {
|
||||
skipZero = 0;
|
||||
int newLightPixels = NUMPIXELS - (NUMPIXELS*(displayDist-PANIC_DISTANCE)/(MAX_DISTANCE-PANIC_DISTANCE));
|
||||
if (newLightPixels>numLightPixels) {
|
||||
// Fast raise
|
||||
numLightPixels += max((newLightPixels - numLightPixels) / 2, 1);
|
||||
} else if (newLightPixels<numLightPixels) {
|
||||
// Slow decent
|
||||
numLightPixels--;
|
||||
}
|
||||
}
|
||||
|
||||
if (numLightPixels>=NUMPIXELS) {
|
||||
// Do some intense red blinking
|
||||
if (now-lastBlinkPeriod > blinkInterval) {
|
||||
blinkColor = !blinkColor;
|
||||
lastBlinkPeriod = now;
|
||||
}
|
||||
for(int i=0;i<numLightPixels;i++){
|
||||
pixels.setPixelColor(i, pixels.Color(blinkColor?255*MAX_INTESITY/100:0,0,0));
|
||||
}
|
||||
} else {
|
||||
for(int i=0;i<numLightPixels;i++){
|
||||
int r = 255 * i/NUMPIXELS;
|
||||
int g = 255 - r;
|
||||
// pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
|
||||
pixels.setPixelColor(i, pixels.Color(r*MAX_INTESITY/100,g*MAX_INTESITY/100,0));
|
||||
}
|
||||
// Turn off the rest
|
||||
for(int i=numLightPixels;i<NUMPIXELS;i++){
|
||||
pixels.setPixelColor(i, pixels.Color(0,0,0));
|
||||
}
|
||||
}
|
||||
}
|
||||
pixels.show(); // This sends the updated pixel color to the hardware.
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/****
|
||||
* Formatted logging to the Serial console.
|
||||
* Compiled in by setting LOGDEBUG
|
||||
*
|
||||
* 2015-05-25 Bruce Lacey V1.0
|
||||
*
|
||||
* Based upon Arduino Playground prior art and should be moved to
|
||||
* the MySensors library at some point as a common debug logging facility
|
||||
*/
|
||||
#ifndef MYSLog_h
|
||||
#define MYSLog_h
|
||||
|
||||
#define LOGDEBUG 1
|
||||
|
||||
#if defined ( LOGDEBUG )
|
||||
#define LOG(fmt, args... ) log( fmt, ## args );
|
||||
#else
|
||||
#define log(fmt, args... )
|
||||
#endif
|
||||
|
||||
void log(const char *fmt, ... ) {
|
||||
char buff[128];
|
||||
va_list args;
|
||||
va_start (args, fmt);
|
||||
vsnprintf(buff, sizeof(buff), fmt, args);
|
||||
va_end (args);
|
||||
buff[sizeof(buff)/sizeof(buff[0])-1]='\0';
|
||||
Serial.print(buff);
|
||||
}
|
||||
|
||||
void log(const __FlashStringHelper *fmt, ... ){
|
||||
char buf[128]; // resulting string limited to 128 chars
|
||||
va_list args;
|
||||
va_start (args, fmt);
|
||||
#ifdef __AVR__
|
||||
vsnprintf_P(buf, sizeof(buf), (const char *)fmt, args); // progmem for AVR
|
||||
#else
|
||||
vsnprintf(buf, sizeof(buf), (const char *)fmt, args); // for the rest of the world
|
||||
#endif
|
||||
va_end(args);
|
||||
Serial.print(buf);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,97 +0,0 @@
|
||||
/***
|
||||
* This is a simple sketch used to demenstrate and test node-to-node MySensor's communication.
|
||||
* To use this sketch, assemble MySensors nodes - they need nothing more than a radio
|
||||
* 1. Flash each node with the same sketch, open the console and type either 0 or 1 to the respective nodes to set thei ID
|
||||
* 2. You only need to set the node id once, and restart the nodes
|
||||
* 3. To being a ping-pong test, simply type T in the console for one of the nodes.
|
||||
*
|
||||
* 2015-05-25 Bruce Lacey v1.0
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include "MYSLog.h"
|
||||
|
||||
#define VSN "v1.0"
|
||||
|
||||
// Define two generic nodes with a single child
|
||||
#define YING 200
|
||||
#define YANG 201
|
||||
#define CHILD 1
|
||||
|
||||
MyMessage mPing(CHILD, V_VAR1); //Ping message
|
||||
MyMessage mPong(CHILD, V_VAR2); //Pong message
|
||||
|
||||
void setup() {
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
present(CHILD, S_CUSTOM); //
|
||||
|
||||
sendSketchInfo( nodeTypeAsCharRepresentation( getNodeId() ), VSN );
|
||||
LOG(F("\n%sReady.\n"), nodeTypeAsCharRepresentation(getNodeId()));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// Interactive command and control
|
||||
// Entering a number from 0 or 1 will write the node 200 (YING) or 201 (YANG) to EEPROM
|
||||
// Entering T on either node will initiatve a ping-pong test.
|
||||
if (Serial.available()) {
|
||||
byte inChar = Serial.read();
|
||||
uint8_t node = getNodeId();
|
||||
|
||||
// Manual Test Mode
|
||||
if (inChar == 'T' || inChar == 't') {
|
||||
LOG(F("T received - starting test...\n"));
|
||||
MyMessage msg = mPong;
|
||||
msg.sender = (node == YING ? YANG : YING);
|
||||
sendPingOrPongResponse( msg );
|
||||
}
|
||||
else if (inChar == '0' or inChar == '1') {
|
||||
byte nodeID = 200 + (inChar - '0');
|
||||
setNodeId(nodeID);
|
||||
}
|
||||
else {
|
||||
LOG("Invalid input\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
|
||||
LOG(F("Received %s from %s\n"), msgTypeAsCharRepresentation((mysensor_data)message.type), nodeTypeAsCharRepresentation(message.sender));
|
||||
|
||||
delay(250);
|
||||
sendPingOrPongResponse( message );
|
||||
}
|
||||
|
||||
void sendPingOrPongResponse( MyMessage msg ) {
|
||||
|
||||
MyMessage response = (msg.type == V_VAR1 ? mPong : mPing);
|
||||
|
||||
LOG(F("Sending %s to %s\n"), msgTypeAsCharRepresentation( (mysensor_data)response.type ), nodeTypeAsCharRepresentation(msg.sender));
|
||||
|
||||
// Set payload to current time in millis to ensure each message is unique
|
||||
response.set( millis() );
|
||||
response.setDestination(msg.sender);
|
||||
send(response);
|
||||
}
|
||||
|
||||
void setNodeId(byte nodeID) {
|
||||
LOG(F("Setting node id to: %i.\n***Please restart the node for changes to take effect.\n"), nodeID);
|
||||
eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, (byte)nodeID);
|
||||
}
|
||||
|
||||
const char * msgTypeAsCharRepresentation( mysensor_data mType ) {
|
||||
return mType == V_VAR1 ? "Ping" : "Pong";
|
||||
}
|
||||
|
||||
const char * nodeTypeAsCharRepresentation( uint8_t node ) {
|
||||
return node == YING ? "Ying Node" : "Yang Node";
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Pressure sensor example using BMP085 module
|
||||
* http://www.mysensors.org/build/pressure
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_BMP085.h>
|
||||
|
||||
#define BARO_CHILD 0
|
||||
#define TEMP_CHILD 1
|
||||
|
||||
const float ALTITUDE = 688; // <-- adapt this value to your own location's altitude.
|
||||
|
||||
// Sleep time between reads (in seconds). Do not change this value as the forecast algorithm needs a sample every minute.
|
||||
const unsigned long SLEEP_TIME = 60000;
|
||||
|
||||
const char *weather[] = { "stable", "sunny", "cloudy", "unstable", "thunderstorm", "unknown" };
|
||||
enum FORECAST
|
||||
{
|
||||
STABLE = 0, // "Stable Weather Pattern"
|
||||
SUNNY = 1, // "Slowly rising Good Weather", "Clear/Sunny "
|
||||
CLOUDY = 2, // "Slowly falling L-Pressure ", "Cloudy/Rain "
|
||||
UNSTABLE = 3, // "Quickly rising H-Press", "Not Stable"
|
||||
THUNDERSTORM = 4, // "Quickly falling L-Press", "Thunderstorm"
|
||||
UNKNOWN = 5 // "Unknown (More Time needed)
|
||||
};
|
||||
|
||||
Adafruit_BMP085 bmp = Adafruit_BMP085(); // Digital Pressure Sensor
|
||||
|
||||
float lastPressure = -1;
|
||||
float lastTemp = -1;
|
||||
int lastForecast = -1;
|
||||
|
||||
const int LAST_SAMPLES_COUNT = 5;
|
||||
float lastPressureSamples[LAST_SAMPLES_COUNT];
|
||||
|
||||
// this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm
|
||||
// get kPa/h be dividing hPa by 10
|
||||
#define CONVERSION_FACTOR (1.0/10.0)
|
||||
|
||||
int minuteCount = 0;
|
||||
bool firstRound = true;
|
||||
// average value is used in forecast algorithm.
|
||||
float pressureAvg;
|
||||
// average after 2 hours is used as reference value for the next iteration.
|
||||
float pressureAvg2;
|
||||
|
||||
float dP_dt;
|
||||
boolean metric;
|
||||
MyMessage tempMsg(TEMP_CHILD, V_TEMP);
|
||||
MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
|
||||
MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Pressure Sensor", "1.1");
|
||||
|
||||
if (!bmp.begin())
|
||||
{
|
||||
Serial.println("Could not find a valid BMP085 sensor, check wiring!");
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
// Register sensors to gw (they will be created as child devices)
|
||||
present(BARO_CHILD, S_BARO);
|
||||
present(TEMP_CHILD, S_TEMP);
|
||||
metric = getConfig().isMetric;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
float pressure = bmp.readSealevelPressure(ALTITUDE) / 100.0;
|
||||
float temperature = bmp.readTemperature();
|
||||
|
||||
if (!metric)
|
||||
{
|
||||
// Convert to fahrenheit
|
||||
temperature = temperature * 9.0 / 5.0 + 32.0;
|
||||
}
|
||||
|
||||
int forecast = sample(pressure);
|
||||
|
||||
Serial.print("Temperature = ");
|
||||
Serial.print(temperature);
|
||||
Serial.println(metric ? " *C" : " *F");
|
||||
Serial.print("Pressure = ");
|
||||
Serial.print(pressure);
|
||||
Serial.println(" hPa");
|
||||
Serial.print("Forecast = ");
|
||||
Serial.println(weather[forecast]);
|
||||
|
||||
|
||||
if (temperature != lastTemp)
|
||||
{
|
||||
send(tempMsg.set(temperature, 1));
|
||||
lastTemp = temperature;
|
||||
}
|
||||
|
||||
if (pressure != lastPressure)
|
||||
{
|
||||
send(pressureMsg.set(pressure, 0));
|
||||
lastPressure = pressure;
|
||||
}
|
||||
|
||||
if (forecast != lastForecast)
|
||||
{
|
||||
send(forecastMsg.set(weather[forecast]));
|
||||
lastForecast = forecast;
|
||||
}
|
||||
|
||||
sleep(SLEEP_TIME);
|
||||
}
|
||||
|
||||
float getLastPressureSamplesAverage()
|
||||
{
|
||||
float lastPressureSamplesAverage = 0;
|
||||
for (int i = 0; i < LAST_SAMPLES_COUNT; i++)
|
||||
{
|
||||
lastPressureSamplesAverage += lastPressureSamples[i];
|
||||
}
|
||||
lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
|
||||
|
||||
return lastPressureSamplesAverage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Algorithm found here
|
||||
// http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf
|
||||
// Pressure in hPa --> forecast done by calculating kPa/h
|
||||
int sample(float pressure)
|
||||
{
|
||||
// Calculate the average of the last n minutes.
|
||||
int index = minuteCount % LAST_SAMPLES_COUNT;
|
||||
lastPressureSamples[index] = pressure;
|
||||
|
||||
minuteCount++;
|
||||
if (minuteCount > 185)
|
||||
{
|
||||
minuteCount = 6;
|
||||
}
|
||||
|
||||
if (minuteCount == 5)
|
||||
{
|
||||
pressureAvg = getLastPressureSamplesAverage();
|
||||
}
|
||||
else if (minuteCount == 35)
|
||||
{
|
||||
float lastPressureAvg = getLastPressureSamplesAverage();
|
||||
float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
|
||||
if (firstRound) // first time initial 3 hour
|
||||
{
|
||||
dP_dt = change * 2; // note this is for t = 0.5hour
|
||||
}
|
||||
else
|
||||
{
|
||||
dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value.
|
||||
}
|
||||
}
|
||||
else if (minuteCount == 65)
|
||||
{
|
||||
float lastPressureAvg = getLastPressureSamplesAverage();
|
||||
float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
|
||||
if (firstRound) //first time initial 3 hour
|
||||
{
|
||||
dP_dt = change; //note this is for t = 1 hour
|
||||
}
|
||||
else
|
||||
{
|
||||
dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value
|
||||
}
|
||||
}
|
||||
else if (minuteCount == 95)
|
||||
{
|
||||
float lastPressureAvg = getLastPressureSamplesAverage();
|
||||
float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
|
||||
if (firstRound) // first time initial 3 hour
|
||||
{
|
||||
dP_dt = change / 1.5; // note this is for t = 1.5 hour
|
||||
}
|
||||
else
|
||||
{
|
||||
dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value
|
||||
}
|
||||
}
|
||||
else if (minuteCount == 125)
|
||||
{
|
||||
float lastPressureAvg = getLastPressureSamplesAverage();
|
||||
pressureAvg2 = lastPressureAvg; // store for later use.
|
||||
float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
|
||||
if (firstRound) // first time initial 3 hour
|
||||
{
|
||||
dP_dt = change / 2; // note this is for t = 2 hour
|
||||
}
|
||||
else
|
||||
{
|
||||
dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value
|
||||
}
|
||||
}
|
||||
else if (minuteCount == 155)
|
||||
{
|
||||
float lastPressureAvg = getLastPressureSamplesAverage();
|
||||
float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
|
||||
if (firstRound) // first time initial 3 hour
|
||||
{
|
||||
dP_dt = change / 2.5; // note this is for t = 2.5 hour
|
||||
}
|
||||
else
|
||||
{
|
||||
dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value
|
||||
}
|
||||
}
|
||||
else if (minuteCount == 185)
|
||||
{
|
||||
float lastPressureAvg = getLastPressureSamplesAverage();
|
||||
float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
|
||||
if (firstRound) // first time initial 3 hour
|
||||
{
|
||||
dP_dt = change / 3; // note this is for t = 3 hour
|
||||
}
|
||||
else
|
||||
{
|
||||
dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value
|
||||
}
|
||||
pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
|
||||
firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
|
||||
}
|
||||
|
||||
int forecast = UNKNOWN;
|
||||
if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
|
||||
{
|
||||
forecast = UNKNOWN;
|
||||
}
|
||||
else if (dP_dt < (-0.25))
|
||||
{
|
||||
forecast = THUNDERSTORM;
|
||||
}
|
||||
else if (dP_dt > 0.25)
|
||||
{
|
||||
forecast = UNSTABLE;
|
||||
}
|
||||
else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
|
||||
{
|
||||
forecast = CLOUDY;
|
||||
}
|
||||
else if ((dP_dt > 0.05) && (dP_dt < 0.25))
|
||||
{
|
||||
forecast = SUNNY;
|
||||
}
|
||||
else if ((dP_dt >(-0.05)) && (dP_dt < 0.05))
|
||||
{
|
||||
forecast = STABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
forecast = UNKNOWN;
|
||||
}
|
||||
|
||||
// uncomment when debugging
|
||||
//Serial.print(F("Forecast at minute "));
|
||||
//Serial.print(minuteCount);
|
||||
//Serial.print(F(" dP/dt = "));
|
||||
//Serial.print(dP_dt);
|
||||
//Serial.print(F("kPa/h --> "));
|
||||
//Serial.println(weather[forecast]);
|
||||
|
||||
return forecast;
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This sketch demonstrates how to use InterruptChain to receive and
|
||||
* decode remote switches (old and new) and remote sensors.
|
||||
*
|
||||
* Basically, this sketch combines the features of the ShowReceivedCode
|
||||
* and ShowReceivedCodeNewKaku examples of RemoteSwitch and the
|
||||
* ThermoHygroReceiver of RemoteSensor all at the same time!
|
||||
*
|
||||
* After uploading, enable the serial monitor at 115200 baud.
|
||||
* When you press buttons on a 433MHz remote control, as supported by
|
||||
* RemoteSwitch or NewRemoteSwitch, the code will be echoed.
|
||||
* At the same time, if data of a remote thermo/hygro-sensor is
|
||||
* received, as supported by RemoteSensor, it will be echoed as well.
|
||||
*
|
||||
* Setup:
|
||||
* - connect a 433MHz receiver on digital pin 2.
|
||||
*
|
||||
* MySensor note: This example has not yet been adopted but can be used as an example
|
||||
* of receiving 433Mhz stuff.
|
||||
*
|
||||
* One idea could be to echo received 433 codes back to gateway to be able to pick up and
|
||||
* handle data over there.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <RemoteReceiver.h>
|
||||
#include <NewRemoteReceiver.h>
|
||||
#include <SensorReceiver.h>
|
||||
#include <InterruptChain.h>
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Interrupt -1 to indicate you will call the interrupt handler with InterruptChain
|
||||
RemoteReceiver::init(-1, 2, showOldCode);
|
||||
|
||||
// Again, interrupt -1 to indicate you will call the interrupt handler with InterruptChain
|
||||
NewRemoteReceiver::init(-1, 2, showNewCode);
|
||||
|
||||
// And once more, interrupt -1 to indicate you will call the interrupt handler with InterruptChain
|
||||
SensorReceiver::init(-1, showTempHumi);
|
||||
|
||||
// On interrupt, call the interrupt handlers of remote and sensor receivers
|
||||
InterruptChain::addInterruptCallback(0, RemoteReceiver::interruptHandler);
|
||||
InterruptChain::addInterruptCallback(0, NewRemoteReceiver::interruptHandler);
|
||||
InterruptChain::addInterruptCallback(0, SensorReceiver::interruptHandler);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// You can do other stuff here!
|
||||
}
|
||||
|
||||
// shows the received code sent from an old-style remote switch
|
||||
void showOldCode(unsigned long receivedCode, unsigned int period) {
|
||||
// Print the received code.
|
||||
Serial.print("Code: ");
|
||||
Serial.print(receivedCode);
|
||||
Serial.print(", period: ");
|
||||
Serial.print(period);
|
||||
Serial.println("us.");
|
||||
}
|
||||
|
||||
// Shows the received code sent from an new-style remote switch
|
||||
void showNewCode(NewRemoteCode receivedCode) {
|
||||
// Print the received code.
|
||||
Serial.print("Addr ");
|
||||
Serial.print(receivedCode.address);
|
||||
|
||||
if (receivedCode.groupBit) {
|
||||
Serial.print(" group");
|
||||
} else {
|
||||
Serial.print(" unit ");
|
||||
Serial.print(receivedCode.unit);
|
||||
}
|
||||
|
||||
switch (receivedCode.switchType) {
|
||||
case NewRemoteCode::off:
|
||||
Serial.print(" off");
|
||||
break;
|
||||
case NewRemoteCode::on:
|
||||
Serial.print(" on");
|
||||
break;
|
||||
case NewRemoteCode::dim:
|
||||
Serial.print(" dim level ");
|
||||
Serial.print(receivedCode.dimLevel);
|
||||
break;
|
||||
case NewRemoteCode::on_with_dim:
|
||||
Serial.print(" on with dim level ");
|
||||
Serial.print(receivedCode.dimLevel);
|
||||
break;
|
||||
}
|
||||
|
||||
Serial.print(", period: ");
|
||||
Serial.print(receivedCode.period);
|
||||
Serial.println("us.");
|
||||
}
|
||||
|
||||
// Shows the received sensor data
|
||||
void showTempHumi(byte *data) {
|
||||
// is data a ThermoHygro-device?
|
||||
if ((data[3] & 0x1f) == 0x1e) {
|
||||
// Yes!
|
||||
byte channel, randomId;
|
||||
int temp;
|
||||
byte humidity;
|
||||
|
||||
// Decode the data
|
||||
SensorReceiver::decodeThermoHygro(data, channel, randomId, temp, humidity);
|
||||
|
||||
// Print temperature. Note: temp is 10x the actual temperature!
|
||||
Serial.print("Temperature: ");
|
||||
Serial.print(temp / 10); // units
|
||||
Serial.print('.');
|
||||
Serial.println(temp % 10); // decimal
|
||||
}
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* RFID Lock sensor/actuator
|
||||
*
|
||||
* Use RFID tag to lock/unlock a door or trigger a scene on your controller.
|
||||
* This example sketch allows you to add an optional relay or solenoid
|
||||
* which can be activated/opened by RFID or controller.
|
||||
*
|
||||
* Use the I2C wiring option for your RFID module and connect to the following Arduino pins.
|
||||
*
|
||||
* RFID Arduino
|
||||
* ----- -------
|
||||
* GND -> GND
|
||||
* VCC -> +5V
|
||||
* SCL -> A5
|
||||
* SDA -> A4
|
||||
*
|
||||
* Use normal wiring for NRF24L01 radio
|
||||
*
|
||||
* Attach a optional relay or solonoid lock to pin 4
|
||||
* http://www.mysensors.org/build/rfid
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <Wire.h>
|
||||
#include <PN532_I2C.h>
|
||||
#include <PN532.h>
|
||||
|
||||
|
||||
// Add your valid rfid keys here. To find you your key just run sketch; hold your new RFID tag in fron ot the reader;
|
||||
// and copy the key from serial output of this sketch.
|
||||
const uint8_t maxKeyLength = 7;
|
||||
uint8_t validKeys[][maxKeyLength] = {
|
||||
{ 0xB3, 0xC6, 0xD9, 0x80, 0x00, 0x00, 0x00 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0 }, // ADD YOUR KEYS HERE!
|
||||
{ 0, 0, 0, 0, 0, 0, 0 }};
|
||||
int keyCount = sizeof validKeys / maxKeyLength;
|
||||
|
||||
|
||||
#define CHILD_ID 99 // Id of the sensor child
|
||||
|
||||
// Pin definition
|
||||
const int lockPin = 4; // (Digital 4) The pin that activates the relay/solenoid lock.
|
||||
bool lockStatus;
|
||||
MyMessage lockMsg(CHILD_ID, V_LOCK_STATUS);
|
||||
PN532_I2C pn532i2c(Wire);
|
||||
PN532 nfc(pn532i2c);
|
||||
|
||||
void setup() {
|
||||
|
||||
pinMode(lockPin, OUTPUT);
|
||||
|
||||
nfc.begin();
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (! versiondata) {
|
||||
Serial.print("Couldn't find PN53x board");
|
||||
while (1); // halt
|
||||
}
|
||||
Serial.print("Found NFC chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
// Set the max number of retry attempts to read from a card
|
||||
// This prevents us from waiting forever for a card, which is
|
||||
// the default behaviour of the PN532.
|
||||
nfc.setPassiveActivationRetries(0x3);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
|
||||
// Add callback for incoming messages
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
sendSketchInfo("RFID Lock", "1.0");
|
||||
present(CHILD_ID, S_LOCK);
|
||||
|
||||
lockStatus = loadState(0); // Read last lock status from eeprom
|
||||
setLockState(lockStatus, true); // Now set the last known state and send it to controller
|
||||
}
|
||||
|
||||
void loop() {
|
||||
boolean success;
|
||||
uint8_t key[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t currentKeyLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
|
||||
|
||||
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &key[0], ¤tKeyLength);
|
||||
|
||||
if (success) {
|
||||
Serial.print("Found tag id: ");
|
||||
for (uint8_t i=0; i < currentKeyLength; i++)
|
||||
{
|
||||
if (i>0) Serial.print(",");
|
||||
Serial.print("0x");Serial.print(key[i], HEX);
|
||||
}
|
||||
for (uint8_t i=currentKeyLength; i < maxKeyLength; i++)
|
||||
{
|
||||
Serial.print(",0x00");
|
||||
}
|
||||
|
||||
|
||||
Serial.println("");
|
||||
|
||||
boolean valid = false;
|
||||
// Compare this key to the valid once registered here in sketch
|
||||
for (int i=0;i<keyCount && !valid;i++) {
|
||||
for (int j=0;i<currentKeyLength && !valid;j++) {
|
||||
if (key[j] != validKeys[i][j]) {
|
||||
break;
|
||||
}
|
||||
if (j==currentKeyLength-1) {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
// Switch lock status
|
||||
setLockState(!lockStatus, true);
|
||||
}
|
||||
|
||||
// Wait for card/tag to leave reader
|
||||
while(nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &key[0], ¤tKeyLength));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Unlocks the door.
|
||||
void setLockState(bool state, bool doSend){
|
||||
if (state)
|
||||
Serial.println("open lock");
|
||||
else
|
||||
Serial.println("close lock");
|
||||
if (doSend)
|
||||
send(lockMsg.set(state));
|
||||
digitalWrite(lockPin, state);
|
||||
saveState(0,state);
|
||||
lockStatus = state;
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
// We only expect one type of message from controller. But we better check anyway.
|
||||
if (message.type==V_LOCK_STATUS) {
|
||||
// Change relay state
|
||||
setLockState(message.getBool(), false);
|
||||
|
||||
// Write some debug info
|
||||
Serial.print("Incoming lock status:");
|
||||
Serial.println(message.getBool());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,304 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Created by vil1driver
|
||||
*
|
||||
* DESCRIPTION
|
||||
* RGB led strip controled with three dimmers + one On/Off for run/stop rgb color cycle :p
|
||||
*
|
||||
*/
|
||||
|
||||
#define SN "RGB Led strip 3D"
|
||||
#define SV "v1"
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
// Arduino pin attached to MOSFET Gate pin
|
||||
#define RED_PIN 3
|
||||
#define GREEN_PIN 5
|
||||
#define BLUE_PIN 6
|
||||
|
||||
// Define message name and type to send sensor info
|
||||
MyMessage RedStatus(RED_PIN, V_DIMMER);
|
||||
MyMessage GreenStatus(GREEN_PIN, V_DIMMER);
|
||||
MyMessage BlueStatus(BLUE_PIN, V_DIMMER);
|
||||
MyMessage Status(1, V_DIMMER);
|
||||
MyMessage rgbShowState(0, V_LIGHT);
|
||||
|
||||
// Serial.print translate sensor id to sensor name
|
||||
char color[][6] = {"","","","RED","","GREEN","BLUE"};
|
||||
|
||||
// Vars for rgbShow function
|
||||
int redval = 0;
|
||||
int greenval = 0;
|
||||
int blueval = 0;
|
||||
long time=0;
|
||||
int isShow;
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Add callback for incoming messages
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
// Present sketch (name, version)
|
||||
sendSketchInfo(SN, SV);
|
||||
|
||||
// Register sensors (id, type, description, ack back)
|
||||
present(RED_PIN, S_DIMMER, "present RED light", false);
|
||||
present(GREEN_PIN, S_DIMMER, "present GREEN light", false);
|
||||
present(BLUE_PIN, S_DIMMER, "present BLUE light", false);
|
||||
present(0, S_LIGHT, "present Show button", false);
|
||||
|
||||
// Define pin mode (pin number, type)
|
||||
pinMode(RED_PIN, OUTPUT);
|
||||
pinMode(GREEN_PIN, OUTPUT);
|
||||
pinMode(BLUE_PIN, OUTPUT);
|
||||
|
||||
// Correct saved RGB value for first start
|
||||
saveState(RED_PIN, constrain((int8_t)loadState(RED_PIN), 0, 100));
|
||||
saveState(GREEN_PIN, constrain((int8_t)loadState(GREEN_PIN), 0, 100));
|
||||
saveState(BLUE_PIN, constrain((int8_t)loadState(BLUE_PIN), 0, 100));
|
||||
|
||||
// Get value from eeprom and write to output
|
||||
analogWrite(RED_PIN, 255 * loadState(RED_PIN) / 100);
|
||||
analogWrite(GREEN_PIN, 255 * loadState(GREEN_PIN) / 100);
|
||||
analogWrite(BLUE_PIN, 255 * loadState(BLUE_PIN) / 100);
|
||||
|
||||
// Write some debug info
|
||||
Serial.print("Load from eeprom RED: ");
|
||||
Serial.print(loadState(RED_PIN));
|
||||
Serial.println("%");
|
||||
Serial.print("Load from eeprom GREEN: ");
|
||||
Serial.print(loadState(GREEN_PIN));
|
||||
Serial.println("%");
|
||||
Serial.print("Load from eeprom BLUE: ");
|
||||
Serial.print(loadState(BLUE_PIN));
|
||||
Serial.println("%");
|
||||
|
||||
// Send RGB value to controler (request ack back: true/false)
|
||||
Serial.println("Send eeprom value to controler");
|
||||
send( RedStatus.set(loadState(RED_PIN)), false );
|
||||
send( GreenStatus.set(loadState(GREEN_PIN)), false );
|
||||
send( BlueStatus.set(loadState(BLUE_PIN)), false );
|
||||
|
||||
// Correct RGB show state for first start and load it (set to 'On' at first start)
|
||||
saveState(0, constrain((int8_t)loadState(0), 0, 1));
|
||||
isShow=loadState(0);
|
||||
|
||||
// Send RGB show state to controler (request ack back: true/false)
|
||||
send( rgbShowState.set(isShow), false);
|
||||
|
||||
if (isShow==1){Serial.println("RGB show running..."); }
|
||||
Serial.println("Ready to receive messages...");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Run RGB show if is set
|
||||
if (isShow==1)
|
||||
{
|
||||
rgbShow();
|
||||
analogWrite(RED_PIN, redval);
|
||||
analogWrite(GREEN_PIN, greenval);
|
||||
analogWrite(BLUE_PIN, blueval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void incomingMessage(const MyMessage &message)
|
||||
{
|
||||
if (message.isAck())
|
||||
{
|
||||
Serial.println("Got ack from gateway");
|
||||
}
|
||||
if (message.type == V_LIGHT)
|
||||
{
|
||||
// Incoming on/off command sent from controller ("1" or "0")
|
||||
int lightState = message.getString()[0] == '1';
|
||||
|
||||
// if receive RGB Show On commands, start the show
|
||||
if (message.sensor==0 && lightState==1){ rgbShowOn(); }
|
||||
// if receive RGB Show Off commands, stop the show
|
||||
else if (message.sensor==0 && lightState==0){ rgbShowOff(); }
|
||||
|
||||
// if receive RGB switch On command
|
||||
else if (lightState==1)
|
||||
{
|
||||
// Write some debug info
|
||||
Serial.print("Incoming change for ");
|
||||
Serial.print(color[message.sensor]);
|
||||
Serial.println(": On");
|
||||
Serial.print("Load from eeprom: ");
|
||||
|
||||
if ( loadState(message.sensor) == 0)
|
||||
{
|
||||
// Pick up last saved dimmer level from the eeprom
|
||||
analogWrite(message.sensor, 255 * loadState(10*message.sensor) / 100);
|
||||
// Save loaded value to current
|
||||
saveState(message.sensor, loadState(10*message.sensor));
|
||||
Serial.print(loadState(10*message.sensor));
|
||||
Serial.println("%");
|
||||
// Send value to controler
|
||||
Serial.println("Send value to controler");
|
||||
send(Status.setSensor(message.sensor).set(loadState(10*message.sensor)),false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pick up last saved dimmer level from the eeprom
|
||||
analogWrite(message.sensor, 255 * loadState(message.sensor) / 100);
|
||||
Serial.print(loadState(message.sensor));
|
||||
Serial.println("%");
|
||||
// Send value to controler
|
||||
Serial.println("Send value to controler");
|
||||
send(Status.setSensor(message.sensor).set(loadState(message.sensor)),false);
|
||||
}
|
||||
// Stop the show if it's running
|
||||
if (isShow==1){ rgbShowStop(message.sensor); }
|
||||
}
|
||||
// if recieve switch Off command
|
||||
else if (lightState==0)
|
||||
{
|
||||
// Write output to 0 (Off)
|
||||
analogWrite(message.sensor, 0);
|
||||
// Save old value to eeprom if it'was not zero
|
||||
if ( loadState(message.sensor) != 0 )
|
||||
{
|
||||
saveState(10*message.sensor, constrain((int8_t)loadState(message.sensor), 0, 100));
|
||||
}
|
||||
// Save new value to eeprom
|
||||
saveState(message.sensor, 0);
|
||||
// Write some debug info
|
||||
Serial.print("Incoming change for ");
|
||||
Serial.print(color[message.sensor]);
|
||||
Serial.print(": ");
|
||||
Serial.println("Off");
|
||||
Serial.print("Store old value: ");
|
||||
Serial.print(loadState(10*message.sensor));
|
||||
Serial.println("%");
|
||||
// Send value to controler
|
||||
Serial.println("Send value to controler");
|
||||
send(Status.setSensor(message.sensor).set(loadState(message.sensor)),false);
|
||||
// Stop the show if it's running
|
||||
if (isShow==1){ rgbShowStop(message.sensor); }
|
||||
}
|
||||
}
|
||||
else if (message.type == V_DIMMER)
|
||||
{
|
||||
uint8_t incomingDimmerStatus = message.getByte();
|
||||
// limits range of sensor values to between 0 and 100
|
||||
incomingDimmerStatus = constrain((int8_t)incomingDimmerStatus, 0, 100);
|
||||
// Change Dimmer level
|
||||
analogWrite(message.sensor, 255 * incomingDimmerStatus / 100);
|
||||
//Save value to eeprom
|
||||
saveState(message.sensor, incomingDimmerStatus);
|
||||
// Write some debug info
|
||||
Serial.print("Incoming change for ");
|
||||
Serial.print(color[message.sensor]);
|
||||
Serial.print(": ");
|
||||
Serial.print(incomingDimmerStatus);
|
||||
Serial.println("%");
|
||||
// Send value to controler
|
||||
Serial.println("Send value to controler");
|
||||
send(Status.setSensor(message.sensor).set(loadState(message.sensor)),false);
|
||||
// Stop the show if it's running
|
||||
if (isShow==1){ rgbShowStop(message.sensor); }
|
||||
}
|
||||
}
|
||||
|
||||
void rgbShow()
|
||||
{
|
||||
time = millis();
|
||||
redval = 128+250*cos(2*PI/300000*time);
|
||||
greenval = 128+250*cos(2*PI/300000*time-222);
|
||||
blueval = 128+250*cos(2*PI/300000*time-111);
|
||||
// limits range of sensor values to between 0 and 255
|
||||
redval = constrain(redval, 0, 255);
|
||||
greenval = constrain(greenval, 0, 255);
|
||||
blueval = constrain(blueval, 0, 255);
|
||||
}
|
||||
|
||||
void rgbShowOn()
|
||||
{
|
||||
// define show On
|
||||
isShow=1;
|
||||
// Save state
|
||||
saveState(0, 1);
|
||||
// Write some debug info
|
||||
Serial.println("Show must go on");
|
||||
}
|
||||
|
||||
void rgbShowOff()
|
||||
{
|
||||
// define show Off
|
||||
isShow=0;
|
||||
// Save state
|
||||
saveState(0, 0);
|
||||
// Save RGB value to eeprom
|
||||
saveState(RED_PIN, 100 * redval / 255);
|
||||
saveState(GREEN_PIN, 100 * greenval / 255);
|
||||
saveState(BLUE_PIN, 100 * blueval / 255);
|
||||
// Write some debug info
|
||||
Serial.println("Stop the show");
|
||||
// Send actual RGB value and state to controler and request ack back (true/false)
|
||||
Serial.println("Send eeprom value to controler");
|
||||
send( RedStatus.set(loadState(RED_PIN)), false );
|
||||
send( GreenStatus.set(loadState(GREEN_PIN)), false );
|
||||
send( BlueStatus.set(loadState(BLUE_PIN)), false );
|
||||
send( rgbShowState.set(0), false);
|
||||
}
|
||||
|
||||
void rgbShowStop(int sensor)
|
||||
{
|
||||
// define show Off
|
||||
isShow=0;
|
||||
// Save state
|
||||
saveState(0, 0);
|
||||
// Write some debug info
|
||||
Serial.println("Stop the show");
|
||||
// Send actual RGB value and state to controler and request ack back (true/false)
|
||||
Serial.println("Send eeprom value to controler");
|
||||
if (sensor != RED_PIN)
|
||||
{
|
||||
saveState(RED_PIN, 100 * redval / 255);
|
||||
send( RedStatus.set(loadState(RED_PIN)), false );
|
||||
}
|
||||
if (sensor != GREEN_PIN)
|
||||
{
|
||||
saveState(GREEN_PIN, 100 * greenval / 255);
|
||||
send( GreenStatus.set(loadState(GREEN_PIN)), false );
|
||||
}
|
||||
if (sensor != BLUE_PIN)
|
||||
{
|
||||
saveState(BLUE_PIN, 100 * blueval / 255);
|
||||
send( BlueStatus.set(loadState(BLUE_PIN)), false );
|
||||
}
|
||||
send( rgbShowState.set(0), false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,599 +0,0 @@
|
||||
/*
|
||||
Arduino Tipping Bucket Rain Gauge
|
||||
|
||||
April 26, 2015
|
||||
|
||||
Version 1.4.1 alpha
|
||||
|
||||
Arduino Tipping Bucket Rain Gauge
|
||||
|
||||
Utilizing a tipping bucket sensor, your Vera home automation controller and the MySensors.org
|
||||
gateway you can measure and sense local rain. This sketch will create two devices on your
|
||||
Vera controller. One will display your total precipitation for the last 5 days. The other,
|
||||
a sensor that changes state if there is recent rain (up to last 120 hours) above a threshold.
|
||||
Both these settings are user definable.
|
||||
|
||||
There is a build overview video here: https://youtu.be/1eMfKQaLROo
|
||||
|
||||
This sketch features the following:
|
||||
|
||||
* Allows you to set the rain threshold in mm
|
||||
* Allows you to determine the tripped indicator window up to 120 hours.
|
||||
* Displays the last 5 days of rain in Variable1 through Variable5
|
||||
of the Rain Sensor device
|
||||
* Configuration changes to Sensor device updated every hour
|
||||
* Should run on any Arduino
|
||||
* Will retain Tripped/Not Tripped status and data in a power interruption, saving small amount
|
||||
of data to EEPROM (Circular Buffer to maximize life of EEPROM)
|
||||
* LED status indicator
|
||||
* Optional Temp/Humidity (DHT-22 or DHT-11) and Light LUX (BH1750) sensors. To use, uncomment
|
||||
#define DHT_ON and/or #define LUX_ON
|
||||
* Optionally send total accumulation of each day's rainfall or send only individual days rainfall totals.
|
||||
Comment out #define USE_DAILY to display individual daily rainfall.
|
||||
|
||||
by @BulldogLowell and @PeteWill for free public use
|
||||
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
//#define MY_NODE_ID 7
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <math.h>
|
||||
#include <Time.h>
|
||||
|
||||
#define SKETCH_NAME "Rain Gauge"
|
||||
#define SKETCH_VERSION "1.4.1a"
|
||||
|
||||
#define DWELL_TIME 125 // this allows for radio to come back to power after a transmission, ideally 0
|
||||
|
||||
//#define DEBUG_ON // comment out this line to disable serial debug
|
||||
#define DHT_ON // uncomment out this line to enable DHT sensor
|
||||
#define LUX_ON // uncomment out this line to enable BH1750 sensor
|
||||
//#define USE_DAILY // displays each time segment as an accumulation of prior periods inclusive. Comment out to display individual daily rainfall totals in the variables sent to your controller.
|
||||
|
||||
#define CALIBRATE_FACTOR 60 // amount of rain per rain bucket tip e.g. 5 is .05mm
|
||||
#define DHT_LUX_DELAY 300000 //Delay in milliseconds that the DHT and LUX sensors will wait before sending data
|
||||
|
||||
#define CHILD_ID_RAIN_LOG 3 // Keeps track of accumulated rainfall
|
||||
#define CHILD_ID_TRIPPED_INDICATOR 4 // Indicates Tripped when rain detected
|
||||
#define EEPROM_BUFFER_LOCATION 0 // location of the EEPROM circular buffer
|
||||
#define E_BUFFER_LENGTH 240
|
||||
#define RAIN_BUCKET_SIZE 120
|
||||
|
||||
#ifdef DEBUG_ON
|
||||
#define DEBUG_PRINT(x) Serial.print(x)
|
||||
#define DEBUG_PRINTLN(x) Serial.println(x)
|
||||
#define SERIAL_START(x) Serial.begin(x)
|
||||
#else
|
||||
#define DEBUG_PRINT(x)
|
||||
#define DEBUG_PRINTLN(x)
|
||||
#define SERIAL_START(x)
|
||||
#endif
|
||||
//
|
||||
MyMessage msgRainRate(CHILD_ID_RAIN_LOG, V_RAINRATE);
|
||||
MyMessage msgRain(CHILD_ID_RAIN_LOG, V_RAIN);
|
||||
//
|
||||
MyMessage msgRainVAR1(CHILD_ID_RAIN_LOG, V_VAR1);
|
||||
MyMessage msgRainVAR2(CHILD_ID_RAIN_LOG, V_VAR2);
|
||||
MyMessage msgRainVAR3(CHILD_ID_RAIN_LOG, V_VAR3);
|
||||
MyMessage msgRainVAR4(CHILD_ID_RAIN_LOG, V_VAR4);
|
||||
MyMessage msgRainVAR5(CHILD_ID_RAIN_LOG, V_VAR5);
|
||||
//
|
||||
MyMessage msgTripped(CHILD_ID_TRIPPED_INDICATOR, V_TRIPPED);
|
||||
MyMessage msgTrippedVar1(CHILD_ID_TRIPPED_INDICATOR, V_VAR1);
|
||||
MyMessage msgTrippedVar2(CHILD_ID_TRIPPED_INDICATOR, V_VAR2);
|
||||
//
|
||||
#ifdef DHT_ON
|
||||
#include <DHT.h>
|
||||
#define CHILD_ID_HUM 0
|
||||
#define CHILD_ID_TEMP 1
|
||||
#define HUMIDITY_SENSOR_DIGITAL_PIN 8
|
||||
DHT dht;
|
||||
float lastTemp;
|
||||
float lastHum;
|
||||
boolean metric = true;
|
||||
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
|
||||
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
|
||||
#endif
|
||||
//
|
||||
#ifdef LUX_ON
|
||||
//BH1750 is connected to SCL (analog input A5) and SDA (analog input A4)
|
||||
#include <BH1750.h>
|
||||
#include <Wire.h>
|
||||
#define CHILD_ID_LIGHT 2
|
||||
BH1750 lightSensor;
|
||||
MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
|
||||
unsigned int lastlux;
|
||||
byte heartbeat = 10; //Used to send the light lux to gateway as soon as the device is restarted and after the DHT_LUX_DELAY has happened 10 times
|
||||
#endif
|
||||
unsigned long sensorPreviousMillis;
|
||||
int eepromIndex;
|
||||
int tipSensorPin = 3; // Pin the tipping bucket is connected to. Must be interrupt capable pin
|
||||
int ledPin = 5; // Pin the LED is connected to. PWM capable pin required
|
||||
unsigned long dataMillis;
|
||||
unsigned long serialInterval = 600000UL;
|
||||
const unsigned long oneHour = 3600000UL;
|
||||
unsigned long lastTipTime;
|
||||
unsigned long lastRainTime; //Used for rainRate calculation
|
||||
unsigned int rainBucket [RAIN_BUCKET_SIZE] ; /* 24 hours x 5 Days = 120 hours */
|
||||
unsigned int rainRate = 0;
|
||||
byte rainWindow = 72; //default rain window in hours. Will be overwritten with msgTrippedVar1.
|
||||
volatile int wasTippedBuffer = 0;
|
||||
int rainSensorThreshold = 50; //default rain sensor sensitivity in hundredths. Will be overwritten with msgTrippedVar2.
|
||||
byte state = 0;
|
||||
byte oldState = -1;
|
||||
unsigned int lastRainRate = 0;
|
||||
int lastMeasure = 0;
|
||||
boolean gotTime = false;
|
||||
byte lastHour;
|
||||
byte currentHour;
|
||||
//
|
||||
void setup()
|
||||
{
|
||||
SERIAL_START(115200);
|
||||
//
|
||||
// Set up the IO
|
||||
pinMode(tipSensorPin, INPUT_PULLUP);
|
||||
attachInterrupt (1, sensorTipped, FALLING); // depending on location of the hall effect sensor may need CHANGE
|
||||
pinMode(ledPin, OUTPUT);
|
||||
digitalWrite(ledPin, HIGH);
|
||||
//
|
||||
//Let's get the controller talking to the Arduino
|
||||
setIncomingCallback(getVariables);
|
||||
|
||||
sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
|
||||
wait(DWELL_TIME);
|
||||
present(CHILD_ID_RAIN_LOG, S_RAIN);
|
||||
wait(DWELL_TIME);
|
||||
present(CHILD_ID_TRIPPED_INDICATOR, S_MOTION);
|
||||
wait(DWELL_TIME);
|
||||
DEBUG_PRINTLN(F("Sensor Presentation Complete"));
|
||||
//
|
||||
//Sync time with the server, this will be called hourly in order to keep time from creeping with the crystal
|
||||
//
|
||||
unsigned long functionTimeout = millis();
|
||||
while (timeStatus() == timeNotSet && millis() - functionTimeout < 30000UL)
|
||||
{
|
||||
requestTime(receiveTime);
|
||||
DEBUG_PRINTLN(F("Getting Time"));
|
||||
wait(1000); // call once per second
|
||||
DEBUG_PRINTLN(F("."));
|
||||
}
|
||||
currentHour = hour();
|
||||
lastHour = hour();
|
||||
//
|
||||
//retrieve from EEPROM stored values on a power cycle.
|
||||
//
|
||||
boolean isDataOnEeprom = false;
|
||||
for (int i = 0; i < E_BUFFER_LENGTH; i++)
|
||||
{
|
||||
byte locator = loadState(EEPROM_BUFFER_LOCATION + i);
|
||||
if (locator == 0xFE) // found the EEPROM circular buffer index
|
||||
{
|
||||
eepromIndex = EEPROM_BUFFER_LOCATION + i;
|
||||
DEBUG_PRINT(F("EEPROM Index "));
|
||||
DEBUG_PRINTLN(eepromIndex);
|
||||
//Now that we have the buffer index let's populate the rainBucket[] with data from eeprom
|
||||
loadRainArray(eepromIndex);
|
||||
isDataOnEeprom = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
if (!isDataOnEeprom) // Added for the first time it is run on a new Arduino
|
||||
{
|
||||
DEBUG_PRINTLN(F("I didn't find valid EEPROM Index, so I'm writing one to location 0"));
|
||||
eepromIndex = EEPROM_BUFFER_LOCATION;
|
||||
saveState(eepromIndex, 0xFE);
|
||||
saveState(eepromIndex + 1, 0xFE);
|
||||
//then I will clear out any bad data
|
||||
for (int i = 2; i <= E_BUFFER_LENGTH; i++)
|
||||
{
|
||||
saveState(i, 0x00);
|
||||
}
|
||||
}
|
||||
dataMillis = millis();
|
||||
lastTipTime = millis() - oneHour; //why is this -oneHour?? Doesn't millis() start at 0 when first powered on?
|
||||
//
|
||||
request(CHILD_ID_TRIPPED_INDICATOR, V_VAR1);
|
||||
wait(DWELL_TIME);
|
||||
request(CHILD_ID_TRIPPED_INDICATOR, V_VAR2);
|
||||
wait(DWELL_TIME);
|
||||
//
|
||||
#ifdef DHT_ON
|
||||
dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
present(CHILD_ID_HUM, S_HUM);
|
||||
wait(DWELL_TIME);
|
||||
present(CHILD_ID_TEMP, S_TEMP);
|
||||
wait(DWELL_TIME);
|
||||
metric = getConfig().isMetric;
|
||||
wait(DWELL_TIME);
|
||||
#endif
|
||||
//
|
||||
#ifdef LUX_ON
|
||||
present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
|
||||
wait(DWELL_TIME);
|
||||
lightSensor.begin();
|
||||
#endif
|
||||
//
|
||||
DEBUG_PRINTLN(F("Radio Setup Complete!"));
|
||||
transmitRainData();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
prettyFade(); // breathe if tripped
|
||||
}
|
||||
else
|
||||
{
|
||||
slowFlash(); // blink if not tripped
|
||||
}
|
||||
#ifdef DEBUG_ON // Serial Debug Block
|
||||
if ( (millis() - dataMillis) >= serialInterval)
|
||||
{
|
||||
for (int i = 24; i <= 120; i = i + 24)
|
||||
{
|
||||
updateSerialData(i);
|
||||
}
|
||||
dataMillis = millis();
|
||||
}
|
||||
#endif
|
||||
//
|
||||
// let's constantly check to see if the rain in the past rainWindow hours is greater than rainSensorThreshold
|
||||
//
|
||||
int measure = 0; // Check to see if we need to show sensor tripped in this block
|
||||
for (int i = 0; i < rainWindow; i++)
|
||||
{
|
||||
measure += rainBucket [i];
|
||||
if (measure != lastMeasure)
|
||||
{
|
||||
// DEBUG_PRINT(F("measure value (total rainBucket within rainWindow): "));
|
||||
// DEBUG_PRINTLN(measure);
|
||||
lastMeasure = measure;
|
||||
}
|
||||
}
|
||||
//
|
||||
state = (measure >= (rainSensorThreshold * 100));
|
||||
if (state != oldState)
|
||||
{
|
||||
send(msgTripped.set(state));
|
||||
wait(DWELL_TIME);
|
||||
DEBUG_PRINT(F("New Sensor State... Sensor: "));
|
||||
DEBUG_PRINTLN(state ? "Tripped" : "Not Tripped");
|
||||
oldState = state;
|
||||
}
|
||||
//
|
||||
unsigned long tipDelay = millis() - lastRainTime;
|
||||
if (wasTippedBuffer) // if was tipped, then update the 24hour total and transmit to Vera
|
||||
{
|
||||
DEBUG_PRINTLN(F("Sensor Tipped"));
|
||||
DEBUG_PRINT(F("rainBucket [0] value: "));
|
||||
DEBUG_PRINTLN(rainBucket [0]);
|
||||
send(msgRain.set((float)rainTotal(currentHour) / 100, 1)); //Calculate the total rain for the day
|
||||
wait(DWELL_TIME);
|
||||
wasTippedBuffer--;
|
||||
rainRate = ((oneHour) / tipDelay);
|
||||
if (rainRate != lastRainRate)
|
||||
{
|
||||
send(msgRainRate.set(rainRate, 1));
|
||||
wait(DWELL_TIME);
|
||||
DEBUG_PRINT(F("RainRate= "));
|
||||
DEBUG_PRINTLN(rainRate);
|
||||
lastRainRate = rainRate;
|
||||
}
|
||||
lastRainTime = lastTipTime;
|
||||
}
|
||||
//
|
||||
currentHour = hour();
|
||||
if (currentHour != lastHour)
|
||||
{
|
||||
DEBUG_PRINTLN(F("One hour elapsed."));
|
||||
send(msgRain.set((float)rainTotal(currentHour) / 100, 1)); // send today's rainfall
|
||||
wait(DWELL_TIME);
|
||||
saveState(eepromIndex, highByte(rainBucket[0]));
|
||||
saveState(eepromIndex + 1, lowByte(rainBucket[0]));
|
||||
DEBUG_PRINT(F("Saving rainBucket[0] to eeprom. rainBucket[0] = "));
|
||||
DEBUG_PRINTLN(rainBucket[0]);
|
||||
for (int i = RAIN_BUCKET_SIZE - 1; i >= 0; i--)//cascade an hour of values back into the array
|
||||
{
|
||||
rainBucket [i + 1] = rainBucket [i];
|
||||
}
|
||||
request(CHILD_ID_TRIPPED_INDICATOR, V_VAR1);
|
||||
wait(DWELL_TIME);
|
||||
request(CHILD_ID_TRIPPED_INDICATOR, V_VAR2);
|
||||
wait(DWELL_TIME);
|
||||
rainBucket[0] = 0;
|
||||
eepromIndex = eepromIndex + 2;
|
||||
if (eepromIndex > EEPROM_BUFFER_LOCATION + E_BUFFER_LENGTH)
|
||||
{
|
||||
eepromIndex = EEPROM_BUFFER_LOCATION;
|
||||
}
|
||||
DEBUG_PRINT(F("Writing to EEPROM. Index: "));
|
||||
DEBUG_PRINTLN(eepromIndex);
|
||||
saveState(eepromIndex, 0xFE);
|
||||
saveState(eepromIndex + 1, 0xFE);
|
||||
requestTime(receiveTime); // sync the time every hour
|
||||
wait(DWELL_TIME);
|
||||
transmitRainData();
|
||||
rainRate = 0;
|
||||
send(msgRainRate.set(rainRate, 1));
|
||||
wait(DWELL_TIME);
|
||||
DEBUG_PRINTLN(F("Sending rainRate is 0 to controller"));
|
||||
lastHour = currentHour;
|
||||
}
|
||||
if (millis() - sensorPreviousMillis > DHT_LUX_DELAY)
|
||||
{
|
||||
#ifdef DHT_ON //DHT Code
|
||||
doDHT();
|
||||
#endif
|
||||
#ifdef LUX_ON
|
||||
doLUX();
|
||||
#endif
|
||||
sensorPreviousMillis = millis();
|
||||
}
|
||||
}
|
||||
//
|
||||
#ifdef DHT_ON
|
||||
void doDHT(void)
|
||||
{
|
||||
float temperature = dht.getTemperature();
|
||||
if (isnan(temperature))
|
||||
{
|
||||
DEBUG_PRINTLN(F("Failed reading temperature from DHT"));
|
||||
} else if (temperature != lastTemp)
|
||||
{
|
||||
lastTemp = temperature;
|
||||
if (!metric)
|
||||
{
|
||||
temperature = dht.toFahrenheit(temperature);
|
||||
}
|
||||
send(msgTemp.set(temperature, 1));
|
||||
wait(DWELL_TIME);
|
||||
DEBUG_PRINT(F("Temperature is: "));
|
||||
DEBUG_PRINTLN(temperature);
|
||||
}
|
||||
float humidity = dht.getHumidity();;
|
||||
if (isnan(humidity))
|
||||
{
|
||||
DEBUG_PRINTLN(F("Failed reading humidity from DHT"));
|
||||
} else if (humidity != lastHum)
|
||||
{
|
||||
lastHum = humidity;
|
||||
send(msgHum.set(humidity, 1));
|
||||
wait(DWELL_TIME);
|
||||
DEBUG_PRINT(F("Humidity is: "));
|
||||
DEBUG_PRINTLN(humidity);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//
|
||||
#ifdef LUX_ON
|
||||
void doLUX(void)
|
||||
{
|
||||
unsigned int lux = lightSensor.readLightLevel();// Get Lux value
|
||||
DEBUG_PRINT(F("Current LUX Level: "));
|
||||
DEBUG_PRINTLN(lux);
|
||||
heartbeat++;
|
||||
if (lux != lastlux || heartbeat > 10)
|
||||
{
|
||||
send(msg.set(lux));
|
||||
lastlux = lux;
|
||||
}
|
||||
if (heartbeat > 10)
|
||||
{
|
||||
heartbeat = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//
|
||||
void sensorTipped()
|
||||
{
|
||||
unsigned long thisTipTime = millis();
|
||||
if (thisTipTime - lastTipTime > 100UL)
|
||||
{
|
||||
rainBucket[0] += CALIBRATE_FACTOR; // adds CALIBRATE_FACTOR hundredths of unit each tip
|
||||
wasTippedBuffer++;
|
||||
}
|
||||
lastTipTime = thisTipTime;
|
||||
}
|
||||
//
|
||||
int rainTotal(int hours)
|
||||
{
|
||||
int total = 0;
|
||||
for ( int i = 0; i <= hours; i++)
|
||||
{
|
||||
total += rainBucket [i];
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
void updateSerialData(int x)
|
||||
{
|
||||
DEBUG_PRINT(F("Rain last "));
|
||||
DEBUG_PRINT(x);
|
||||
DEBUG_PRINTLN(F(" hours: "));
|
||||
float tipCount = 0;
|
||||
for (int i = 0; i < x; i++)
|
||||
{
|
||||
tipCount = tipCount + rainBucket [i];
|
||||
}
|
||||
tipCount = tipCount / 100;
|
||||
DEBUG_PRINTLN(tipCount);
|
||||
}
|
||||
|
||||
void loadRainArray(int value) // retrieve stored rain array from EEPROM on powerup
|
||||
{
|
||||
for (int i = 0; i < RAIN_BUCKET_SIZE; i++)
|
||||
{
|
||||
value = value - 2;
|
||||
if (value < EEPROM_BUFFER_LOCATION)
|
||||
{
|
||||
value = EEPROM_BUFFER_LOCATION + E_BUFFER_LENGTH;
|
||||
}
|
||||
DEBUG_PRINT(F("EEPROM location: "));
|
||||
DEBUG_PRINTLN(value);
|
||||
byte rainValueHigh = loadState(value);
|
||||
byte rainValueLow = loadState(value + 1);
|
||||
unsigned int rainValue = rainValueHigh << 8;
|
||||
rainValue |= rainValueLow;
|
||||
rainBucket[i + 1] = rainValue;
|
||||
//
|
||||
DEBUG_PRINT(F("rainBucket[ value: "));
|
||||
DEBUG_PRINT(i + 1);
|
||||
DEBUG_PRINT(F("] value: "));
|
||||
DEBUG_PRINTLN(rainBucket[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
void transmitRainData(void)
|
||||
{
|
||||
DEBUG_PRINT(F("In transmitRainData. currentHour = "));
|
||||
DEBUG_PRINTLN(currentHour);
|
||||
int rainUpdateTotal = 0;
|
||||
for (int i = currentHour; i >= 0; i--)
|
||||
{
|
||||
rainUpdateTotal += rainBucket[i];
|
||||
DEBUG_PRINT(F("Adding rainBucket["));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F("] to rainUpdateTotal."));
|
||||
}
|
||||
DEBUG_PRINT(F("TX Day 1: rainUpdateTotal = "));
|
||||
DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
|
||||
send(msgRainVAR1.set((float)rainUpdateTotal / 100.0, 1)); //Send current day rain totals (resets at midnight)
|
||||
wait(DWELL_TIME);
|
||||
#ifdef USE_DAILY
|
||||
rainUpdateTotal = 0;
|
||||
#endif
|
||||
for (int i = currentHour + 24; i > currentHour; i--)
|
||||
{
|
||||
rainUpdateTotal += rainBucket[i];
|
||||
DEBUG_PRINT(F("Adding rainBucket["));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F("] to rainUpdateTotal."));
|
||||
}
|
||||
DEBUG_PRINT(F("TX Day 2: rainUpdateTotal = "));
|
||||
DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
|
||||
send(msgRainVAR2.set((float)rainUpdateTotal / 100.0, 1));
|
||||
wait(DWELL_TIME);
|
||||
#ifdef USE_DAILY
|
||||
rainUpdateTotal = 0;
|
||||
#endif
|
||||
for (int i = currentHour + 48; i > currentHour + 24; i--)
|
||||
{
|
||||
rainUpdateTotal += rainBucket[i];
|
||||
DEBUG_PRINT(F("Adding rainBucket["));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F("] to rainUpdateTotal."));
|
||||
}
|
||||
DEBUG_PRINT(F("TX Day 3: rainUpdateTotal = "));
|
||||
DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
|
||||
send(msgRainVAR3.set((float)rainUpdateTotal / 100.0, 1));
|
||||
wait(DWELL_TIME);
|
||||
#ifdef USE_DAILY
|
||||
rainUpdateTotal = 0;
|
||||
#endif
|
||||
for (int i = currentHour + 72; i > currentHour + 48; i--)
|
||||
{
|
||||
rainUpdateTotal += rainBucket[i];
|
||||
DEBUG_PRINT(F("Adding rainBucket["));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F("] to rainUpdateTotal."));
|
||||
}
|
||||
DEBUG_PRINT(F("TX Day 4: rainUpdateTotal = "));
|
||||
DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
|
||||
send(msgRainVAR4.set((float)rainUpdateTotal / 100.0, 1));
|
||||
wait(DWELL_TIME);
|
||||
#ifdef USE_DAILY
|
||||
rainUpdateTotal = 0;
|
||||
#endif
|
||||
for (int i = currentHour + 96; i > currentHour + 72; i--)
|
||||
{
|
||||
rainUpdateTotal += rainBucket[i];
|
||||
DEBUG_PRINT(F("Adding rainBucket["));
|
||||
DEBUG_PRINT(i);
|
||||
DEBUG_PRINTLN(F("] to rainUpdateTotal."));
|
||||
}
|
||||
DEBUG_PRINT(F("TX Day 5: rainUpdateTotal = "));
|
||||
DEBUG_PRINTLN((float)rainUpdateTotal / 100.0);
|
||||
send(msgRainVAR5.set((float)rainUpdateTotal / 100.0, 1));
|
||||
wait(DWELL_TIME);
|
||||
}
|
||||
|
||||
void getVariables(const MyMessage &message)
|
||||
{
|
||||
if (message.sensor == CHILD_ID_RAIN_LOG)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
else if (message.sensor == CHILD_ID_TRIPPED_INDICATOR)
|
||||
{
|
||||
if (message.type == V_VAR1)
|
||||
{
|
||||
rainWindow = atoi(message.data);
|
||||
if (rainWindow > 120)
|
||||
{
|
||||
rainWindow = 120;
|
||||
}
|
||||
else if (rainWindow < 1)
|
||||
{
|
||||
rainWindow = 1;
|
||||
}
|
||||
if (rainWindow != atoi(message.data)) // if I changed the value back inside the boundries, push that number back to Vera
|
||||
{
|
||||
send(msgTrippedVar1.set(rainWindow));
|
||||
}
|
||||
}
|
||||
else if (message.type == V_VAR2)
|
||||
{
|
||||
rainSensorThreshold = atoi(message.data);
|
||||
if (rainSensorThreshold > 10000)
|
||||
{
|
||||
rainSensorThreshold = 10000;
|
||||
}
|
||||
else if (rainSensorThreshold < 1)
|
||||
{
|
||||
rainSensorThreshold = 1;
|
||||
}
|
||||
if (rainSensorThreshold != atoi(message.data)) // if I changed the value back inside the boundries, push that number back to Vera
|
||||
{
|
||||
send(msgTrippedVar2.set(rainSensorThreshold));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void prettyFade(void)
|
||||
{
|
||||
float val = (exp(sin(millis() / 2000.0 * PI)) - 0.36787944) * 108.0;
|
||||
analogWrite(ledPin, val);
|
||||
}
|
||||
|
||||
void slowFlash(void)
|
||||
{
|
||||
static boolean ledState = true;
|
||||
static unsigned long pulseStart = millis();
|
||||
if (millis() - pulseStart < 100UL)
|
||||
{
|
||||
digitalWrite(ledPin, !ledState);
|
||||
pulseStart = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void receiveTime(unsigned long time)
|
||||
{
|
||||
DEBUG_PRINTLN(F("Time received..."));
|
||||
setTime(time);
|
||||
char theTime[6];
|
||||
sprintf(theTime, "%d:%2d", hour(), minute());
|
||||
DEBUG_PRINTLN(theTime);
|
||||
}
|
||||
-142
@@ -1,142 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Example sketch showing how to request time from controller which is stored in RTC module
|
||||
* The time and temperature (DS3231/DS3232) is shown on an attached Crystal LCD display
|
||||
*
|
||||
*
|
||||
* Wiring (radio wiring on www.mysensors.org)
|
||||
* ------------------------------------
|
||||
* Arduino RTC-Module I2C Display
|
||||
* ------------------------------------
|
||||
* GND GND GND
|
||||
* +5V VCC VCC
|
||||
* A4 SDA SDA
|
||||
* A5 SCL SCL
|
||||
*
|
||||
* http://www.mysensors.org/build/display
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <Time.h>
|
||||
#include <DS3232RTC.h> // A DS3231/DS3232 library
|
||||
#include <Wire.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
boolean timeReceived = false;
|
||||
unsigned long lastUpdate=0, lastRequest=0;
|
||||
|
||||
// Initialize display. Google the correct settings for your display.
|
||||
// The follwoing setting should work for the recommended display in the MySensors "shop".
|
||||
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("RTC Clock", "1.0");
|
||||
|
||||
// the function to get the time from the RTC
|
||||
setSyncProvider(RTC.get);
|
||||
|
||||
// Request latest time from controller at startup
|
||||
requestTime(receiveTime);
|
||||
|
||||
// initialize the lcd for 16 chars 2 lines and turn on backlight
|
||||
lcd.begin(16,2);
|
||||
}
|
||||
|
||||
// This is called when a new time value was received
|
||||
void receiveTime(unsigned long controllerTime) {
|
||||
// Ok, set incoming time
|
||||
Serial.print("Time value received: ");
|
||||
Serial.println(controllerTime);
|
||||
RTC.set(controllerTime); // this sets the RTC to the time from controller - which we do want periodically
|
||||
timeReceived = true;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long now = millis();
|
||||
|
||||
// If no time has been received yet, request it every 10 second from controller
|
||||
// When time has been received, request update every hour
|
||||
if ((!timeReceived && (now-lastRequest) > (10UL*1000UL))
|
||||
|| (timeReceived && (now-lastRequest) > (60UL*1000UL*60UL))) {
|
||||
// Request time from controller.
|
||||
Serial.println("requesting time");
|
||||
requestTime(receiveTime);
|
||||
lastRequest = now;
|
||||
}
|
||||
|
||||
// Update display every second
|
||||
if (now-lastUpdate > 1000) {
|
||||
updateDisplay();
|
||||
lastUpdate = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void updateDisplay(){
|
||||
tmElements_t tm;
|
||||
RTC.read(tm);
|
||||
|
||||
// Print date and time
|
||||
lcd.home();
|
||||
lcd.print(tm.Day);
|
||||
lcd.print("/");
|
||||
lcd.print(tm.Month);
|
||||
// lcd.print(" ");
|
||||
// lcd.print(tmYearToCalendar(tm.Year)-2000);
|
||||
|
||||
lcd.print(" ");
|
||||
printDigits(tm.Hour);
|
||||
lcd.print(":");
|
||||
printDigits(tm.Minute);
|
||||
lcd.print(":");
|
||||
printDigits(tm.Second);
|
||||
|
||||
// Go to next line and print temperature
|
||||
lcd.setCursor ( 0, 1 );
|
||||
lcd.print("Temp: ");
|
||||
lcd.print(RTC.temperature()/4);
|
||||
lcd.write(223); // Degree-sign
|
||||
lcd.print("C");
|
||||
}
|
||||
|
||||
|
||||
void printDigits(int digits){
|
||||
if(digits < 10)
|
||||
lcd.print('0');
|
||||
lcd.print(digits);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Example sketch showing how to control physical relays.
|
||||
* This example will remember relay state after power failure.
|
||||
* http://www.mysensors.org/build/relay
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
// Enable repeater functionality for this node
|
||||
#define MY_REPEATER_FEATURE
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define RELAY_1 3 // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
|
||||
#define NUMBER_OF_RELAYS 1 // Total number of attached relays
|
||||
#define RELAY_ON 1 // GPIO value to write to turn on attached relay
|
||||
#define RELAY_OFF 0 // GPIO value to write to turn off attached relay
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Initialize library and add callback for incoming messages
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Relay", "1.0");
|
||||
|
||||
// Fetch relay status
|
||||
for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) {
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
present(sensor, S_LIGHT);
|
||||
// Then set relay pins in output mode
|
||||
pinMode(pin, OUTPUT);
|
||||
// Set relay to last known state (using eeprom storage)
|
||||
digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
// We only expect one type of message from controller. But we better check anyway.
|
||||
if (message.type==V_LIGHT) {
|
||||
// Change relay state
|
||||
digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
|
||||
// Store state in eeprom
|
||||
saveState(message.sensor, message.getBool());
|
||||
// Write some debug info
|
||||
Serial.print("Incoming change for sensor:");
|
||||
Serial.print(message.sensor);
|
||||
Serial.print(", New status: ");
|
||||
Serial.println(message.getBool());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Example sketch for a "light switch" where you can control light or something
|
||||
* else from both HA controller and a local physical button
|
||||
* (connected between digital pin 3 and GND).
|
||||
* This node also works as a repeader for other nodes
|
||||
* http://www.mysensors.org/build/relay
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
// Enabled repeater feature for this node
|
||||
#define MY_REPEATER_FEATURE
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <Bounce2.h>
|
||||
|
||||
#define RELAY_PIN 4 // Arduino Digital I/O pin number for relay
|
||||
#define BUTTON_PIN 3 // Arduino Digital I/O pin number for button
|
||||
#define CHILD_ID 1 // Id of the sensor child
|
||||
#define RELAY_ON 1
|
||||
#define RELAY_OFF 0
|
||||
|
||||
Bounce debouncer = Bounce();
|
||||
int oldValue=0;
|
||||
bool state;
|
||||
|
||||
MyMessage msg(CHILD_ID,V_LIGHT);
|
||||
|
||||
void setup()
|
||||
{
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Relay & Button", "1.0");
|
||||
|
||||
// Setup the button
|
||||
pinMode(BUTTON_PIN,INPUT);
|
||||
// Activate internal pull-up
|
||||
digitalWrite(BUTTON_PIN,HIGH);
|
||||
|
||||
// After setting up the button, setup debouncer
|
||||
debouncer.attach(BUTTON_PIN);
|
||||
debouncer.interval(5);
|
||||
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
present(CHILD_ID, S_LIGHT);
|
||||
|
||||
// Make sure relays are off when starting up
|
||||
digitalWrite(RELAY_PIN, RELAY_OFF);
|
||||
// Then set relay pins in output mode
|
||||
pinMode(RELAY_PIN, OUTPUT);
|
||||
|
||||
// Set relay to last known state (using eeprom storage)
|
||||
state = loadState(CHILD_ID);
|
||||
digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Example on how to asynchronously check for new messages from gw
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
debouncer.update();
|
||||
// Get the update value
|
||||
int value = debouncer.read();
|
||||
if (value != oldValue && value==0) {
|
||||
send(msg.set(state?false:true), true); // Send new state and request ack back
|
||||
}
|
||||
oldValue = value;
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
// We only expect one type of message from controller. But we better check anyway.
|
||||
if (message.isAck()) {
|
||||
Serial.println("This is an ack from gateway");
|
||||
}
|
||||
|
||||
if (message.type == V_LIGHT) {
|
||||
// Change relay state
|
||||
state = message.getBool();
|
||||
digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
|
||||
// Store state in eeprom
|
||||
saveState(CHILD_ID, state);
|
||||
|
||||
// Write some debug info
|
||||
Serial.print("Incoming change for sensor:");
|
||||
Serial.print(message.sensor);
|
||||
Serial.print(", New status: ");
|
||||
Serial.println(message.getBool());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Example sketch showing how to create a node thay repeates messages
|
||||
* from nodes far from gateway back to gateway.
|
||||
* It is important that nodes that has enabled repeater mode calls
|
||||
* process() frequently. Repeaters should never sleep.
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
// Enabled repeater feature for this node
|
||||
#define MY_REPEATER_FEATURE
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
//Send the sensor node sketch version information to the gateway
|
||||
sendSketchInfo("Repeater Node", "1.0");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,379 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Secret Knock Sensor
|
||||
* http://www.mysensors.org/build/knock
|
||||
*
|
||||
* See original instructions here (note: The MySensors adopted code might differ in wiring. The instructions below is correct):
|
||||
* https://learn.adafruit.com/secret-knock-activated-drawer-lock/
|
||||
* Version 13.10.31 Built with Arduino IDE 1.0.5
|
||||
*
|
||||
* By Steve Hoefer http://grathio.com
|
||||
* Adapted to MySensors by Henrik Ekblad
|
||||
*
|
||||
* Licensed under Creative Commons Attribution-Noncommercial-Share Alike 3.0
|
||||
* http://creativecommons.org/licenses/by-nc-sa/3.0/us/
|
||||
* (In short: Do what you want, as long as you credit me, don't relicense it, and don't sell it or use it in anything you sell without contacting me.)
|
||||
*
|
||||
* ------Wiring------
|
||||
* Pin 0: Program button used for recording a new Knock (connect Pin0 -> button -> GND)
|
||||
* Pin 1: Optional: Connect LED here (remember resisor in series)
|
||||
* Pin 2: Optional: Piezo element (for beeps).
|
||||
* Pin 5: A sound sensor (digital output) for sensing knocks. See MySensors purchase guide. I used this: http://rover.ebay.com/rover/1/711-53200-19255-0/1?icep_ff3=2&pub=5575069610&toolid=10001&campid=5337433187&customid=&icep_item=200941260251&ipn=psmain&icep_vectorid=229466&kwid=902099&mtid=824&kw=lg
|
||||
* Pin 4: Connects to either 1. Relay which open door or lock or
|
||||
* 2. transistor that opens a solenoid lock when HIGH (see adafruit guide for this option).
|
||||
*
|
||||
*
|
||||
* Connect radio according as usual(you can skip IRQ pin)
|
||||
* http://www.mysensors.org/build/connect_radio
|
||||
*/
|
||||
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
|
||||
#define CHILD_ID 99 // Id of the sensor child
|
||||
|
||||
const byte eepromValid = 121; // If the first byte in eeprom is this then the data is valid.
|
||||
|
||||
/*Pin definitions*/
|
||||
const int programButton = 0; // (Digital 0) Record A New Knock button.
|
||||
const int ledPin = 1; // (Digital 1) The LED pin (if any)
|
||||
const int knockSensor = 5; // (Digital 5) for using the microphone digital output (tune knob to register knock)
|
||||
const int audioOut = 2; // (Digital 2) for using the peizo as an output device. (Thing that goes beep.)
|
||||
const int lockPin = 4; // (Digital 4) The pin that activates the relay/solenoid lock.
|
||||
|
||||
/*Tuning constants. Changing the values below changes the behavior of the device.*/
|
||||
int threshold = 3; // Minimum signal from the piezo to register as a knock. Higher = less sensitive. Typical values 1 - 10
|
||||
const int rejectValue = 25; // If an individual knock is off by this percentage of a knock we don't unlock. Typical values 10-30
|
||||
const int averageRejectValue = 15; // If the average timing of all the knocks is off by this percent we don't unlock. Typical values 5-20
|
||||
const int knockFadeTime = 150; // Milliseconds we allow a knock to fade before we listen for another one. (Debounce timer.)
|
||||
const int lockOperateTime = 2500; // Milliseconds that we operate the lock solenoid latch before releasing it.
|
||||
const int maximumKnocks = 20; // Maximum number of knocks to listen for.
|
||||
const int knockComplete = 1200; // Longest time to wait for a knock before we assume that it's finished. (milliseconds)
|
||||
|
||||
byte secretCode[maximumKnocks] = {50, 25, 25, 50, 100, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Initial setup: "Shave and a Hair Cut, two bits."
|
||||
int knockReadings[maximumKnocks]; // When someone knocks this array fills with the delays between knocks.
|
||||
int knockSensorValue = 0; // Last reading of the knock sensor.
|
||||
boolean programModeActive = false; // True if we're trying to program a new knock.
|
||||
|
||||
bool lockStatus;
|
||||
|
||||
MyMessage lockMsg(CHILD_ID, V_LOCK_STATUS);
|
||||
|
||||
void setup() {
|
||||
|
||||
pinMode(ledPin, OUTPUT);
|
||||
pinMode(knockSensor, INPUT);
|
||||
pinMode(lockPin, OUTPUT);
|
||||
pinMode(programButton, INPUT);
|
||||
digitalWrite(programButton, HIGH); // Enable internal pull up
|
||||
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
sendSketchInfo("Secret Knock", "1.0");
|
||||
present(CHILD_ID, S_LOCK);
|
||||
|
||||
readSecretKnock(); // Load the secret knock (if any) from EEPROM.
|
||||
|
||||
digitalWrite(lockPin, HIGH); // Unlock the door for a bit when we power up. For system check and to allow a way in if the key is forgotten
|
||||
delay(500); // Wait a short time
|
||||
|
||||
lockStatus = loadState(0); // Read last lock status from eeprom
|
||||
setLockState(lockStatus, true); // Now set the last known state and send it to controller
|
||||
|
||||
delay(500); // This delay is here because the solenoid lock returning to place can otherwise trigger and inadvertent knock.
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Listen for any knock at all.
|
||||
knockSensorValue = digitalRead(knockSensor);
|
||||
if (digitalRead(programButton) == LOW){ // is the program button pressed?
|
||||
delay(100); // Cheap debounce.
|
||||
if (digitalRead(programButton) == LOW){
|
||||
if (programModeActive == false){ // If we're not in programming mode, turn it on.
|
||||
programModeActive = true; // Remember we're in programming mode.
|
||||
digitalWrite(ledPin, HIGH); // Turn on the red light too so the user knows we're programming.
|
||||
chirp(500, 1500); // And play a tone in case the user can't see the LED.
|
||||
chirp(500, 1000);
|
||||
} else { // If we are in programing mode, turn it off.
|
||||
programModeActive = false;
|
||||
digitalWrite(ledPin, LOW);
|
||||
chirp(500, 1000); // Turn off the programming LED and play a sad note.
|
||||
chirp(500, 1500);
|
||||
delay(500);
|
||||
}
|
||||
while (digitalRead(programButton) == LOW){
|
||||
delay(10); // Hang around until the button is released.
|
||||
}
|
||||
}
|
||||
delay(250); // Another cheap debounce. Longer because releasing the button can sometimes be sensed as a knock.
|
||||
}
|
||||
|
||||
|
||||
if (knockSensorValue == 0) {
|
||||
if (programModeActive == true){ // Blink the LED when we sense a knock.
|
||||
digitalWrite(ledPin, LOW);
|
||||
} else {
|
||||
digitalWrite(ledPin, HIGH);
|
||||
}
|
||||
knockDelay();
|
||||
if (programModeActive == true){ // Un-blink the LED.
|
||||
digitalWrite(ledPin, HIGH);
|
||||
} else {
|
||||
digitalWrite(ledPin, LOW);
|
||||
}
|
||||
listenToSecretKnock(); // We have our first knock. Go and see what other knocks are in store...
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Records the timing of knocks.
|
||||
void listenToSecretKnock(){
|
||||
int i = 0;
|
||||
// First reset the listening array.
|
||||
for (i=0; i < maximumKnocks; i++){
|
||||
knockReadings[i] = 0;
|
||||
}
|
||||
|
||||
int currentKnockNumber = 0; // Position counter for the array.
|
||||
int startTime = millis(); // Reference for when this knock started.
|
||||
int now = millis();
|
||||
|
||||
do { // Listen for the next knock or wait for it to timeout.
|
||||
knockSensorValue = digitalRead(knockSensor);
|
||||
|
||||
if (knockSensorValue == 0){ // Here's another knock. Save the time between knocks.
|
||||
Serial.println("knock");
|
||||
|
||||
now=millis();
|
||||
knockReadings[currentKnockNumber] = now - startTime;
|
||||
currentKnockNumber ++;
|
||||
startTime = now;
|
||||
|
||||
if (programModeActive==true){ // Blink the LED when we sense a knock.
|
||||
digitalWrite(ledPin, LOW);
|
||||
} else {
|
||||
digitalWrite(ledPin, HIGH);
|
||||
}
|
||||
knockDelay();
|
||||
if (programModeActive == true){ // Un-blink the LED.
|
||||
digitalWrite(ledPin, HIGH);
|
||||
} else {
|
||||
digitalWrite(ledPin, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
now = millis();
|
||||
|
||||
// Stop listening if there are too many knocks or there is too much time between knocks.
|
||||
} while ((now-startTime < knockComplete) && (currentKnockNumber < maximumKnocks));
|
||||
Serial.println("end");
|
||||
|
||||
//we've got our knock recorded, lets see if it's valid
|
||||
if (programModeActive == false){ // Only do this if we're not recording a new knock.
|
||||
if (validateKnock() == true){
|
||||
// Lock/unlock door
|
||||
chirp(500, 1500); // And play a tone in case the user can't see the LED.
|
||||
chirp(500, 1000);
|
||||
setLockState(!lockStatus, true);
|
||||
} else {
|
||||
Serial.println("fail unlock");
|
||||
|
||||
// knock is invalid. Blink the LED as a warning to others.
|
||||
for (i=0; i < 4; i++){
|
||||
digitalWrite(ledPin, HIGH);
|
||||
delay(50);
|
||||
digitalWrite(ledPin, LOW);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
} else { // If we're in programming mode we still validate the lock because it makes some numbers we need, we just don't do anything with the return.
|
||||
validateKnock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Unlocks the door.
|
||||
void setLockState(bool state, bool doSend){
|
||||
if (state)
|
||||
Serial.println("open lock");
|
||||
else
|
||||
Serial.println("close lock");
|
||||
if (doSend)
|
||||
send(lockMsg.set(state));
|
||||
|
||||
digitalWrite(ledPin, state);
|
||||
digitalWrite(lockPin, state);
|
||||
saveState(0,state);
|
||||
lockStatus = state;
|
||||
delay(500); // This delay is here because releasing the latch can cause a vibration that will be sensed as a knock.
|
||||
}
|
||||
|
||||
// Checks to see if our knock matches the secret.
|
||||
// Returns true if it's a good knock, false if it's not.
|
||||
boolean validateKnock(){
|
||||
int i = 0;
|
||||
|
||||
int currentKnockCount = 0;
|
||||
int secretKnockCount = 0;
|
||||
int maxKnockInterval = 0; // We use this later to normalize the times.
|
||||
|
||||
for (i=0;i<maximumKnocks;i++){
|
||||
if (knockReadings[i] > 0){
|
||||
currentKnockCount++;
|
||||
}
|
||||
if (secretCode[i] > 0){
|
||||
secretKnockCount++;
|
||||
}
|
||||
|
||||
if (knockReadings[i] > maxKnockInterval){ // Collect normalization data while we're looping.
|
||||
maxKnockInterval = knockReadings[i];
|
||||
}
|
||||
}
|
||||
|
||||
// If we're recording a new knock, save the info and get out of here.
|
||||
if (programModeActive == true){
|
||||
for (i=0; i < maximumKnocks; i++){ // Normalize the time between knocks. (the longest time = 100)
|
||||
secretCode[i] = map(knockReadings[i], 0, maxKnockInterval, 0, 100);
|
||||
}
|
||||
saveSecretKnock(); // save the result to EEPROM
|
||||
programModeActive = false;
|
||||
playbackKnock(maxKnockInterval);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (currentKnockCount != secretKnockCount){ // Easiest check first. If the number of knocks is wrong, don't unlock.
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Now we compare the relative intervals of our knocks, not the absolute time between them.
|
||||
(ie: if you do the same pattern slow or fast it should still open the door.)
|
||||
This makes it less picky, which while making it less secure can also make it
|
||||
less of a pain to use if you're tempo is a little slow or fast.
|
||||
*/
|
||||
int totaltimeDifferences = 0;
|
||||
int timeDiff = 0;
|
||||
for (i=0; i < maximumKnocks; i++){ // Normalize the times
|
||||
knockReadings[i]= map(knockReadings[i], 0, maxKnockInterval, 0, 100);
|
||||
timeDiff = abs(knockReadings[i] - secretCode[i]);
|
||||
if (timeDiff > rejectValue){ // Individual value too far out of whack. No access for this knock!
|
||||
return false;
|
||||
}
|
||||
totaltimeDifferences += timeDiff;
|
||||
}
|
||||
// It can also fail if the whole thing is too inaccurate.
|
||||
if (totaltimeDifferences / secretKnockCount > averageRejectValue){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// reads the secret knock from EEPROM. (if any.)
|
||||
void readSecretKnock(){
|
||||
byte reading;
|
||||
reading = loadState(1);
|
||||
if (reading == eepromValid){ // only read EEPROM if the signature byte is correct.
|
||||
for (int i=0; i < maximumKnocks ;i++){
|
||||
secretCode[i] = loadState(i+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//saves a new pattern too eeprom
|
||||
void saveSecretKnock(){
|
||||
saveState(1, 0); // clear out the signature. That way we know if we didn't finish the write successfully.
|
||||
for (int i=0; i < maximumKnocks; i++){
|
||||
saveState(i+2, secretCode[i]);
|
||||
}
|
||||
saveState(1, eepromValid); // all good. Write the signature so we'll know it's all good.
|
||||
}
|
||||
|
||||
// Plays back the pattern of the knock in blinks and beeps
|
||||
void playbackKnock(int maxKnockInterval){
|
||||
digitalWrite(ledPin, LOW);
|
||||
delay(1000);
|
||||
digitalWrite(ledPin, HIGH);
|
||||
chirp(200, 1800);
|
||||
for (int i = 0; i < maximumKnocks ; i++){
|
||||
digitalWrite(ledPin, LOW);
|
||||
// only turn it on if there's a delay
|
||||
if (secretCode[i] > 0){
|
||||
delay(map(secretCode[i], 0, 100, 0, maxKnockInterval)); // Expand the time back out to what it was. Roughly.
|
||||
digitalWrite(ledPin, HIGH);
|
||||
chirp(200, 1800);
|
||||
}
|
||||
}
|
||||
digitalWrite(ledPin, LOW);
|
||||
}
|
||||
|
||||
// Deals with the knock delay thingy.
|
||||
void knockDelay(){
|
||||
int itterations = (knockFadeTime / 20); // Wait for the peak to dissipate before listening to next one.
|
||||
for (int i=0; i < itterations; i++){
|
||||
delay(10);
|
||||
analogRead(knockSensor); // This is done in an attempt to defuse the analog sensor's capacitor that will give false readings on high impedance sensors.
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
// Plays a non-musical tone on the piezo.
|
||||
// playTime = milliseconds to play the tone
|
||||
// delayTime = time in microseconds between ticks. (smaller=higher pitch tone.)
|
||||
void chirp(int playTime, int delayTime){
|
||||
long loopTime = (playTime * 1000L) / delayTime;
|
||||
pinMode(audioOut, OUTPUT);
|
||||
for(int i=0; i < loopTime; i++){
|
||||
digitalWrite(audioOut, HIGH);
|
||||
delayMicroseconds(delayTime);
|
||||
digitalWrite(audioOut, LOW);
|
||||
}
|
||||
pinMode(audioOut, INPUT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
// We only expect one type of message from controller. But we better check anyway.
|
||||
if (message.type==V_LOCK_STATUS) {
|
||||
// Change relay state
|
||||
setLockState(message.getBool(), false);
|
||||
|
||||
// Write some debug info
|
||||
Serial.print("Incoming lock status:");
|
||||
Serial.println(message.getBool());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Patrick "Anticimex" Fallberg <patrick@fallberg.net>
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Example sketch showing how to securely control locks.
|
||||
* This example will remember lock state even after power failure.
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
// Select soft/hardware signing method
|
||||
#define MY_SIGNING_SOFT // Software signing enabled
|
||||
//#define MY_SIGNING_ATSHA204 // Hardware signing using ATSHA204A
|
||||
|
||||
// Enable node whitelisting
|
||||
//#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}}
|
||||
// Enable this if you want destination node to sign all messages sent to this node. Default is not to require signing.
|
||||
//#define MY_SIGNING_REQUEST_SIGNATURES
|
||||
|
||||
|
||||
// SETTINGS FOR MY_SIGNING_SOFT
|
||||
// Set the soft_serial value to an arbitrary value for proper security (9 bytes)
|
||||
#define MY_SIGNING_SOFT_SERIAL 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09
|
||||
// Key to use for HMAC calculation in soft signing (32 bytes)
|
||||
#define MY_SIGNING_SOFT_HMAC_KEY 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
|
||||
#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
|
||||
|
||||
// SETTINGS FOR MY_SIGNING_ATSHA204
|
||||
#define MY_SIGNING_ATSHA204_PIN 17 // A3 - pin where ATSHA204 is attached
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
|
||||
#define LOCK_1 3 // Arduino Digital I/O pin number for first lock (second on pin+1 etc)
|
||||
#define NOF_LOCKS 1 // Total number of attached locks
|
||||
#define LOCK_LOCK 1 // GPIO value to write to lock attached lock
|
||||
#define LOCK_UNLOCK 0 // GPIO value to write to unlock attached lock
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Add callback for incoming messages (signing is required)
|
||||
setIncomingCallback(incomingMessage);
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Secure Lock", "1.0");
|
||||
|
||||
// Fetch lock status
|
||||
for (int lock=1, pin=LOCK_1; lock<=NOF_LOCKS;lock++, pin++) {
|
||||
// Register all locks to gw (they will be created as child devices)
|
||||
present(lock, S_LOCK, "SecureActuator", false);
|
||||
// Then set lock pins in output mode
|
||||
pinMode(pin, OUTPUT);
|
||||
// Set lock to last known state (using eeprom storage)
|
||||
digitalWrite(pin, loadState(lock)?LOCK_LOCK:LOCK_UNLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
// We only expect one type of message from controller. But we better check anyway.
|
||||
if (message.type==V_LOCK_STATUS && message.sensor<=NOF_LOCKS) {
|
||||
// Change relay state
|
||||
digitalWrite(message.sensor-1+LOCK_1, message.getBool()?LOCK_LOCK:LOCK_UNLOCK);
|
||||
// Store state in eeprom
|
||||
saveState(message.sensor, message.getBool());
|
||||
// Write some debug info
|
||||
Serial.print("Incoming change for lock:");
|
||||
Serial.print(message.sensor);
|
||||
Serial.print(", New status: ");
|
||||
Serial.println(message.getBool());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
// Sensebender Micro board
|
||||
// Simple blinking FW to test OTA updates
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable repeater feature
|
||||
#define MY_REPEATER_FEATURE
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define SketchName "Sensebender Blink"
|
||||
#define SketchVersion "20150721"
|
||||
#define NODE_ID AUTO
|
||||
#define CHILD_ID_COUNTER 0
|
||||
|
||||
#define LED_PIN A2
|
||||
#define BLINK_INTERVAL 500
|
||||
#define REPORT_TIME 5000L
|
||||
|
||||
unsigned long lastUpdate = 0;
|
||||
boolean LED_STATUS = false;
|
||||
|
||||
MyMessage msgCounter(CHILD_ID_COUNTER, V_VAR1);
|
||||
|
||||
void setup() {
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
digitalWrite(LED_PIN, LED_STATUS);
|
||||
|
||||
sendSketchInfo(SketchName, SketchVersion);
|
||||
|
||||
present(CHILD_ID_COUNTER, S_CUSTOM,"Millis()");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
wait(BLINK_INTERVAL);
|
||||
LED_STATUS ^= true;
|
||||
digitalWrite(LED_PIN, LED_STATUS);
|
||||
|
||||
if (millis()-lastUpdate > REPORT_TIME) {
|
||||
send(msgCounter.set( millis() ));
|
||||
lastUpdate = millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,422 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Thomas Bowman Mørch
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Default sensor sketch for Sensebender Micro module
|
||||
* Act as a temperature / humidity sensor by default.
|
||||
*
|
||||
* If A0 is held low while powering on, it will enter testmode, which verifies all on-board peripherals
|
||||
*
|
||||
* Battery voltage is as battery percentage (Internal message), and optionally as a sensor value (See defines below)
|
||||
*
|
||||
*
|
||||
* Version 1.3 - Thomas Bowman Mørch
|
||||
* Improved transmission logic, eliminating spurious transmissions (when temperatuere / humidity fluctuates 1 up and down between measurements)
|
||||
*
|
||||
* Added OTA boot mode, need to hold A1 low while applying power. (uses slightly more power as it's waiting for bootloader messages)
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
//#define MY_DEBUG
|
||||
|
||||
// Define a static node address, remove if you want auto address assignment
|
||||
//#deine MY_NODE_ID 3
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <Wire.h>
|
||||
#include <SI7021.h>
|
||||
#include "drivers/SPIFlash/SPIFlash.cpp"
|
||||
#include <EEPROM.h>
|
||||
#include <sha204_lib_return_codes.h>
|
||||
#include <sha204_library.h>
|
||||
#include <RunningAverage.h>
|
||||
//#include <avr/power.h>
|
||||
|
||||
// Uncomment the line below, to transmit battery voltage as a normal sensor value
|
||||
//#define BATT_SENSOR 199
|
||||
|
||||
#define RELEASE "1.3"
|
||||
|
||||
#define AVERAGES 2
|
||||
|
||||
// Child sensor ID's
|
||||
#define CHILD_ID_TEMP 1
|
||||
#define CHILD_ID_HUM 2
|
||||
|
||||
// How many milli seconds between each measurement
|
||||
#define MEASURE_INTERVAL 60000
|
||||
|
||||
// How many milli seconds should we wait for OTA?
|
||||
#define OTA_WAIT_PERIOD 300
|
||||
|
||||
// FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller
|
||||
#define FORCE_TRANSMIT_INTERVAL 30
|
||||
|
||||
// When MEASURE_INTERVAL is 60000 and FORCE_TRANSMIT_INTERVAL is 30, we force a transmission every 30 minutes.
|
||||
// Between the forced transmissions a tranmission will only occur if the measured value differs from the previous measurement
|
||||
|
||||
// HUMI_TRANSMIT_THRESHOLD tells how much the humidity should have changed since last time it was transmitted. Likewise with
|
||||
// TEMP_TRANSMIT_THRESHOLD for temperature threshold.
|
||||
#define HUMI_TRANSMIT_THRESHOLD 0.5
|
||||
#define TEMP_TRANSMIT_THRESHOLD 0.5
|
||||
|
||||
// Pin definitions
|
||||
#define TEST_PIN A0
|
||||
#define OTA_ENABLE A1
|
||||
#define LED_PIN A2
|
||||
#define ATSHA204_PIN 17 // A3
|
||||
|
||||
const int sha204Pin = ATSHA204_PIN;
|
||||
atsha204Class sha204(sha204Pin);
|
||||
|
||||
SI7021 humiditySensor;
|
||||
SPIFlash flash(8, 0x1F65);
|
||||
|
||||
// Sensor messages
|
||||
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
|
||||
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
|
||||
|
||||
#ifdef BATT_SENSOR
|
||||
MyMessage msgBatt(BATT_SENSOR, V_VOLTAGE);
|
||||
#endif
|
||||
|
||||
// Global settings
|
||||
int measureCount = 0;
|
||||
int sendBattery = 0;
|
||||
boolean isMetric = true;
|
||||
boolean highfreq = true;
|
||||
boolean ota_enabled = false;
|
||||
boolean transmission_occured = false;
|
||||
|
||||
// Storage of old measurements
|
||||
float lastTemperature = -100;
|
||||
int lastHumidity = -100;
|
||||
long lastBattery = -100;
|
||||
|
||||
RunningAverage raHum(AVERAGES);
|
||||
|
||||
/****************************************************
|
||||
*
|
||||
* Setup code
|
||||
*
|
||||
****************************************************/
|
||||
void setup() {
|
||||
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.print(F("Sensebender Micro FW "));
|
||||
Serial.print(RELEASE);
|
||||
Serial.flush();
|
||||
|
||||
// First check if we should boot into test mode
|
||||
|
||||
pinMode(TEST_PIN,INPUT);
|
||||
digitalWrite(TEST_PIN, HIGH); // Enable pullup
|
||||
if (!digitalRead(TEST_PIN)) testMode();
|
||||
|
||||
pinMode(OTA_ENABLE, INPUT);
|
||||
digitalWrite(OTA_ENABLE, HIGH);
|
||||
if (!digitalRead(OTA_ENABLE)) {
|
||||
ota_enabled = true;
|
||||
}
|
||||
|
||||
// Make sure that ATSHA204 is not floating
|
||||
pinMode(ATSHA204_PIN, INPUT);
|
||||
digitalWrite(ATSHA204_PIN, HIGH);
|
||||
|
||||
digitalWrite(TEST_PIN,LOW);
|
||||
digitalWrite(OTA_ENABLE, LOW); // remove pullup, save some power.
|
||||
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
|
||||
humiditySensor.begin();
|
||||
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
|
||||
Serial.flush();
|
||||
Serial.println(F(" - Online!"));
|
||||
sendSketchInfo("Sensebender Micro", RELEASE);
|
||||
|
||||
present(CHILD_ID_TEMP,S_TEMP);
|
||||
present(CHILD_ID_HUM,S_HUM);
|
||||
|
||||
#ifdef BATT_SENSOR
|
||||
present(BATT_SENSOR, S_POWER);
|
||||
#endif
|
||||
|
||||
|
||||
isMetric = getConfig().isMetric;
|
||||
Serial.print(F("isMetric: ")); Serial.println(isMetric);
|
||||
raHum.clear();
|
||||
sendTempHumidityMeasurements(false);
|
||||
sendBattLevel(false);
|
||||
if (ota_enabled) Serial.println("OTA FW update enabled");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/***********************************************
|
||||
*
|
||||
* Main loop function
|
||||
*
|
||||
***********************************************/
|
||||
void loop() {
|
||||
|
||||
measureCount ++;
|
||||
sendBattery ++;
|
||||
bool forceTransmit = false;
|
||||
transmission_occured = false;
|
||||
if ((measureCount == 5) && highfreq)
|
||||
{
|
||||
if (!ota_enabled) clock_prescale_set(clock_div_8); // Switch to 1Mhz for the reminder of the sketch, save power.
|
||||
highfreq = false;
|
||||
}
|
||||
|
||||
if (measureCount > FORCE_TRANSMIT_INTERVAL) { // force a transmission
|
||||
forceTransmit = true;
|
||||
measureCount = 0;
|
||||
}
|
||||
|
||||
sendTempHumidityMeasurements(forceTransmit);
|
||||
if (sendBattery > 60)
|
||||
{
|
||||
sendBattLevel(forceTransmit); // Not needed to send battery info that often
|
||||
sendBattery = 0;
|
||||
}
|
||||
|
||||
if (ota_enabled & transmission_occured) {
|
||||
wait(OTA_WAIT_PERIOD);
|
||||
}
|
||||
|
||||
sleep(MEASURE_INTERVAL);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************
|
||||
*
|
||||
* Sends temperature and humidity from Si7021 sensor
|
||||
*
|
||||
* Parameters
|
||||
* - force : Forces transmission of a value (even if it's the same as previous measurement)
|
||||
*
|
||||
*********************************************/
|
||||
void sendTempHumidityMeasurements(bool force)
|
||||
{
|
||||
bool tx = force;
|
||||
|
||||
si7021_env data = humiditySensor.getHumidityAndTemperature();
|
||||
|
||||
raHum.addValue(data.humidityPercent);
|
||||
|
||||
float diffTemp = abs(lastTemperature - (isMetric ? data.celsiusHundredths : data.fahrenheitHundredths)/100);
|
||||
float diffHum = abs(lastHumidity - raHum.getAverage());
|
||||
|
||||
Serial.print(F("TempDiff :"));Serial.println(diffTemp);
|
||||
Serial.print(F("HumDiff :"));Serial.println(diffHum);
|
||||
|
||||
if (isnan(diffHum)) tx = true;
|
||||
if (diffTemp > TEMP_TRANSMIT_THRESHOLD) tx = true;
|
||||
if (diffHum > HUMI_TRANSMIT_THRESHOLD) tx = true;
|
||||
|
||||
if (tx) {
|
||||
measureCount = 0;
|
||||
float temperature = (isMetric ? data.celsiusHundredths : data.fahrenheitHundredths) / 100.0;
|
||||
|
||||
int humidity = data.humidityPercent;
|
||||
Serial.print("T: ");Serial.println(temperature);
|
||||
Serial.print("H: ");Serial.println(humidity);
|
||||
|
||||
send(msgTemp.set(temperature,1));
|
||||
send(msgHum.set(humidity));
|
||||
lastTemperature = temperature;
|
||||
lastHumidity = humidity;
|
||||
transmission_occured = true;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************
|
||||
*
|
||||
* Sends battery information (battery percentage)
|
||||
*
|
||||
* Parameters
|
||||
* - force : Forces transmission of a value
|
||||
*
|
||||
*******************************************/
|
||||
void sendBattLevel(bool force)
|
||||
{
|
||||
if (force) lastBattery = -1;
|
||||
long vcc = readVcc();
|
||||
if (vcc != lastBattery) {
|
||||
lastBattery = vcc;
|
||||
|
||||
#ifdef BATT_SENSOR
|
||||
send(msgBatt.set(vcc));
|
||||
#endif
|
||||
|
||||
// Calculate percentage
|
||||
|
||||
vcc = vcc - 1900; // subtract 1.9V from vcc, as this is the lowest voltage we will operate at
|
||||
|
||||
long percent = vcc / 14.0;
|
||||
sendBatteryLevel(percent);
|
||||
transmission_occured = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
*
|
||||
* Internal battery ADC measuring
|
||||
*
|
||||
*******************************************/
|
||||
long readVcc() {
|
||||
// Read 1.1V reference against AVcc
|
||||
// set the reference to Vcc and the measurement to the internal 1.1V reference
|
||||
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
|
||||
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
|
||||
ADMUX = _BV(MUX5) | _BV(MUX0);
|
||||
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
ADcdMUX = _BV(MUX3) | _BV(MUX2);
|
||||
#else
|
||||
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
|
||||
#endif
|
||||
|
||||
delay(2); // Wait for Vref to settle
|
||||
ADCSRA |= _BV(ADSC); // Start conversion
|
||||
while (bit_is_set(ADCSRA,ADSC)); // measuring
|
||||
|
||||
uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
|
||||
uint8_t high = ADCH; // unlocks both
|
||||
|
||||
long result = (high<<8) | low;
|
||||
|
||||
result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
|
||||
return result; // Vcc in millivolts
|
||||
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
*
|
||||
* Verify all peripherals, and signal via the LED if any problems.
|
||||
*
|
||||
****************************************************/
|
||||
void testMode()
|
||||
{
|
||||
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
|
||||
uint8_t ret_code;
|
||||
byte tests = 0;
|
||||
|
||||
digitalWrite(LED_PIN, HIGH); // Turn on LED.
|
||||
Serial.println(F(" - TestMode"));
|
||||
Serial.println(F("Testing peripherals!"));
|
||||
Serial.flush();
|
||||
Serial.print(F("-> SI7021 : "));
|
||||
Serial.flush();
|
||||
|
||||
if (humiditySensor.begin())
|
||||
{
|
||||
Serial.println(F("ok!"));
|
||||
tests ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("failed!"));
|
||||
}
|
||||
Serial.flush();
|
||||
|
||||
Serial.print(F("-> Flash : "));
|
||||
Serial.flush();
|
||||
if (flash.initialize())
|
||||
{
|
||||
Serial.println(F("ok!"));
|
||||
tests ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("failed!"));
|
||||
}
|
||||
Serial.flush();
|
||||
|
||||
|
||||
Serial.print(F("-> SHA204 : "));
|
||||
ret_code = sha204.sha204c_wakeup(rx_buffer);
|
||||
Serial.flush();
|
||||
if (ret_code != SHA204_SUCCESS)
|
||||
{
|
||||
Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX);
|
||||
}
|
||||
Serial.flush();
|
||||
if (ret_code == SHA204_SUCCESS)
|
||||
{
|
||||
ret_code = sha204.getSerialNumber(rx_buffer);
|
||||
if (ret_code != SHA204_SUCCESS)
|
||||
{
|
||||
Serial.print(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("Ok (serial : "));
|
||||
for (int i=0; i<9; i++)
|
||||
{
|
||||
if (rx_buffer[i] < 0x10)
|
||||
{
|
||||
Serial.print('0'); // Because Serial.print does not 0-pad HEX
|
||||
}
|
||||
Serial.print(rx_buffer[i], HEX);
|
||||
}
|
||||
Serial.println(")");
|
||||
tests ++;
|
||||
}
|
||||
|
||||
}
|
||||
Serial.flush();
|
||||
|
||||
Serial.println(F("Test finished"));
|
||||
|
||||
if (tests == 3)
|
||||
{
|
||||
Serial.println(F("Selftest ok!"));
|
||||
while (1) // Blink OK pattern!
|
||||
{
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
delay(200);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
delay(200);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(F("----> Selftest failed!"));
|
||||
while (1) // Blink FAILED pattern! Rappidly blinking..
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The ArduinoGateway prints data received from sensors on the serial link.
|
||||
* The gateway accepts input on seral which will be sent out on radio network.
|
||||
*
|
||||
* The GW code is designed for Arduino Nano 328p / 16MHz
|
||||
*
|
||||
* Wire connections (OPTIONAL):
|
||||
* - Inclusion button should be connected between digital pin 3 and GND
|
||||
* - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series
|
||||
*
|
||||
* LEDs (OPTIONAL):
|
||||
* - To use the feature, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h
|
||||
* - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved
|
||||
* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly
|
||||
* - ERR (red) - fast blink on error during transmission error or recieve crc error
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
// Enable serial gateway
|
||||
#define MY_GATEWAY_SERIAL
|
||||
|
||||
// Flash leds on rx/tx/err
|
||||
#define MY_LEDS_BLINKING_FEATURE
|
||||
// Set blinking period
|
||||
#define MY_DEFAULT_LED_BLINK_PERIOD 300
|
||||
|
||||
// Enable inclusion mode
|
||||
#define MY_INCLUSION_MODE_FEATURE
|
||||
// Enable Inclusion mode button on gateway
|
||||
#define MY_INCLUSION_BUTTON_FEATURE
|
||||
// Set inclusion mode duration (in seconds)
|
||||
#define MY_INCLUSION_MODE_DURATION 60
|
||||
// Digital pin used for inclusion mode button
|
||||
#define MY_INCLUSION_MODE_BUTTON_PIN 3
|
||||
|
||||
#define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin
|
||||
#define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin
|
||||
#define MY_DEFAULT_TX_LED_PIN 9 // the PCB, on board LED
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Nothing to do here
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Nothing to do here
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
* Contribution by: Derek Macias
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Example showing how to create an atuator for a servo.
|
||||
* Connect red to +5V, Black or brown to GND and the last cable to Digital pin 3.
|
||||
* The servo consumes much power and should probably have its own powersource.'
|
||||
* The arduino might spontanally restart if too much power is used (happend
|
||||
* to me when servo tried to pass the extreme positions = full load).
|
||||
* http://www.mysensors.org/build/servo
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <Servo.h>
|
||||
|
||||
#define SERVO_DIGITAL_OUT_PIN 3
|
||||
#define SERVO_MIN 0 // Fine tune your servos min. 0-180
|
||||
#define SERVO_MAX 180 // Fine tune your servos max. 0-180
|
||||
#define DETACH_DELAY 900 // Tune this to let your movement finish before detaching the servo
|
||||
#define CHILD_ID 10 // Id of the sensor child
|
||||
|
||||
MyMessage msg(CHILD_ID, V_DIMMER);
|
||||
Servo myservo; // create servo object to control a servo
|
||||
// a maximum of eight servo objects can be created Sensor gw(9,10);
|
||||
unsigned long timeOfLastChange = 0;
|
||||
bool attachedServo = false;
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Attach method for incoming messages
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Servo", "1.0");
|
||||
|
||||
// Register all sensors to gw (they will be created as child devices)
|
||||
present(CHILD_ID, S_COVER);
|
||||
|
||||
// Request last servo state at startup
|
||||
request(CHILD_ID, V_DIMMER);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (attachedServo && millis() - timeOfLastChange > DETACH_DELAY) {
|
||||
myservo.detach();
|
||||
attachedServo = false;
|
||||
}
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
myservo.attach(SERVO_DIGITAL_OUT_PIN);
|
||||
attachedServo = true;
|
||||
if (message.type==V_DIMMER) { // This could be M_ACK_VARIABLE or M_SET_VARIABLE
|
||||
int val = message.getInt();
|
||||
myservo.write(SERVO_MAX + (SERVO_MIN-SERVO_MAX)/100 * val); // sets the servo position 0-180
|
||||
// Write some debug info
|
||||
Serial.print("Servo changed. new state: ");
|
||||
Serial.println(val);
|
||||
} else if (message.type==V_UP) {
|
||||
Serial.println("Servo UP command");
|
||||
myservo.write(SERVO_MIN);
|
||||
send(msg.set(100));
|
||||
} else if (message.type==V_DOWN) {
|
||||
Serial.println("Servo DOWN command");
|
||||
myservo.write(SERVO_MAX);
|
||||
send(msg.set(0));
|
||||
} else if (message.type==V_STOP) {
|
||||
Serial.println("Servo STOP command");
|
||||
myservo.detach();
|
||||
attachedServo = false;
|
||||
|
||||
}
|
||||
timeOfLastChange = millis();
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,186 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Arduino soil moisture based on gypsum sensor/resistive sensor to avoid electric catalyse in soil
|
||||
* Required to interface the sensor: 2 * 4.7kOhm + 2 * 1N4148
|
||||
*
|
||||
* Gypsum sensor and calibration:
|
||||
* DIY: See http://vanderleevineyard.com/1/category/vinduino/1.html
|
||||
* Built: Davis / Watermark 200SS
|
||||
* http://www.cooking-hacks.com/watermark-soil-moisture-sensor?_bksrc=item2item&_bkloc=product
|
||||
* http://www.irrometer.com/pdf/supportmaterial/sensors/voltage-WM-chart.pdf
|
||||
* cb (centibar) http://www.irrometer.com/basics.html
|
||||
* 0-10 Saturated Soil. Occurs for a day or two after irrigation
|
||||
* 10-20 Soil is adequately wet (except coarse sands which are drying out at this range)
|
||||
* 30-60 Usual range to irrigate or water (except heavy clay soils).
|
||||
* 60-100 Usual range to irrigate heavy clay soils
|
||||
* 100-200 Soil is becoming dangerously dry for maximum production. Proceed with caution.
|
||||
*
|
||||
* Connection:
|
||||
* D6, D7: alternative powering to avoid sensor degradation
|
||||
* A0, A1: alternative resistance mesuring
|
||||
*
|
||||
* Based on:
|
||||
* "Vinduino" portable soil moisture sensor code V3.00
|
||||
* Date December 31, 2012
|
||||
* Reinier van der Lee and Theodore Kaskalis
|
||||
* www.vanderleevineyard.com
|
||||
* Contributor: epierre
|
||||
**/
|
||||
|
||||
// Copyright (C) 2015, Reinier van der Lee
|
||||
// www.vanderleevineyard.com
|
||||
|
||||
// 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
|
||||
// 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.
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <math.h> // Conversion equation from resistance to %
|
||||
#include <MySensor.h>
|
||||
|
||||
// Setting up format for reading 3 soil sensors
|
||||
#define NUM_READS 10 // Number of sensor reads for filtering
|
||||
#define CHILD_ID 0
|
||||
|
||||
MyMessage msg(CHILD_ID, V_LEVEL);
|
||||
unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
|
||||
|
||||
long buffer[NUM_READS];
|
||||
int index;
|
||||
|
||||
typedef struct { // Structure to be used in percentage and resistance values matrix to be filtered (have to be in pairs)
|
||||
int moisture;
|
||||
long resistance;
|
||||
} values;
|
||||
|
||||
const long knownResistor = 4700; // Constant value of known resistor in Ohms
|
||||
|
||||
int supplyVoltage; // Measured supply voltage
|
||||
int sensorVoltage; // Measured sensor voltage
|
||||
|
||||
values valueOf[NUM_READS]; // Calculated moisture percentages and resistances to be sorted and filtered
|
||||
|
||||
int i; // Simple index variable
|
||||
|
||||
void setup() {
|
||||
|
||||
sendSketchInfo("Soil Moisture Sensor Reverse Polarity", "1.0");
|
||||
present(CHILD_ID, S_HUM);
|
||||
// initialize the digital pins as an output.
|
||||
// Pin 6,7 is for sensor 1
|
||||
// initialize the digital pin as an output.
|
||||
// Pin 6 is sense resistor voltage supply 1
|
||||
pinMode(6, OUTPUT);
|
||||
|
||||
// initialize the digital pin as an output.
|
||||
// Pin 7 is sense resistor voltage supply 2
|
||||
pinMode(7, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
measure(6,7,1);
|
||||
Serial.print ("\t");
|
||||
Serial.println (average());
|
||||
long read1 = average();
|
||||
|
||||
measure(7,6,0);
|
||||
Serial.print ("\t");
|
||||
Serial.println (average());
|
||||
long read2= average();
|
||||
|
||||
long sensor1 = (read1 + read2)/2;
|
||||
|
||||
Serial.print ("resistance bias =" );
|
||||
Serial.println (read1-read2);
|
||||
Serial.print ("sensor bias compensated value = ");
|
||||
Serial.println (sensor1);
|
||||
Serial.println ();
|
||||
|
||||
//send back the values
|
||||
send(msg.set((long int)ceil(sensor1)));
|
||||
// delay until next measurement (msec)
|
||||
sleep(SLEEP_TIME);
|
||||
}
|
||||
|
||||
void measure (int phase_b, int phase_a, int analog_input)
|
||||
{
|
||||
// read sensor, filter, and calculate resistance value
|
||||
// Noise filter: median filter
|
||||
|
||||
for (i=0; i<NUM_READS; i++) {
|
||||
|
||||
// Read 1 pair of voltage values
|
||||
digitalWrite(phase_a, HIGH); // set the voltage supply on
|
||||
delayMicroseconds(25);
|
||||
supplyVoltage = analogRead(analog_input); // read the supply voltage
|
||||
delayMicroseconds(25);
|
||||
digitalWrite(phase_a, LOW); // set the voltage supply off
|
||||
delay(1);
|
||||
|
||||
digitalWrite(phase_b, HIGH); // set the voltage supply on
|
||||
delayMicroseconds(25);
|
||||
sensorVoltage = analogRead(analog_input); // read the sensor voltage
|
||||
delayMicroseconds(25);
|
||||
digitalWrite(phase_b, LOW); // set the voltage supply off
|
||||
|
||||
// Calculate resistance
|
||||
// the 0.5 add-term is used to round to the nearest integer
|
||||
// Tip: no need to transform 0-1023 voltage value to 0-5 range, due to following fraction
|
||||
long resistance = (knownResistor * (supplyVoltage - sensorVoltage ) / sensorVoltage) ;
|
||||
|
||||
delay(1);
|
||||
addReading(resistance);
|
||||
Serial.print (resistance);
|
||||
Serial.print ("\t");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Averaging algorithm
|
||||
void addReading(long resistance){
|
||||
buffer[index] = resistance;
|
||||
index++;
|
||||
if (index >= NUM_READS) index = 0;
|
||||
}
|
||||
|
||||
long average(){
|
||||
long sum = 0;
|
||||
for (int i = 0; i < NUM_READS; i++){
|
||||
sum += buffer[i];
|
||||
}
|
||||
return (long)(sum / NUM_READS);
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Example sketch showing how to request time from controller.
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <Time.h>
|
||||
|
||||
boolean timeReceived = false;
|
||||
unsigned long lastUpdate=0, lastRequest=0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Clock", "1.0");
|
||||
|
||||
// Request time from controller.
|
||||
requestTime(receiveTime);
|
||||
}
|
||||
|
||||
// This is called when a new time value was received
|
||||
void receiveTime(unsigned long time) {
|
||||
// Ok, set incoming time
|
||||
setTime(time);
|
||||
timeReceived = true;
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long now = millis();
|
||||
|
||||
// If no time has been received yet, request it every 10 second from controller
|
||||
// When time has been received, request update every hour
|
||||
if ((!timeReceived && (now-lastRequest) > (10UL*1000UL))
|
||||
|| (timeReceived && (now-lastRequest) > (60UL*1000UL*60UL))) {
|
||||
// Request time from controller.
|
||||
Serial.println("requesting time");
|
||||
requestTime(receiveTime);
|
||||
lastRequest = now;
|
||||
}
|
||||
|
||||
// Print time every second
|
||||
if (timeReceived && now-lastUpdate > 1000) {
|
||||
Serial.print(hour());
|
||||
printDigits(minute());
|
||||
printDigits(second());
|
||||
Serial.print(" ");
|
||||
Serial.print(day());
|
||||
Serial.print(" ");
|
||||
Serial.print(month());
|
||||
Serial.print(" ");
|
||||
Serial.print(year());
|
||||
Serial.println();
|
||||
lastUpdate = now;
|
||||
}
|
||||
}
|
||||
|
||||
void printDigits(int digits){
|
||||
// utility function for digital clock display: prints preceding colon and leading 0
|
||||
Serial.print(":");
|
||||
if(digits < 10)
|
||||
Serial.print('0');
|
||||
Serial.print(digits);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// SevenSegNumFontPlus.c
|
||||
// Font type : Special (SubSet)
|
||||
// Font size : 32x50 pixels
|
||||
// Memory usage : 2204 bytes
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
const uint8_t ArialNumFontPlus[2204] PROGMEM={
|
||||
0x20,0x32,0x30,0x0B,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0x00,0x1F,0xF8,0x00,0x00,0x7F,0xFE,0x00,0x00,0xFF,0xFF,0x00,0x01,0xFF,0xFF,0x00,0x03,0xF8,0x1F,0x80,0x03,0xF0,0x0F,0xC0,0x07,0xE0,0x07,0xC0,0x07,0xC0,0x03,0xE0,0x0F,0xC0,0x03,0xE0,0x0F,0x80,0x01,0xF0,0x0F,0x80,0x01,0xF0,0x1F,0x80,0x01,0xF0,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF8,0x3F,0x00,0x00,0xFC,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3F,0x00,0x00,0x7C,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF8,0x0F,0x80,0x01,0xF0,0x0F,0x80,0x01,0xF0,0x0F,0x80,0x01,0xF0,0x07,0xC0,0x03,0xE0,0x07,0xC0,0x03,0xE0,0x03,0xE0,0x07,0xC0,0x03,0xF0,0x0F,0xC0,0x01,0xF8,0x1F,0x80,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFE,0x00,0x00,0x7F,0xFC,0x00,0x00,0x1F,0xF8,0x00,0x00,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0 neu
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x03,0xF0,0x00,0x00,0x07,0xF0,0x00,0x00,0x0F,0xF0,0x00,0x00,0x1F,0xF0,0x00,0x00,0x3F,0xF0,0x00,0x00,0x7F,0xF0,0x00,0x01,0xFF,0xF0,0x00,0x03,0xFD,0xF0,0x00,0x0F,0xF1,0xF0,0x00,0x0F,0xE1,0xF0,0x00,0x0F,0x81,0xF0,0x00,0x0F,0x01,0xF0,0x00,0x0C,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //1 neu
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0x00,0x7F,0xFE,0x00,0x01,0xFF,0xFF,0x00,0x03,0xFF,0xFF,0xC0,0x03,0xFF,0xFF,0xE0,0x07,0xE0,0x0F,0xF0,0x0F,0xC0,0x03,0xF0,0x0F,0x80,0x01,0xF0,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF8,0x3E,0x00,0x00,0xF8,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0xF8,0x00,0x00,0x01,0xF8,0x00,0x00,0x03,0xF0,0x00,0x00,0x07,0xF0,0x00,0x00,0x0F,0xE0,0x00,0x00,0x1F,0xC0,0x00,0x00,0x3F,0x80,0x00,0x00,0x7F,0x00,0x00,0x00,0xFE,0x00,0x00,0x01,0xFC,0x00,0x00,0x03,0xF8,0x00,0x00,0x07,0xF0,0x00,0x00,0x0F,0xE0,0x00,0x00,0x1F,0xC0,0x00,0x00,0x3F,0x80,0x00,0x00,0x7F,0x00,0x00,0x00,0xFE,0x00,0x00,0x01,0xFC,0x00,0x00,0x03,0xF8,0x00,0x00,0x07,0xF0,0x00,0x00,0x07,0xE0,0x00,0x00,0x0F,0xC0,0x00,0x00,0x0F,0x80,0x00,0x00,0x1F,0x80,0x00,0x00,0x3F,0xFF,0xFF,0xFC,0x3F,0xFF,0xFF,0xFC,0x7F,0xFF,0xFF,0xFC,0x7F,0xFF,0xFF,0xFC,0x7F,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 2 neu
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0x00,0x3F,0xFC,0x00,0x00,0xFF,0xFE,0x00,0x01,0xFF,0xFF,0x00,0x03,0xFF,0xFF,0x80,0x03,0xE0,0x1F,0xC0,0x07,0xC0,0x0F,0xC0,0x07,0x80,0x07,0xE0,0x0F,0x80,0x03,0xE0,0x0F,0x00,0x03,0xE0,0x0F,0x00,0x03,0xF0,0x0F,0x00,0x01,0xF0,0x00,0x00,0x03,0xF0,0x00,0x00,0x03,0xE0,0x00,0x00,0x03,0xE0,0x00,0x00,0x07,0xE0,0x00,0x00,0x0F,0xC0,0x00,0x00,0x1F,0xC0,0x00,0x00,0x3F,0x80,0x00,0x07,0xFF,0x00,0x00,0x07,0xFF,0x00,0x00,0x07,0xFF,0x00,0x00,0x07,0xFF,0x80,0x00,0x00,0x1F,0xC0,0x00,0x00,0x0F,0xE0,0x00,0x00,0x03,0xE0,0x00,0x00,0x01,0xF0,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x01,0xF8,0x0F,0x80,0x01,0xF8,0x0F,0x80,0x03,0xF0,0x0F,0xC0,0x07,0xF0,0x07,0xE0,0x0F,0xE0,0x03,0xFC,0x3F,0xC0,0x01,0xFF,0xFF,0x80,0x00,0xFF,0xFF,0x00,0x00,0x7F,0xFC,0x00,0x00,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 3 neu
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0xFF,0x00,0x00,0x01,0xFF,0x00,0x00,0x01,0xFF,0x00,0x00,0x03,0xFF,0x00,0x00,0x07,0xDF,0x00,0x00,0x07,0xDF,0x00,0x00,0x0F,0x9F,0x00,0x00,0x0F,0x9F,0x00,0x00,0x1F,0x1F,0x00,0x00,0x3E,0x1F,0x00,0x00,0x7E,0x1F,0x00,0x00,0x7C,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x01,0xF0,0x1F,0x00,0x03,0xE0,0x1F,0x00,0x03,0xE0,0x1F,0x00,0x07,0xC0,0x1F,0x00,0x07,0xC0,0x1F,0x00,0x0F,0x80,0x1F,0x00,0x1F,0x80,0x1F,0x00,0x1F,0x00,0x1F,0x00,0x3E,0x00,0x1F,0x00,0x3F,0xFF,0xFF,0xFC,0x3F,0xFF,0xFF,0xFC,0x3F,0xFF,0xFF,0xFC,0x3F,0xFF,0xFF,0xFC,0x3F,0xFF,0xFF,0xFC,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00, //4 neu
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFF,0xFF,0xF0,0x01,0xFF,0xFF,0xF0,0x01,0xFF,0xFF,0xF0,0x01,0xFF,0xFF,0xF0,0x01,0xFF,0xFF,0xF0,0x03,0xE0,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0xC0,0x00,0x00,0x07,0xC0,0x00,0x00,0x07,0xC0,0x00,0x00,0x07,0xC0,0x00,0x00,0x07,0xC0,0x00,0x00,0x07,0x80,0x00,0x00,0x0F,0x80,0x00,0x00,0x0F,0x80,0xF0,0x00,0x0F,0x8F,0xFE,0x00,0x0F,0xBF,0xFF,0x80,0x0F,0xFF,0xFF,0xC0,0x0F,0xFF,0xFF,0xE0,0x1F,0xFF,0x07,0xF0,0x1F,0xE0,0x03,0xF0,0x1F,0xC0,0x01,0xF8,0x1F,0x00,0x00,0xF8,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x3F,0x00,0x00,0xF8,0x3F,0x00,0x00,0xF8,0x3F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF0,0x1F,0x00,0x01,0xF0,0x1F,0x80,0x03,0xE0,0x0F,0xC0,0x07,0xE0,0x07,0xE0,0x1F,0xC0,0x03,0xFF,0xFF,0x80,0x03,0xFF,0xFF,0x00,0x01,0xFF,0xFE,0x00,0x00,0x7F,0xF8,0x00,0x00,0x0F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 5 neu
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0x00,0x3F,0xFE,0x00,0x00,0xFF,0xFF,0x00,0x01,0xFF,0xFF,0x80,0x03,0xFF,0xFF,0xC0,0x07,0xE0,0x07,0xE0,0x07,0xC0,0x03,0xF0,0x0F,0xC0,0x01,0xF0,0x0F,0x80,0x00,0xF8,0x1F,0x80,0x00,0xF8,0x1F,0x80,0x00,0xF8,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x3F,0x03,0xF0,0x00,0x3F,0x1F,0xFC,0x00,0x3F,0x7F,0xFE,0x00,0x3F,0xFF,0xFF,0x80,0x3F,0xFF,0xFF,0xC0,0x3F,0xF8,0x0F,0xE0,0x3F,0xE0,0x03,0xF0,0x3F,0xE0,0x03,0xF0,0x3F,0xC0,0x01,0xF8,0x3F,0x80,0x00,0xF8,0x3F,0x80,0x00,0xF8,0x3F,0x00,0x00,0x7C,0x3F,0x00,0x00,0x7C,0x3F,0x00,0x00,0x7C,0x3F,0x00,0x00,0x7C,0x3F,0x00,0x00,0x7C,0x3F,0x00,0x00,0x7C,0x1F,0x00,0x00,0x7C,0x1F,0x80,0x00,0x78,0x1F,0x80,0x00,0xF8,0x1F,0x80,0x00,0xF8,0x0F,0x80,0x00,0xF8,0x0F,0xC0,0x01,0xF0,0x07,0xF0,0x03,0xF0,0x03,0xF8,0x0F,0xE0,0x01,0xFF,0xFF,0xC0,0x00,0xFF,0xFF,0x80,0x00,0x7F,0xFF,0x00,0x00,0x1F,0xFC,0x00,0x00,0x03,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 6 neu
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0xFC,0x3F,0xFF,0xFF,0xFC,0x3F,0xFF,0xFF,0xFC,0x3F,0xFF,0xFF,0xFC,0x3F,0xFF,0xFF,0xFC,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0xFC,0x00,0x00,0x01,0xF8,0x00,0x00,0x01,0xF0,0x00,0x00,0x03,0xE0,0x00,0x00,0x03,0xE0,0x00,0x00,0x07,0xC0,0x00,0x00,0x0F,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x01,0xF0,0x00,0x00,0x03,0xE0,0x00,0x00,0x03,0xE0,0x00,0x00,0x03,0xE0,0x00,0x00,0x07,0xC0,0x00,0x00,0x07,0xC0,0x00,0x00,0x0F,0x80,0x00,0x00,0x0F,0x80,0x00,0x00,0x0F,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 7 neu
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0x00,0x7F,0xFE,0x00,0x00,0xFF,0xFF,0x80,0x01,0xFF,0xFF,0x80,0x03,0xF8,0x1F,0xC0,0x07,0xE0,0x07,0xE0,0x07,0xC0,0x03,0xE0,0x0F,0xC0,0x03,0xF0,0x0F,0x80,0x01,0xF0,0x0F,0x80,0x01,0xF0,0x0F,0x80,0x01,0xF0,0x0F,0x80,0x01,0xF0,0x0F,0x80,0x01,0xF0,0x0F,0x80,0x01,0xF0,0x07,0xC0,0x03,0xE0,0x07,0xC0,0x03,0xE0,0x03,0xE0,0x07,0xC0,0x01,0xF0,0x07,0x80,0x00,0xFC,0x3F,0x00,0x00,0x7F,0xFF,0x00,0x00,0x3F,0xFC,0x00,0x00,0x7F,0xFE,0x00,0x00,0xFF,0xFF,0x00,0x03,0xFF,0xFF,0xC0,0x07,0xF0,0x0F,0xE0,0x0F,0xC0,0x03,0xF0,0x0F,0x80,0x01,0xF0,0x1F,0x80,0x01,0xF8,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF8,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x3E,0x00,0x00,0x7C,0x1F,0x00,0x00,0xF8,0x1F,0x00,0x00,0xF8,0x0F,0x80,0x01,0xF0,0x0F,0x80,0x03,0xF0,0x07,0xC0,0x07,0xE0,0x03,0xF0,0x0F,0xC0,0x01,0xFF,0xFF,0x80,0x00,0xFF,0xFF,0x00,0x00,0x3F,0xFC,0x00,0x00,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 8 neu
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0x00,0x3F,0xFC,0x00,0x00,0xFF,0xFF,0x00,0x01,0xFF,0xFF,0x80,0x03,0xFF,0xFF,0xC0,0x03,0xF8,0x1F,0xE0,0x07,0xE0,0x07,0xE0,0x07,0xE0,0x07,0xF0,0x0F,0xC0,0x03,0xF0,0x0F,0xC0,0x03,0xF8,0x1F,0x80,0x01,0xF8,0x1F,0x80,0x01,0xF8,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x80,0x01,0xFC,0x1F,0x80,0x01,0xFC,0x0F,0xC0,0x03,0xFC,0x0F,0xC0,0x03,0xFC,0x07,0xE0,0x07,0xFC,0x07,0xE0,0x07,0xFC,0x03,0xF8,0x1F,0xFC,0x01,0xFF,0xFF,0xFC,0x00,0xFF,0xFF,0xFC,0x00,0xFF,0xFE,0xFC,0x00,0x7F,0xF8,0xFC,0x00,0x1F,0xE0,0xFC,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0xFC,0x00,0x00,0x01,0xF8,0x3F,0x00,0x01,0xF8,0x3F,0x00,0x01,0xF0,0x1F,0x00,0x03,0xF0,0x1F,0x80,0x07,0xE0,0x0F,0xC0,0x0F,0xE0,0x0F,0xE0,0x3F,0xC0,0x07,0xFF,0xFF,0x80,0x03,0xFF,0xFF,0x00,0x01,0xFF,0xFE,0x00,0x00,0xFF,0xF8,0x00,0x00,0x3F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 9 neu
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x01,0xF0,0x00,0x00,0x03,0xF8,0x00,0x00,0x03,0xF8,0x00,0x00,0x03,0xF8,0x00,0x00,0x01,0xF0,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x01,0xF0,0x00,0x00,0x03,0xF8,0x00,0x00,0x03,0xF8,0x00,0x00,0x03,0xF8,0x00,0x00,0x01,0xF0,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // :
|
||||
};
|
||||
-198
@@ -1,198 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
*
|
||||
* DESCRIPTION
|
||||
* http://www.mysensors.org/build/scene_controller
|
||||
* Touch Display Scene Controller build using a touch enabled tft display
|
||||
* attached to a ATMega 2560. This example fetches time from controller and sends
|
||||
* in scene commands to the controller.
|
||||
* Short press sends V_SCENE_ON and long press (>0.5sec) sends V_SCENE_OFF.
|
||||
*
|
||||
* Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
*
|
||||
* This example uses:
|
||||
* UTFT library: http://www.henningkarlsen.com/electronics/library.php?id=51
|
||||
* Convert your own images here: http://www.henningkarlsen.com/electronics/t_imageconverter565.php
|
||||
*
|
||||
* The 3v3 output on the ATMega2560 is especially bad. I had to use a step down
|
||||
* on the 5V output to get solid transmissions.
|
||||
*
|
||||
*
|
||||
* Connect radio
|
||||
* ----------------------------------
|
||||
* Radio Arduino Pin
|
||||
* ----------------------------------
|
||||
* GND GND
|
||||
* 5V -> Step down -> 3V3 (see buying guide for help finding step-down)
|
||||
* SCK 14
|
||||
* MOSI 15
|
||||
* MISO 16
|
||||
* CE 17
|
||||
* CSN 18
|
||||
*
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable soft spi as radio has a hard time sharing spi
|
||||
#define MY_SOFTSPI
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <Time.h>
|
||||
#include <MySensor.h>
|
||||
#include <stdarg.h>
|
||||
#include <UTFT.h>
|
||||
#include <UTouch.h>
|
||||
#include <UTFT_Buttons.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "arial_bold.c"
|
||||
#include "ArialNumFontPlus.c"
|
||||
#include "logo.c"
|
||||
|
||||
#define CHILD_ID 1
|
||||
|
||||
int LONG_PRESS = 500; // Number of millisecons to trinnger scene off for button push
|
||||
int RESEND_DEBOUNCE = 2000; // Number of millisecons interval between sending of same
|
||||
// scene number again.
|
||||
// This is used to avoid unwanted re-trigger when using
|
||||
// a sensetive touch diplay.
|
||||
|
||||
// Add your buttons here. Max is 5 if you still want time at the top.
|
||||
char *buttons[] = {
|
||||
(char *)"Good Morning",
|
||||
(char *)"Clean Up!",
|
||||
(char *)"All Lights Off",
|
||||
(char *)"Music On/Off"
|
||||
};
|
||||
|
||||
const int buttonCount = sizeof(buttons)/sizeof(char *);
|
||||
const int padding = 10;
|
||||
const int topBarHeight = 60;
|
||||
|
||||
MyMessage on(CHILD_ID, V_SCENE_ON);
|
||||
MyMessage off(CHILD_ID, V_SCENE_OFF);
|
||||
|
||||
UTFT myGLCD(ITDB32S,38,39,40,41);
|
||||
UTouch myTouch( 6, 5, 4, 3, 2);
|
||||
UTFT_Buttons myButtons(&myGLCD, &myTouch);
|
||||
boolean timeReceived = false;
|
||||
unsigned long lastTimeUpdate=0, lastRequest=0;
|
||||
char timeBuf[20];
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
myGLCD.InitLCD();
|
||||
myGLCD.clrScr();
|
||||
myGLCD.setFont((uint8_t*)ArialNumFontPlus);
|
||||
myGLCD.setColor(100, 255, 100);
|
||||
myGLCD.setBackColor(0, 0, 0);
|
||||
myGLCD.drawBitmap (0, 0, 60, 60, (unsigned int*)logo);
|
||||
|
||||
myTouch.InitTouch();
|
||||
myTouch.setPrecision(PREC_MEDIUM);
|
||||
|
||||
myButtons.setButtonColors(VGA_WHITE, VGA_GRAY, VGA_WHITE, VGA_RED, VGA_BLUE);
|
||||
myButtons.setTextFont((uint8_t*)arial_bold);
|
||||
int height = (myGLCD.getDisplayYSize()-topBarHeight-(padding*(buttonCount+2)))/buttonCount;
|
||||
|
||||
// Add buttons
|
||||
for (int i=0; i<buttonCount;i++) {
|
||||
int y = topBarHeight + padding+(i*(height+padding));
|
||||
myButtons.addButton( padding, y, myGLCD.getDisplayXSize()-padding*2, height, buttons[i]);
|
||||
}
|
||||
myButtons.drawButtons();
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Scene Ctrl", "1.0");
|
||||
present(CHILD_ID, S_SCENE_CONTROLLER);
|
||||
// Request time from controller.
|
||||
requestTime(receiveTime);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int lastPressedButton = -1;
|
||||
unsigned long lastPressedButtonTime = 0;
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long now = millis();
|
||||
|
||||
if (myTouch.dataAvailable()) {
|
||||
int pressedButton = myButtons.checkButtons();
|
||||
|
||||
if (pressedButton>=0) {
|
||||
bool longPress = millis()-now>(unsigned long)LONG_PRESS;
|
||||
|
||||
if (pressedButton != lastPressedButton || now-lastPressedButtonTime > (unsigned long)RESEND_DEBOUNCE) {
|
||||
if (longPress) {
|
||||
send(off.set(pressedButton));
|
||||
Serial.print("Long pressed: ");
|
||||
} else {
|
||||
send(on.set(pressedButton));
|
||||
Serial.print("Pressed: ");
|
||||
}
|
||||
Serial.println(pressedButton);
|
||||
lastPressedButton = pressedButton;
|
||||
lastPressedButtonTime=now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no time has been received yet, request it every 10 second from controller
|
||||
// When time has been received, request update every hour
|
||||
if ((!timeReceived && now-lastRequest > (unsigned long)10*1000)
|
||||
|| (timeReceived && now-lastRequest > (unsigned long)60*1000*60)) {
|
||||
// Request time from controller.
|
||||
Serial.println("requesting time");
|
||||
requestTime(receiveTime);
|
||||
lastRequest = now;
|
||||
}
|
||||
|
||||
// Update time every second
|
||||
if (timeReceived && now-lastTimeUpdate > 1000) {
|
||||
printTime();
|
||||
lastTimeUpdate = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This is called when a new time value was received
|
||||
void receiveTime(unsigned long time) {
|
||||
// Ok, set incoming time
|
||||
setTime(time);
|
||||
timeReceived = true;
|
||||
}
|
||||
|
||||
void printTime() {
|
||||
sprintf(timeBuf, "%02d:%02d:%02d", hour(), minute(), second());
|
||||
myGLCD.print(timeBuf, 60,7);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
// Ubuntu.c
|
||||
// Font type : Full (95 characters)
|
||||
// Font size : 24x32 pixels
|
||||
// Memory usage : 9124 bytes
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
const uint8_t Ubuntu[9124] PROGMEM={
|
||||
0x18,0x20,0x20,0x5F,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // <space>
|
||||
0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // !
|
||||
0x00,0x00,0x00,0x01,0xC0,0xE0,0x03,0xE1,0xF0,0x03,0xE1,0xF0,0x03,0xE1,0xF0,0x01,0xE0,0xF0,0x00,0xE0,0x70,0x01,0xC0,0xE0,0x03,0xC1,0xE0,0x0F,0x87,0xC0,0x0E,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // "
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x70,0x00,0x38,0x70,0x00,0x70,0xE0,0x00,0x70,0xE0,0x00,0x70,0xE0,0x00,0x70,0xE0,0x0F,0xFF,0xF8,0x0F,0xFF,0xF8,0x0F,0xFF,0xF8,0x00,0xE1,0xC0,0x00,0xE1,0xC0,0x00,0xE1,0xC0,0x01,0xC3,0x80,0x01,0xC3,0x80,0x01,0xC3,0x80,0x0F,0xFF,0xF8,0x0F,0xFF,0xF8,0x0F,0xFF,0xF8,0x03,0x87,0x00,0x03,0x87,0x00,0x03,0x87,0x00,0x03,0x87,0x00,0x07,0x0E,0x00,0x07,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // #
|
||||
0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x7F,0x00,0x01,0xFF,0xC0,0x03,0xFF,0xC0,0x07,0x80,0x80,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x80,0x00,0x03,0xC0,0x00,0x03,0xF8,0x00,0x01,0xFE,0x00,0x00,0x7F,0x80,0x00,0x0F,0xC0,0x00,0x03,0xC0,0x00,0x01,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x02,0x01,0xC0,0x07,0xFF,0xC0,0x07,0xFF,0x80,0x01,0xFE,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x00,0x00, // $
|
||||
0x00,0x00,0x00,0x07,0x80,0x70,0x0F,0xC0,0xE0,0x0C,0xC0,0xE0,0x18,0x61,0xC0,0x18,0x63,0x80,0x18,0x63,0x80,0x18,0x67,0x00,0x18,0x67,0x00,0x18,0x6E,0x00,0x0C,0xDC,0x00,0x0F,0xDC,0x00,0x07,0xB8,0x00,0x00,0x3B,0xC0,0x00,0x77,0xE0,0x00,0x76,0x60,0x00,0xEC,0x30,0x01,0xCC,0x30,0x01,0xCC,0x30,0x03,0x8C,0x30,0x03,0x8C,0x30,0x07,0x0C,0x30,0x0E,0x06,0x60,0x0E,0x07,0xE0,0x1C,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // %
|
||||
0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0xFF,0x00,0x01,0xFF,0x00,0x03,0xC7,0x80,0x03,0x83,0x80,0x03,0x83,0x80,0x03,0x83,0x80,0x03,0x87,0x00,0x01,0xCF,0x00,0x01,0xFE,0x00,0x00,0xFC,0x00,0x01,0xF0,0x70,0x03,0xF8,0x70,0x03,0xBC,0x70,0x07,0x1E,0x60,0x0E,0x0F,0xE0,0x0E,0x07,0xE0,0x0E,0x03,0xC0,0x0E,0x01,0xC0,0x0F,0x03,0xE0,0x07,0x8F,0xE0,0x07,0xFF,0x70,0x03,0xFE,0x70,0x00,0xF8,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // &
|
||||
0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x3C,0x00,0x00,0x1E,0x00,0x00,0x0E,0x00,0x00,0x07,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // '
|
||||
0x00,0x07,0x00,0x00,0x0F,0x80,0x00,0x0F,0x00,0x00,0x1E,0x00,0x00,0x3C,0x00,0x00,0x38,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x38,0x00,0x00,0x3C,0x00,0x00,0x1E,0x00,0x00,0x0F,0x00,0x00,0x07,0x80,0x00,0x03,0x00,0x00,0x01,0x00, // (
|
||||
0x00,0x60,0x00,0x00,0xF0,0x00,0x00,0x78,0x00,0x00,0x3C,0x00,0x00,0x1E,0x00,0x00,0x0E,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x0E,0x00,0x00,0x1E,0x00,0x00,0x3C,0x00,0x00,0x78,0x00,0x00,0xF0,0x00,0x00,0x60,0x00,0x00,0x40,0x00, // )
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x02,0x1C,0x20,0x03,0xC9,0xE0,0x07,0xFF,0xF0,0x01,0xFF,0xC0,0x00,0x1C,0x00,0x00,0x36,0x00,0x00,0x77,0x00,0x00,0xF3,0x80,0x01,0xE3,0xC0,0x00,0xE3,0x80,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // *
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // +
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x1F,0x00,0x00,0x1F,0x00,0x00,0x1F,0x00,0x00,0x0F,0x00,0x00,0x07,0x00,0x00,0x0E,0x00,0x00,0x1C,0x00,0x00,0x78,0x00,0x00,0x70,0x00,0x00,0x00,0x00, // ,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // -
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // .
|
||||
0x00,0x01,0xC0,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x07,0x00,0x00,0x07,0x00,0x00, // /
|
||||
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x01,0xFF,0x00,0x03,0xFF,0x80,0x03,0xC7,0x80,0x07,0x83,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x30,0xE0,0x0E,0x78,0xE0,0x0E,0x78,0xE0,0x0E,0x78,0xE0,0x0E,0x30,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x83,0xC0,0x03,0xC7,0x80,0x03,0xFF,0x80,0x01,0xFF,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x7C,0x00,0x00,0xFC,0x00,0x03,0xFC,0x00,0x07,0x9C,0x00,0x02,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x03,0xFF,0xC0,0x03,0xFF,0xC0,0x03,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 1
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0x03,0xFF,0x00,0x07,0xFF,0x80,0x07,0x87,0xC0,0x02,0x03,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x03,0x80,0x00,0x07,0x80,0x00,0x07,0x00,0x00,0x0E,0x00,0x00,0x1C,0x00,0x00,0x38,0x00,0x00,0x70,0x00,0x00,0xE0,0x00,0x01,0xC0,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x07,0x00,0x00,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 2
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFC,0x00,0x0F,0xFF,0x00,0x0F,0xFF,0x80,0x06,0x07,0x80,0x00,0x03,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x03,0xC0,0x00,0x07,0x80,0x00,0xFF,0x00,0x00,0xFF,0x00,0x00,0xFF,0x80,0x00,0x07,0xC0,0x00,0x01,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x01,0xE0,0x04,0x03,0xC0,0x0F,0xFF,0x80,0x0F,0xFF,0x00,0x03,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 3
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x00,0x0F,0x80,0x00,0x1F,0x80,0x00,0x3F,0x80,0x00,0x3B,0x80,0x00,0x73,0x80,0x00,0xF3,0x80,0x01,0xE3,0x80,0x01,0xC3,0x80,0x03,0x83,0x80,0x03,0x83,0x80,0x07,0x03,0x80,0x0F,0x03,0x80,0x0E,0x03,0x80,0x1E,0x03,0x80,0x1F,0xFF,0xF0,0x1F,0xFF,0xF0,0x1F,0xFF,0xF0,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 4
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFF,0x80,0x03,0xFF,0x80,0x03,0xFF,0x80,0x03,0x00,0x00,0x03,0x00,0x00,0x03,0x00,0x00,0x03,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0xF0,0x00,0x07,0xFE,0x00,0x07,0xFF,0x00,0x00,0x1F,0x80,0x00,0x07,0x80,0x00,0x03,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x03,0xC0,0x0C,0x07,0x80,0x0F,0xFF,0x00,0x0F,0xFE,0x00,0x03,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 5
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x1F,0xC0,0x00,0x7F,0xC0,0x00,0xFC,0x00,0x01,0xE0,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x06,0x7E,0x00,0x0F,0xFF,0x80,0x0F,0xFF,0xC0,0x0F,0x03,0xC0,0x0E,0x01,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x07,0x00,0xE0,0x07,0x01,0xC0,0x07,0xC3,0xC0,0x03,0xFF,0x80,0x01,0xFF,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 6
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x00,0x00,0xE0,0x00,0x01,0xC0,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 7
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x01,0xFF,0x00,0x03,0xFF,0x80,0x03,0xC7,0xC0,0x07,0x03,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x81,0xC0,0x03,0xC3,0x80,0x03,0xF7,0x00,0x01,0xFE,0x00,0x01,0xFF,0x80,0x03,0xCF,0xC0,0x07,0x03,0xC0,0x06,0x01,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0F,0x01,0xE0,0x07,0x83,0xC0,0x07,0xFF,0xC0,0x03,0xFF,0x80,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 8
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x00,0x01,0xFF,0x00,0x03,0xFF,0x80,0x07,0x87,0xC0,0x07,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0F,0x00,0xE0,0x07,0x81,0xE0,0x07,0xFF,0xE0,0x03,0xFF,0xE0,0x00,0xFE,0xE0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x03,0xC0,0x00,0x07,0x80,0x00,0x0F,0x00,0x00,0x7E,0x00,0x07,0xFC,0x00,0x07,0xF8,0x00,0x07,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 9
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // :
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x3C,0x00,0x00,0x1C,0x00,0x00,0x38,0x00,0x00,0x70,0x00,0x01,0xE0,0x00,0x01,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ;
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x01,0xE0,0x00,0x0F,0xE0,0x00,0x3F,0xC0,0x00,0xFE,0x00,0x03,0xF8,0x00,0x0F,0xC0,0x00,0x0F,0x00,0x00,0x0F,0xC0,0x00,0x07,0xF8,0x00,0x00,0xFE,0x00,0x00,0x3F,0xC0,0x00,0x0F,0xE0,0x00,0x01,0xE0,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // <
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // =
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x0F,0x00,0x00,0x0F,0xE0,0x00,0x07,0xF8,0x00,0x00,0xFE,0x00,0x00,0x3F,0x80,0x00,0x07,0xE0,0x00,0x01,0xE0,0x00,0x07,0xE0,0x00,0x3F,0xC0,0x00,0xFE,0x00,0x07,0xF8,0x00,0x0F,0xE0,0x00,0x0F,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // >
|
||||
0x00,0x00,0x00,0x00,0xFE,0x00,0x03,0xFF,0x80,0x03,0xFF,0xC0,0x01,0x03,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x01,0xC0,0x00,0x03,0x80,0x00,0x07,0x00,0x00,0x0E,0x00,0x00,0x1C,0x00,0x00,0x3C,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ?
|
||||
|
||||
0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0xFF,0x80,0x01,0xFF,0xC0,0x01,0xE1,0xE0,0x03,0x80,0xE0,0x03,0x80,0x70,0x07,0x00,0x70,0x07,0x00,0x70,0x07,0x07,0xF0,0x0E,0x1F,0xF0,0x0E,0x3F,0xF0,0x0E,0x3C,0x70,0x0E,0x78,0x70,0x0E,0x70,0x70,0x0E,0x70,0x70,0x0E,0x70,0x70,0x0E,0x70,0x70,0x0E,0x78,0x70,0x0E,0x38,0x70,0x07,0x3F,0xF0,0x07,0x1F,0xF0,0x07,0x07,0xE0,0x07,0x80,0x00,0x03,0xC0,0x00,0x03,0xC0,0x00,0x01,0xF0,0x00,0x00,0xFF,0xC0,0x00,0x7F,0xC0,0x00,0x1F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, // @
|
||||
0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0xFF,0x00,0x00,0xF7,0x00,0x00,0xE7,0x00,0x00,0xE7,0x00,0x01,0xE7,0x80,0x01,0xC3,0x80,0x01,0xC3,0x80,0x03,0xC3,0xC0,0x03,0xC1,0xC0,0x03,0x81,0xC0,0x03,0x81,0xC0,0x07,0x81,0xE0,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x0F,0x00,0xF0,0x0E,0x00,0x70,0x0E,0x00,0x70,0x0E,0x00,0x70,0x1E,0x00,0x78,0x1C,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // A
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFC,0x00,0x0F,0xFF,0x00,0x0F,0xFF,0x80,0x0E,0x07,0xC0,0x0E,0x03,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x03,0x80,0x0E,0x07,0x80,0x0F,0xFF,0x00,0x0F,0xFF,0x00,0x0F,0xFF,0x80,0x0E,0x03,0xC0,0x0E,0x01,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x01,0xE0,0x0E,0x07,0xC0,0x0F,0xFF,0xC0,0x0F,0xFF,0x00,0x0F,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // B
|
||||
0x00,0x00,0x00,0x00,0x3F,0x80,0x00,0x7F,0xE0,0x01,0xFF,0xE0,0x03,0xE0,0x40,0x03,0xC0,0x00,0x07,0x80,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0F,0x00,0x00,0x07,0x00,0x00,0x07,0x80,0x00,0x03,0xC0,0x00,0x03,0xE0,0x40,0x01,0xFF,0xE0,0x00,0xFF,0xE0,0x00,0x3F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // C
|
||||
0x00,0x00,0x00,0x0F,0xF0,0x00,0x0F,0xFE,0x00,0x0F,0xFF,0x00,0x0E,0x0F,0x80,0x0E,0x03,0x80,0x0E,0x03,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x01,0xE0,0x0E,0x01,0xC0,0x0E,0x03,0xC0,0x0E,0x03,0x80,0x0E,0x0F,0x80,0x0F,0xFF,0x00,0x0F,0xFE,0x00,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // D
|
||||
0x00,0x00,0x00,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0xFF,0x80,0x07,0xFF,0x80,0x07,0xFF,0x80,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // E
|
||||
0x00,0x00,0x00,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // F
|
||||
0x00,0x00,0x00,0x00,0x3F,0x80,0x00,0xFF,0xC0,0x01,0xFF,0xE0,0x03,0xE0,0xC0,0x03,0xC0,0x40,0x07,0x80,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0F,0x00,0xE0,0x07,0x00,0xE0,0x07,0x80,0xE0,0x03,0xC0,0xE0,0x03,0xE0,0xE0,0x01,0xFF,0xE0,0x00,0xFF,0xE0,0x00,0x3F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // G
|
||||
0x00,0x00,0x00,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // H
|
||||
0x00,0x00,0x00,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // I
|
||||
0x00,0x00,0x00,0x01,0xFF,0xC0,0x01,0xFF,0xC0,0x01,0xFF,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x04,0x03,0xC0,0x07,0x07,0x80,0x0F,0xFF,0x00,0x07,0xFE,0x00,0x01,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // J
|
||||
0x00,0x00,0x00,0x0E,0x01,0xE0,0x0E,0x03,0xC0,0x0E,0x03,0x80,0x0E,0x07,0x80,0x0E,0x0F,0x00,0x0E,0x0E,0x00,0x0E,0x1C,0x00,0x0E,0x3C,0x00,0x0E,0x78,0x00,0x0E,0xF0,0x00,0x0F,0xE0,0x00,0x0F,0xE0,0x00,0x0F,0xF0,0x00,0x0E,0xF8,0x00,0x0E,0x7C,0x00,0x0E,0x3E,0x00,0x0E,0x1E,0x00,0x0E,0x0F,0x00,0x0E,0x07,0x80,0x0E,0x03,0xC0,0x0E,0x03,0xC0,0x0E,0x01,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // K
|
||||
0x00,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // L
|
||||
0x00,0x00,0x00,0x03,0x00,0x60,0x03,0x80,0xF0,0x07,0x80,0xF0,0x07,0x80,0xF0,0x06,0xC1,0xB0,0x06,0xC1,0xB0,0x06,0xE3,0xB0,0x06,0x63,0x30,0x06,0x63,0x30,0x06,0x77,0x30,0x06,0x36,0x30,0x06,0x36,0x30,0x06,0x3E,0x30,0x06,0x1C,0x38,0x0E,0x1C,0x38,0x0E,0x00,0x38,0x0E,0x00,0x38,0x0E,0x00,0x38,0x0E,0x00,0x38,0x0E,0x00,0x38,0x0E,0x00,0x38,0x0E,0x00,0x38,0x0E,0x00,0x38,0x0E,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // M
|
||||
0x00,0x00,0x00,0x07,0x80,0x70,0x07,0xC0,0x70,0x07,0xC0,0x70,0x07,0xE0,0x70,0x07,0xE0,0x70,0x07,0xF0,0x70,0x07,0x70,0x70,0x07,0x70,0x70,0x07,0x38,0x70,0x07,0x38,0x70,0x07,0x1C,0x70,0x07,0x1C,0x70,0x07,0x0E,0x70,0x07,0x0E,0x70,0x07,0x06,0x70,0x07,0x07,0x70,0x07,0x07,0x70,0x07,0x03,0xF0,0x07,0x03,0xF0,0x07,0x01,0xF0,0x07,0x01,0xF0,0x07,0x00,0xF0,0x07,0x00,0xF0,0x07,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // N
|
||||
0x00,0x00,0x00,0x00,0x7C,0x00,0x01,0xFF,0x00,0x03,0xFF,0x80,0x07,0x83,0xC0,0x0F,0x01,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x1C,0x00,0xF0,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0xF0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0F,0x01,0xE0,0x07,0x83,0xC0,0x03,0xFF,0x80,0x01,0xFF,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // O
|
||||
|
||||
0x00,0x00,0x00,0x07,0xFC,0x00,0x07,0xFF,0x00,0x07,0xFF,0x80,0x07,0x03,0xC0,0x07,0x01,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x01,0xE0,0x07,0x03,0xC0,0x07,0xFF,0x80,0x07,0xFF,0x00,0x07,0xFC,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // P
|
||||
0x00,0x00,0x00,0x00,0x7C,0x00,0x01,0xFF,0x00,0x03,0xFF,0x80,0x07,0x83,0xC0,0x0F,0x01,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x1C,0x00,0xF0,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0xF0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0F,0x01,0xE0,0x07,0x83,0xC0,0x03,0xFF,0x80,0x01,0xFF,0x00,0x00,0xFE,0x00,0x00,0x38,0x00,0x00,0x3C,0x00,0x00,0x1F,0x00,0x00,0x0F,0xE0,0x00,0x07,0xE0,0x00,0x00,0xC0,0x00,0x00,0x00, // Q
|
||||
0x00,0x00,0x00,0x0F,0xF8,0x00,0x0F,0xFE,0x00,0x0F,0xFF,0x00,0x0E,0x07,0x80,0x0E,0x03,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x03,0x80,0x0E,0x07,0x80,0x0F,0xFF,0x00,0x0F,0xFE,0x00,0x0F,0xFC,0x00,0x0E,0x1E,0x00,0x0E,0x0E,0x00,0x0E,0x07,0x00,0x0E,0x07,0x00,0x0E,0x03,0x80,0x0E,0x03,0x80,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // R
|
||||
0x00,0x00,0x00,0x00,0x7F,0x00,0x01,0xFF,0xC0,0x03,0xFF,0xC0,0x03,0xC0,0x80,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x80,0x00,0x03,0xE0,0x00,0x01,0xF8,0x00,0x00,0xFE,0x00,0x00,0x3F,0x80,0x00,0x0F,0xC0,0x00,0x03,0xC0,0x00,0x01,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x04,0x01,0xE0,0x0F,0x03,0xC0,0x0F,0xFF,0xC0,0x07,0xFF,0x80,0x01,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // S
|
||||
0x00,0x00,0x00,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // T
|
||||
0x00,0x00,0x00,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0F,0x01,0xE0,0x07,0x01,0xC0,0x07,0x83,0xC0,0x03,0xFF,0x80,0x01,0xFF,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // U
|
||||
0x00,0x00,0x00,0x1C,0x00,0x70,0x1C,0x00,0x70,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x03,0x83,0x80,0x03,0x83,0x80,0x03,0x83,0x80,0x03,0x87,0x80,0x01,0xC7,0x00,0x01,0xC7,0x00,0x01,0xC7,0x00,0x00,0xEE,0x00,0x00,0xEE,0x00,0x00,0xEE,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // V
|
||||
0x00,0x00,0x00,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x38,0xE0,0x0E,0x38,0xE0,0x0E,0x38,0xE0,0x0E,0x6C,0xE0,0x0E,0x6C,0xE0,0x0E,0x6C,0xE0,0x0E,0xC6,0xE0,0x0E,0xC6,0xE0,0x0E,0xC6,0xE0,0x0F,0x83,0xE0,0x0F,0x83,0xE0,0x0F,0x83,0xE0,0x0F,0x01,0xE0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // W
|
||||
0x00,0x00,0x00,0x1E,0x00,0xF0,0x0E,0x00,0xE0,0x0F,0x01,0xE0,0x07,0x01,0xC0,0x03,0x83,0x80,0x03,0x83,0x80,0x01,0xC7,0x00,0x01,0xEF,0x00,0x00,0xEE,0x00,0x00,0xFE,0x00,0x00,0x7C,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x7C,0x00,0x00,0xFE,0x00,0x00,0xEE,0x00,0x01,0xC7,0x00,0x03,0xC7,0x80,0x03,0x83,0x80,0x07,0x83,0xC0,0x07,0x01,0xC0,0x0F,0x01,0xE0,0x0E,0x00,0xE0,0x1E,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // X
|
||||
0x00,0x00,0x00,0x1C,0x00,0x70,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0F,0x01,0xE0,0x07,0x01,0xC0,0x07,0x83,0xC0,0x03,0x83,0x80,0x03,0xC3,0x80,0x01,0xC7,0x00,0x01,0xEF,0x00,0x00,0xEE,0x00,0x00,0xFE,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Y
|
||||
0x00,0x00,0x00,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x07,0xFF,0xE0,0x00,0x01,0xC0,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x07,0x00,0x00,0x0F,0x00,0x00,0x0E,0x00,0x00,0x1E,0x00,0x00,0x3C,0x00,0x00,0x38,0x00,0x00,0x78,0x00,0x00,0x70,0x00,0x00,0xE0,0x00,0x01,0xE0,0x00,0x01,0xC0,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x07,0x80,0x00,0x07,0x00,0x00,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Z
|
||||
0x01,0xFF,0x00,0x01,0xFF,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xFF,0x00,0x01,0xFF,0x00, // [
|
||||
0x03,0x80,0x00,0x03,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x00,0xE0,0x00,0x00,0xE0, // <backslash>
|
||||
0x00,0xFF,0x80,0x00,0xFF,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0xFF,0x80,0x00,0xFF,0x80, // ]
|
||||
0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0xEE,0x00,0x00,0xEE,0x00,0x01,0xC7,0x00,0x01,0xC7,0x00,0x03,0xC7,0x80,0x03,0x83,0x80,0x07,0x83,0xC0,0x07,0x01,0xC0,0x0F,0x01,0xE0,0x02,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xF8,0x3F,0xFF,0xF8,0x3F,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // _
|
||||
|
||||
0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0xFE,0x00,0x01,0xC7,0x00,0x01,0x83,0x00,0x01,0x83,0x00,0x01,0x83,0x00,0x01,0xC7,0x00,0x00,0xFE,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // `
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x01,0xFF,0x80,0x01,0xFF,0xC0,0x01,0x83,0xE0,0x00,0x01,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x7F,0xE0,0x01,0xFF,0xE0,0x03,0xFF,0xE0,0x07,0xC0,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x80,0xE0,0x03,0xFF,0xE0,0x01,0xFF,0xE0,0x00,0x7F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // a
|
||||
0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x7E,0x00,0x07,0xFF,0x00,0x07,0xFF,0x80,0x07,0x83,0xC0,0x07,0x01,0xC0,0x07,0x01,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x01,0xE0,0x07,0x01,0xC0,0x07,0x07,0xC0,0x07,0xFF,0x80,0x07,0xFF,0x00,0x03,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // b
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xC0,0x00,0xFF,0xE0,0x03,0xFF,0xE0,0x03,0xE0,0x40,0x07,0x80,0x00,0x07,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x0E,0x00,0x00,0x07,0x00,0x00,0x07,0x80,0x00,0x03,0xE0,0x60,0x03,0xFF,0xE0,0x00,0xFF,0xE0,0x00,0x3F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // c
|
||||
0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x7E,0xE0,0x00,0xFF,0xE0,0x01,0xFF,0xE0,0x03,0xC1,0xE0,0x03,0x80,0xE0,0x07,0x80,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x80,0xE0,0x03,0x80,0xE0,0x03,0xE0,0xE0,0x01,0xFF,0xE0,0x00,0xFF,0xE0,0x00,0x3F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x01,0xFF,0x00,0x03,0xFF,0x80,0x07,0xC3,0xC0,0x07,0x01,0xC0,0x07,0x00,0xE0,0x0E,0x00,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0E,0x00,0x00,0x0E,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0xC0,0xC0,0x03,0xFF,0xC0,0x01,0xFF,0xC0,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // e
|
||||
0x00,0x0F,0xC0,0x00,0x3F,0xF0,0x00,0x7F,0xF0,0x00,0x78,0x30,0x00,0xF0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x0F,0xFF,0xC0,0x0F,0xFF,0xC0,0x0F,0xFF,0xC0,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // f
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x01,0xFF,0xC0,0x03,0xFF,0xC0,0x07,0x81,0xC0,0x07,0x01,0xC0,0x0F,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x0E,0x01,0xC0,0x07,0x01,0xC0,0x07,0x83,0xC0,0x03,0xFF,0xC0,0x01,0xFF,0xC0,0x00,0xFD,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x00,0x03,0xC0,0x06,0x07,0x80,0x07,0xFF,0x80,0x07,0xFF,0x00,0x03,0xFC,0x00,0x00,0x00,0x00, // g
|
||||
0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0xFC,0x00,0x07,0xFF,0x00,0x07,0xFF,0x80,0x07,0x07,0x80,0x07,0x03,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // h
|
||||
0x00,0x00,0x00,0x00,0x60,0x00,0x00,0xF0,0x00,0x00,0xF0,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0x0F,0xF0,0x00,0x0F,0xF0,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x70,0x00,0x00,0x78,0x20,0x00,0x3F,0xE0,0x00,0x3F,0xE0,0x00,0x0F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // i
|
||||
0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x0F,0x00,0x00,0x0F,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFF,0x80,0x03,0xFF,0x80,0x03,0xFF,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x06,0x0F,0x00,0x0F,0xFF,0x00,0x0F,0xFE,0x00,0x03,0xF8,0x00, // j
|
||||
0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x01,0xE0,0x07,0x03,0xC0,0x07,0x07,0x80,0x07,0x0F,0x00,0x07,0x1E,0x00,0x07,0x3C,0x00,0x07,0x78,0x00,0x07,0xF0,0x00,0x07,0xE0,0x00,0x07,0xF0,0x00,0x07,0x78,0x00,0x07,0x1C,0x00,0x07,0x0F,0x00,0x07,0x07,0x00,0x07,0x03,0x80,0x07,0x03,0xC0,0x07,0x01,0xE0,0x07,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // k
|
||||
0x07,0xF8,0x00,0x07,0xF8,0x00,0x07,0xF8,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x3C,0x10,0x00,0x1F,0xF0,0x00,0x1F,0xF0,0x00,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // l
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE3,0xC0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0E,0x3C,0xF0,0x0E,0x1C,0x70,0x0E,0x1C,0x70,0x0E,0x1C,0x70,0x0E,0x1C,0x70,0x0E,0x1C,0x70,0x0E,0x1C,0x70,0x0E,0x1C,0x70,0x0E,0x00,0x70,0x0E,0x00,0x70,0x0E,0x00,0x70,0x0E,0x00,0x70,0x0E,0x00,0x70,0x0E,0x00,0x70,0x0E,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // m
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x03,0xFF,0x80,0x03,0xFF,0xC0,0x03,0x83,0xC0,0x03,0x81,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // n
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x01,0xFF,0x00,0x03,0xFF,0x80,0x07,0x83,0xC0,0x07,0x01,0xC0,0x0F,0x01,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x07,0x01,0xE0,0x07,0x01,0xC0,0x07,0x83,0xC0,0x03,0xFF,0x80,0x01,0xFF,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // o
|
||||
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFC,0x00,0x07,0xFF,0x00,0x07,0xFF,0x80,0x07,0x07,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x01,0xE0,0x07,0x01,0xC0,0x07,0x83,0xC0,0x07,0xFF,0x80,0x07,0xFF,0x00,0x07,0x7C,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00, // p
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x80,0x00,0xFF,0xE0,0x01,0xFF,0xE0,0x03,0xE0,0xE0,0x03,0x80,0xE0,0x03,0x80,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x80,0xE0,0x03,0x80,0xE0,0x03,0xC1,0xE0,0x01,0xFF,0xE0,0x00,0xFF,0xE0,0x00,0x3E,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0, // q
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xC0,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x07,0x80,0x80,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // r
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x01,0xFF,0x80,0x03,0xFF,0x80,0x07,0x81,0x80,0x07,0x00,0x00,0x07,0x00,0x00,0x07,0xC0,0x00,0x03,0xF0,0x00,0x01,0xFE,0x00,0x00,0x7F,0x00,0x00,0x1F,0x80,0x00,0x03,0xC0,0x00,0x01,0xC0,0x00,0x01,0xC0,0x06,0x03,0xC0,0x07,0xFF,0x80,0x07,0xFF,0x80,0x01,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // s
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x0F,0xFF,0xE0,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xF0,0x20,0x00,0x7F,0xE0,0x00,0x7F,0xE0,0x00,0x1F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // t
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x81,0xC0,0x03,0xC1,0xC0,0x03,0xFF,0xC0,0x01,0xFF,0xC0,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // u
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x70,0x1E,0x00,0xF0,0x0E,0x00,0xE0,0x0E,0x00,0xE0,0x0F,0x01,0xE0,0x07,0x01,0xC0,0x07,0x01,0xC0,0x07,0x83,0xC0,0x03,0x83,0x80,0x03,0x83,0x80,0x03,0xC7,0x00,0x01,0xC7,0x00,0x01,0xEF,0x00,0x00,0xEE,0x00,0x00,0xFE,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // v
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x00,0x70,0x1C,0x10,0x70,0x0C,0x38,0xE0,0x0E,0x38,0xE0,0x0E,0x38,0xE0,0x0E,0x28,0xE0,0x0E,0x6C,0xE0,0x0E,0x6C,0xE0,0x06,0x44,0xC0,0x06,0xC6,0xC0,0x06,0xC7,0xC0,0x07,0x87,0xC0,0x07,0x83,0xC0,0x07,0x83,0x80,0x03,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // w
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x01,0xE0,0x0F,0x03,0xC0,0x07,0x03,0x80,0x03,0x87,0x80,0x03,0xCF,0x00,0x01,0xEE,0x00,0x00,0xFC,0x00,0x00,0x7C,0x00,0x00,0x78,0x00,0x00,0x7C,0x00,0x00,0xFE,0x00,0x01,0xEE,0x00,0x01,0xC7,0x00,0x03,0xC3,0x80,0x07,0x83,0xC0,0x0F,0x01,0xC0,0x0E,0x01,0xE0,0x1E,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // x
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x70,0x0F,0x00,0xF0,0x07,0x00,0xE0,0x07,0x00,0xE0,0x07,0x80,0xE0,0x03,0x81,0xE0,0x03,0x81,0xC0,0x03,0xC1,0xC0,0x01,0xC3,0xC0,0x01,0xC3,0x80,0x01,0xE3,0x80,0x00,0xE7,0x80,0x00,0xF7,0x80,0x00,0x77,0x00,0x00,0x7F,0x00,0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x1E,0x00,0x00,0x3C,0x00,0x00,0x3C,0x00,0x00,0x78,0x00,0x0F,0xF0,0x00,0x0F,0xF0,0x00,0x0F,0xC0,0x00, // y
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x00,0x03,0x80,0x00,0x07,0x80,0x00,0x0F,0x00,0x00,0x1E,0x00,0x00,0x1C,0x00,0x00,0x38,0x00,0x00,0x78,0x00,0x00,0xF0,0x00,0x00,0xE0,0x00,0x01,0xE0,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x07,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // z
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x01,0xC0,0x00,0x0F,0x80,0x00,0x0F,0x80,0x00,0x01,0xC0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0xE0,0x00,0x00,0x70,0x00,0x00,0x7F,0x80,0x00,0x1F,0x80, // {
|
||||
0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00, // |
|
||||
0x00,0xFC,0x00,0x00,0xFF,0x00,0x00,0x07,0x00,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x01,0xC0,0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x01,0xC0,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x03,0x80,0x00,0x07,0x00,0x00,0xFF,0x00,0x00,0xFC,0x00, // }
|
||||
0x00,0x00,0x00,0x01,0xE0,0x20,0x03,0xF0,0x30,0x07,0xFC,0x70,0x0E,0x3F,0xE0,0x0C,0x0F,0xC0,0x04,0x07,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~
|
||||
};
|
||||
@@ -1,111 +0,0 @@
|
||||
// arial_bold.c
|
||||
// Font type : Full (95 characters)
|
||||
// Font size : 16x16 pixels
|
||||
// Memory usage : 3044 bytes
|
||||
// Submitted by : MBWK
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
const uint8_t arial_bold[3044] PROGMEM={
|
||||
0x10,0x10,0x20,0x5F,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // <space>
|
||||
0x00,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00, // !
|
||||
0x00,0x00,0x00,0x00,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // "
|
||||
0x00,0x00,0x00,0x00,0x03,0x60,0x03,0x60,0x06,0xC0,0x3F,0xF0,0x3F,0xF0,0x06,0xC0,0x0D,0x80,0x3F,0xF0,0x3F,0xF0,0x0D,0x80,0x1B,0x00,0x1B,0x00,0x00,0x00,0x00,0x00, // #
|
||||
0x00,0x00,0x01,0x00,0x03,0x80,0x07,0xC0,0x0D,0x60,0x0D,0x00,0x0F,0x00,0x07,0x80,0x03,0xC0,0x01,0xE0,0x0D,0x60,0x0D,0x60,0x07,0xC0,0x03,0x80,0x01,0x00,0x00,0x00, // $
|
||||
0x00,0x00,0x00,0x00,0x3C,0x18,0x66,0x30,0x66,0x30,0x66,0x60,0x66,0xC0,0x3C,0xC0,0x01,0x9E,0x01,0xB3,0x03,0x33,0x03,0x33,0x06,0x33,0x0C,0x1E,0x00,0x00,0x00,0x00, // %
|
||||
0x00,0x00,0x00,0x00,0x07,0xC0,0x0F,0xE0,0x0C,0x60,0x0C,0x60,0x07,0xC0,0x07,0x80,0x0D,0x90,0x19,0xD8,0x18,0xF0,0x18,0x78,0x0F,0xFC,0x07,0x88,0x00,0x00,0x00,0x00, // &
|
||||
0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // '
|
||||
0x00,0x00,0x01,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x03,0x00,0x03,0x00,0x01,0x80,0x00,0x00,0x00,0x00, // (
|
||||
0x00,0x00,0x06,0x00,0x03,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x00,0x00,0x00,0x00, // )
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x03,0x80,0x33,0x98,0x3F,0xF8,0x07,0xC0,0x07,0xC0,0x0E,0xE0,0x1C,0x70,0x04,0x40,0x00,0x00,0x00,0x00,0x00,0x00, // *
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x07,0xF8,0x07,0xF8,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, // +
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x01,0x00,0x01,0x00,0x02,0x00,0x00,0x00, // ,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,0x03,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // -
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // .
|
||||
0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x60,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00, // /
|
||||
|
||||
0x00,0x00,0x00,0x00,0x03,0xC0,0x07,0xE0,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x07,0xE0,0x03,0xC0,0x00,0x00,0x00,0x00, // 0
|
||||
0x00,0x00,0x00,0x00,0x01,0x80,0x03,0x80,0x07,0x80,0x0D,0x80,0x09,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00, // 1
|
||||
0x00,0x00,0x00,0x00,0x03,0xC0,0x07,0xE0,0x0E,0x30,0x0C,0x30,0x00,0x30,0x00,0x60,0x00,0xE0,0x01,0xC0,0x03,0x80,0x06,0x00,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00, // 2
|
||||
0x00,0x00,0x00,0x00,0x03,0xE0,0x07,0xF0,0x0E,0x30,0x00,0x30,0x01,0xE0,0x01,0xE0,0x00,0x70,0x00,0x30,0x0C,0x30,0x0E,0x70,0x07,0xE0,0x03,0xC0,0x00,0x00,0x00,0x00, // 3
|
||||
0x00,0x00,0x00,0x00,0x00,0x60,0x00,0xE0,0x00,0xE0,0x01,0xE0,0x03,0x60,0x03,0x60,0x06,0x60,0x0C,0x60,0x0F,0xF0,0x0F,0xF0,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00, // 4
|
||||
0x00,0x00,0x00,0x00,0x07,0xE0,0x07,0xE0,0x06,0x00,0x0C,0x00,0x0F,0xC0,0x0F,0xE0,0x0C,0x70,0x00,0x30,0x0C,0x30,0x0E,0x70,0x07,0xE0,0x03,0xC0,0x00,0x00,0x00,0x00, // 5
|
||||
0x00,0x00,0x00,0x00,0x03,0xE0,0x07,0xF0,0x06,0x30,0x0C,0x00,0x0D,0xC0,0x0F,0xE0,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x06,0x30,0x07,0xE0,0x03,0xC0,0x00,0x00,0x00,0x00, // 6
|
||||
0x00,0x00,0x00,0x00,0x0F,0xF0,0x0F,0xF0,0x00,0x60,0x00,0xC0,0x00,0xC0,0x01,0x80,0x01,0x80,0x01,0x80,0x03,0x80,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00, // 7
|
||||
0x00,0x00,0x00,0x00,0x03,0xC0,0x07,0xE0,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x07,0xE0,0x07,0xE0,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x07,0xE0,0x03,0xC0,0x00,0x00,0x00,0x00, // 8
|
||||
0x00,0x00,0x00,0x00,0x03,0xC0,0x07,0xE0,0x0C,0x60,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x07,0xF0,0x03,0xB0,0x00,0x30,0x0C,0x60,0x0F,0xE0,0x07,0xC0,0x00,0x00,0x00,0x00, // 9
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // :
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x00,0x80,0x00,0x80,0x01,0x00,0x00,0x00, // ;
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0xE0,0x03,0xC0,0x0F,0x00,0x1C,0x00,0x0F,0x00,0x03,0xC0,0x00,0xE0,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00, // <
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF0,0x1F,0xF0,0x00,0x00,0x00,0x00,0x1F,0xF0,0x1F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // =
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x0E,0x00,0x07,0x80,0x01,0xE0,0x00,0x70,0x01,0xE0,0x07,0x80,0x0E,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // >
|
||||
0x00,0x00,0x00,0x00,0x03,0xC0,0x07,0xE0,0x0E,0x30,0x0C,0x30,0x00,0x70,0x00,0xE0,0x01,0xC0,0x01,0x80,0x01,0x80,0x00,0x00,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00, // ?
|
||||
|
||||
0x00,0x00,0x07,0xC0,0x0C,0x30,0x13,0x78,0x17,0xE8,0x2C,0xC8,0x2C,0xC8,0x2C,0xC8,0x2F,0xD0,0x26,0xE0,0x10,0x08,0x08,0x10,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x00, // @
|
||||
0x00,0x00,0x00,0x00,0x03,0x80,0x03,0x80,0x06,0xC0,0x06,0xC0,0x06,0xC0,0x0C,0x60,0x0C,0x60,0x0F,0xE0,0x1F,0xF0,0x18,0x30,0x18,0x30,0x30,0x18,0x00,0x00,0x00,0x00, // A
|
||||
0x00,0x00,0x00,0x00,0x1F,0xE0,0x1F,0xF0,0x18,0x30,0x18,0x30,0x18,0x30,0x1F,0xE0,0x1F,0xF0,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF0,0x1F,0xE0,0x00,0x00,0x00,0x00, // B
|
||||
0x00,0x00,0x00,0x00,0x03,0xE0,0x0F,0xF0,0x0C,0x38,0x1C,0x10,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1C,0x10,0x0C,0x38,0x0F,0xF0,0x03,0xE0,0x00,0x00,0x00,0x00, // C
|
||||
0x00,0x00,0x00,0x00,0x1F,0xC0,0x1F,0xF0,0x18,0x30,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x30,0x1F,0xF0,0x1F,0xC0,0x00,0x00,0x00,0x00, // D
|
||||
0x00,0x00,0x00,0x00,0x0F,0xF8,0x0F,0xF8,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0F,0xF8,0x0F,0xF8,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0F,0xF8,0x0F,0xF8,0x00,0x00,0x00,0x00, // E
|
||||
0x00,0x00,0x00,0x00,0x0F,0xF0,0x0F,0xF0,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0F,0xE0,0x0F,0xE0,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00, // F
|
||||
0x00,0x00,0x00,0x00,0x07,0xE0,0x1F,0xF0,0x18,0x38,0x38,0x10,0x30,0x00,0x30,0x00,0x30,0xF8,0x30,0xF8,0x38,0x18,0x18,0x38,0x1F,0xF8,0x07,0xE0,0x00,0x00,0x00,0x00, // G
|
||||
0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // H
|
||||
0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00, // I
|
||||
0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x0C,0x30,0x0E,0x70,0x07,0xE0,0x03,0xC0,0x00,0x00,0x00,0x00, // J
|
||||
0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x18,0x60,0x18,0xC0,0x19,0x80,0x1B,0xC0,0x1E,0xC0,0x1C,0x60,0x18,0x70,0x18,0x30,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // K
|
||||
0x00,0x00,0x00,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00, // L
|
||||
0x00,0x00,0x00,0x00,0x38,0x38,0x38,0x38,0x3C,0x78,0x3C,0x78,0x34,0x58,0x36,0xD8,0x36,0xD8,0x36,0xD8,0x33,0x98,0x33,0x98,0x33,0x98,0x31,0x18,0x00,0x00,0x00,0x00, // M
|
||||
0x00,0x00,0x00,0x00,0x18,0x18,0x1C,0x18,0x1E,0x18,0x1E,0x18,0x1B,0x18,0x19,0x98,0x19,0x98,0x18,0xD8,0x18,0x78,0x18,0x78,0x18,0x38,0x18,0x18,0x00,0x00,0x00,0x00, // N
|
||||
0x00,0x00,0x00,0x00,0x07,0xC0,0x1F,0xF0,0x18,0x30,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x18,0x30,0x1F,0xF0,0x07,0xC0,0x00,0x00,0x00,0x00, // O
|
||||
|
||||
0x00,0x00,0x00,0x00,0x0F,0xE0,0x0F,0xF0,0x0C,0x38,0x0C,0x18,0x0C,0x38,0x0F,0xF0,0x0F,0xE0,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00, // P
|
||||
0x00,0x00,0x00,0x00,0x07,0xC0,0x1F,0xF0,0x18,0x30,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x31,0xB8,0x18,0xF0,0x1F,0xF0,0x07,0xB0,0x00,0x18,0x00,0x00, // Q
|
||||
0x00,0x00,0x00,0x00,0x1F,0xE0,0x1F,0xF0,0x18,0x38,0x18,0x18,0x18,0x38,0x1F,0xF0,0x1F,0xC0,0x18,0xE0,0x18,0x70,0x18,0x30,0x18,0x38,0x18,0x1C,0x00,0x00,0x00,0x00, // R
|
||||
0x00,0x00,0x00,0x00,0x03,0xE0,0x07,0xF0,0x0E,0x38,0x0C,0x18,0x0F,0x00,0x07,0xE0,0x01,0xF0,0x00,0x38,0x0C,0x18,0x0E,0x38,0x07,0xF0,0x03,0xE0,0x00,0x00,0x00,0x00, // S
|
||||
0x00,0x00,0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00, // T
|
||||
0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1C,0x38,0x0F,0xF0,0x07,0xE0,0x00,0x00,0x00,0x00, // U
|
||||
0x00,0x00,0x00,0x00,0x30,0x18,0x18,0x30,0x18,0x30,0x18,0x30,0x0C,0x60,0x0C,0x60,0x0E,0xE0,0x06,0xC0,0x06,0xC0,0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00, // V
|
||||
0x00,0x00,0x00,0x00,0x31,0xC6,0x31,0xC6,0x31,0xC6,0x1B,0x6C,0x1B,0x6C,0x1B,0x6C,0x1B,0x6C,0x1B,0x6C,0x0E,0x38,0x0E,0x38,0x0E,0x38,0x0E,0x38,0x00,0x00,0x00,0x00, // W
|
||||
0x00,0x00,0x00,0x00,0x18,0x30,0x1C,0x70,0x0C,0x60,0x06,0xC0,0x07,0xC0,0x03,0x80,0x03,0x80,0x07,0xC0,0x06,0xC0,0x0C,0x60,0x1C,0x70,0x18,0x30,0x00,0x00,0x00,0x00, // X
|
||||
0x00,0x00,0x00,0x00,0x18,0x18,0x1C,0x38,0x0C,0x30,0x06,0x60,0x06,0x60,0x03,0xC0,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00, // Y
|
||||
0x00,0x00,0x00,0x00,0x07,0xF8,0x07,0xF8,0x00,0x30,0x00,0x60,0x00,0xE0,0x00,0xC0,0x01,0x80,0x03,0x80,0x03,0x00,0x06,0x00,0x0F,0xF8,0x0F,0xF8,0x00,0x00,0x00,0x00, // Z
|
||||
0x00,0x00,0x03,0xC0,0x03,0xC0,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0xC0,0x03,0xC0,0x00,0x00, // [
|
||||
0x00,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00, // <backslash>
|
||||
0x00,0x00,0x03,0xC0,0x03,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x03,0xC0,0x03,0xC0,0x00,0x00, // ]
|
||||
0x00,0x00,0x01,0x80,0x03,0xC0,0x03,0xC0,0x06,0x60,0x06,0x60,0x06,0x60,0x0C,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00, // _
|
||||
|
||||
0x00,0x00,0x00,0x00,0x01,0x80,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // `
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xC0,0x0F,0xE0,0x0C,0x60,0x01,0xE0,0x07,0xE0,0x0E,0x60,0x0C,0x60,0x0F,0xE0,0x07,0xB0,0x00,0x00,0x00,0x00,0x00,0x00, // a
|
||||
0x00,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0D,0xC0,0x0F,0xE0,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x0F,0xE0,0x0D,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, // b
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x07,0xE0,0x0E,0x60,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0E,0x60,0x07,0xE0,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, // c
|
||||
0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x30,0x03,0xB0,0x07,0xF0,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x07,0xF0,0x03,0xB0,0x00,0x00,0x00,0x00,0x00,0x00, // d
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x07,0xC0,0x0C,0x60,0x0F,0xE0,0x0F,0xE0,0x0C,0x00,0x0E,0x60,0x07,0xC0,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00, // e
|
||||
0x00,0x00,0x03,0xC0,0x07,0xC0,0x06,0x00,0x0F,0x80,0x0F,0x80,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // f
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x60,0x0F,0xE0,0x1C,0xE0,0x18,0x60,0x18,0x60,0x18,0x60,0x1C,0xE0,0x0F,0xE0,0x07,0x60,0x18,0x60,0x1F,0xE0,0x0F,0xC0,0x00,0x00, // g
|
||||
0x00,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0D,0xE0,0x0F,0xF0,0x0E,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x00,0x00,0x00,0x00,0x00,0x00, // h
|
||||
0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00, // i
|
||||
0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x07,0x80,0x07,0x00, // j
|
||||
0x00,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x60,0x0C,0xC0,0x0D,0x80,0x0F,0x80,0x0F,0xC0,0x0E,0xC0,0x0C,0xC0,0x0C,0x60,0x0C,0x60,0x00,0x00,0x00,0x00,0x00,0x00, // k
|
||||
0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00, // l
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x38,0x3F,0xFC,0x39,0xCC,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x00,0x00,0x00,0x00,0x00,0x00, // m
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0xE0,0x0F,0xF0,0x0E,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x00,0x00,0x00,0x00,0x00,0x00, // n
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x07,0xE0,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x07,0xE0,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, // o
|
||||
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0xC0,0x0F,0xE0,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x0F,0xE0,0x0D,0xC0,0x0C,0x00,0x0C,0x00,0x0C,0x00, // p
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xB0,0x07,0xF0,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x07,0xF0,0x03,0xB0,0x00,0x30,0x00,0x30,0x00,0x30, // q
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x70,0x03,0xF0,0x03,0x80,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // r
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xC0,0x0F,0xE0,0x0C,0x60,0x0F,0x00,0x07,0xC0,0x00,0xE0,0x0C,0x60,0x0F,0xE0,0x07,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, // s
|
||||
0x00,0x00,0x01,0x00,0x03,0x00,0x03,0x00,0x07,0xC0,0x07,0xC0,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0xC0,0x01,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, // t
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x70,0x0F,0xF0,0x07,0xB0,0x00,0x00,0x00,0x00,0x00,0x00, // u
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x30,0x06,0x30,0x06,0x30,0x03,0x60,0x03,0x60,0x03,0x60,0x01,0xC0,0x01,0xC0,0x01,0xC0,0x00,0x00,0x00,0x00,0x00,0x00, // v
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0xC6,0x31,0xC6,0x19,0xCC,0x1B,0x6C,0x1B,0x6C,0x1B,0x6C,0x0E,0x38,0x0E,0x38,0x0E,0x38,0x00,0x00,0x00,0x00,0x00,0x00, // w
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x30,0x07,0x70,0x03,0x60,0x01,0xC0,0x01,0xC0,0x01,0xC0,0x03,0x60,0x07,0x70,0x06,0x30,0x00,0x00,0x00,0x00,0x00,0x00, // x
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x18,0x0C,0x18,0x06,0x30,0x06,0x30,0x03,0x60,0x03,0x60,0x03,0xE0,0x01,0xC0,0x01,0xC0,0x01,0x80,0x07,0x80,0x07,0x00, // y
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xF8,0x03,0xF8,0x00,0x30,0x00,0x70,0x00,0xE0,0x01,0xC0,0x01,0x80,0x03,0xF8,0x03,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, // z
|
||||
0x01,0xC0,0x03,0xC0,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x0E,0x00,0x0E,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0xC0,0x01,0xC0,0x00,0x00, // {
|
||||
0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80, // |
|
||||
0x03,0x80,0x03,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0x70,0x00,0x70,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x03,0xC0,0x03,0x80,0x00,0x00, // }
|
||||
0x00,0x00,0x00,0x00,0x07,0x88,0x0F,0xF8,0x08,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~
|
||||
};
|
||||
@@ -1,235 +0,0 @@
|
||||
// Generated by : ImageConverter 565 Online
|
||||
// Generated from : top.png
|
||||
// Time generated : Tue, 30 Sep 14 23:16:51 +0200 (Server timezone: CET)
|
||||
// Image Size : 60x60 pixels
|
||||
// Memory usage : 7200 bytes
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
const unsigned short logo[3600] PROGMEM={
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0010 (16) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0020 (32) pixels
|
||||
0x08E4, 0x28A3, 0x89A7, 0x71C7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0030 (48) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0040 (64) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0050 (80) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xAD55, 0x18C3, 0x0082, 0x4944, 0x5A08, 0x8147, 0xBB0D, 0x5A69, // 0x0060 (96) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0070 (112) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0080 (128) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x52A0, 0x3180, 0x0000, 0x52AA, 0x2945, // 0x0090 (144) pixels
|
||||
0x2965, 0x0000, 0x0000, 0x0000, 0x18E3, 0x0021, 0x4144, 0x69C6, 0x6924, 0xAA49, 0xB3AD, 0x00E2, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00A0 (160) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00B0 (176) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00C0 (192) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2104, 0x0861, 0x2924, 0x0000, 0x0000, 0x00C2, // 0x00D0 (208) pixels
|
||||
0x1862, 0x4924, 0x4924, 0x9965, 0xCB4A, 0xE48D, 0x9329, 0x0004, 0x6A69, 0x51A5, 0x2125, 0x0000, 0x5000, 0x0000, 0x0000, 0x0000, // 0x00E0 (224) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00F0 (240) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0100 (256) pixels
|
||||
0x0000, 0x1002, 0x1924, 0x41A4, 0x3124, 0x0000, 0x0000, 0x4A69, 0x2924, 0x0000, 0x0000, 0x4125, 0x38E4, 0x5983, 0x9A46, 0xE40A, // 0x0110 (272) pixels
|
||||
0xFCCD, 0xF4CE, 0x50E5, 0x6226, 0xBBAC, 0xAAEB, 0x4904, 0x0000, 0x4104, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0120 (288) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0130 (304) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2124, 0x10C3, 0x0000, 0x0000, 0x2800, 0x41A5, 0x9309, // 0x0140 (320) pixels
|
||||
0x8288, 0x00E5, 0x4A49, 0x73AE, 0x31A6, 0x1800, 0x59C7, 0x71E7, 0x2100, 0x8266, 0xE40B, 0xFCAC, 0xFC8C, 0xDC8F, 0x5187, 0xA387, // 0x0150 (336) pixels
|
||||
0xABA9, 0x9249, 0x58C0, 0x0000, 0x0000, 0x8410, 0x2104, 0x10A2, 0x2965, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0160 (352) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0170 (368) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0944, 0x2062, 0x5165, 0x5903, 0x00A4, 0x0165, 0x8A67, 0xAB28, 0x7267, 0x29E8, 0x7B0C, // 0x0180 (384) pixels
|
||||
0x6185, 0x8207, 0xC3AC, 0x6A04, 0x0140, 0xC36A, 0xFDEC, 0xF5AC, 0xFD30, 0xCC51, 0x70C5, 0xC469, 0xEC8D, 0x89E9, 0x0000, 0x5269, // 0x0190 (400) pixels
|
||||
0x20C3, 0x0861, 0x0841, 0x18A2, 0x39E7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x01A0 (416) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x01B0 (432) pixels
|
||||
0x5000, 0x0000, 0x71A5, 0x9A88, 0xAAA8, 0xC2C9, 0xA248, 0x9A26, 0xCA87, 0xCAC8, 0x58C0, 0x69C5, 0xC30B, 0xD3AC, 0xDC4A, 0x51A2, // 0x01C0 (448) pixels
|
||||
0x5A65, 0xEC6B, 0xFDCB, 0xFE0E, 0xFD0F, 0xEBF1, 0xB3EB, 0xED6E, 0xEC10, 0x61C7, 0x0123, 0x0021, 0x0082, 0x10C3, 0x3186, 0x0000, // 0x01D0 (464) pixels
|
||||
0x0000, 0x6180, 0x5000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x01E0 (480) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF800, 0x0000, 0xFFF0, 0x5943, // 0x01F0 (496) pixels
|
||||
0xA226, 0xD369, 0xEB4A, 0xE289, 0xE26A, 0xEB0E, 0x9AAA, 0x5042, 0xDBAC, 0xEC8C, 0xDC29, 0x7A45, 0xCC4A, 0xFB4C, 0xFD8D, 0xFDF0, // 0x0200 (512) pixels
|
||||
0xF510, 0xFD8F, 0xF5CF, 0xFE31, 0xCC31, 0x0000, 0x3801, 0x4143, 0x59A6, 0x4165, 0x0082, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0210 (528) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0220 (544) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0041, 0x9986, 0xC2E8, 0xDB88, 0xF44A, // 0x0230 (560) pixels
|
||||
0xDBCB, 0xEBCD, 0xD44D, 0x41C5, 0xB308, 0xEC0B, 0xF46C, 0xE40D, 0xD38A, 0xEC2D, 0xFEAE, 0xFEF2, 0xFDD2, 0xFE51, 0xFD52, 0xFCB1, // 0x0240 (576) pixels
|
||||
0xEC50, 0xCBEE, 0xB42A, 0xA2C6, 0x8985, 0x79A6, 0x89A6, 0xB1E6, 0xA1C6, 0x5924, 0x4986, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0250 (592) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0260 (608) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0040, 0x6125, 0xE3A9, 0xF4EB, 0xF5AC, 0xDD49, 0xE5CB, 0xFE6E, 0xC44E, // 0x0270 (624) pixels
|
||||
0x9B8A, 0xE4CD, 0xFD70, 0xFDB1, 0xCCCE, 0xF62E, 0xFE8D, 0xFE50, 0xFE56, 0xFD97, 0xF4B6, 0xF3F0, 0xFD2F, 0xFE50, 0xF5D1, 0xDC10, // 0x0280 (640) pixels
|
||||
0xB289, 0xC269, 0xCA68, 0xEB6C, 0xDC2F, 0xA2C9, 0x2062, 0x1945, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0290 (656) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x02A0 (672) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x00E3, 0x3904, 0xB1C6, 0xE34C, 0xEC2C, 0xE4AB, 0xCD2B, 0xF64C, 0xFE70, 0xFE4F, 0xEE4E, 0xFED2, 0xFED2, // 0x02B0 (688) pixels
|
||||
0xFEB2, 0xFE33, 0xFDD3, 0xFE74, 0xF535, 0xCB11, 0xEB32, 0xFCF2, 0xFDF1, 0xF574, 0xFE13, 0xFE52, 0xBC4B, 0x8226, 0x6945, 0x6A28, // 0x02C0 (704) pixels
|
||||
0x3228, 0x2124, 0x1904, 0x51C7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x02D0 (720) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x10A2, // 0x02E0 (736) pixels
|
||||
0x0861, 0x91C5, 0xDA4A, 0xEAAB, 0xF3D1, 0xED12, 0xD591, 0xC50D, 0xA3E9, 0xB50C, 0xEE92, 0xB4EE, 0x7329, 0x82E8, 0xC572, 0xEDF3, // 0x02F0 (752) pixels
|
||||
0xB3ED, 0x3800, 0xA3CF, 0xFEF6, 0xFED0, 0xFEB4, 0xFEF3, 0xF6CF, 0xEEAE, 0xBD2A, 0x0120, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0300 (768) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0310 (784) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1001, 0x39C7, 0x8227, 0xE2AA, 0xDB0C, // 0x0320 (800) pixels
|
||||
0xE4B3, 0xCD11, 0x83EA, 0x5286, 0x52AA, 0x7BEF, 0x2940, 0x3A2A, 0x5AEB, 0x73CF, 0x52AA, 0x3945, 0x1184, 0x6B2B, 0xACF1, 0xB54F, // 0x0330 (816) pixels
|
||||
0xF733, 0xFF51, 0xFF32, 0xFF55, 0xFF33, 0xF696, 0xCC93, 0x624A, 0x0120, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0340 (832) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0350 (848) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6248, 0x9249, 0xCB2A, 0xABEC, 0x8C2B, 0x5AE6, 0x10C3, 0x5269, // 0x0360 (864) pixels
|
||||
0xA4F3, 0xD637, 0x9C90, 0xAD33, 0xAD12, 0xE6FA, 0xC5B5, 0x6AC9, 0x83CE, 0xBD53, 0xCDD5, 0x9450, 0x6B47, 0xCD91, 0xFEB4, 0xEED4, // 0x0370 (880) pixels
|
||||
0x9490, 0x736E, 0xCCD5, 0xCC94, 0x7B2D, 0x0000, 0xFC10, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0380 (896) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0390 (912) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x6A8A, 0x8B0A, 0x9C2B, 0x7BCA, 0x3163, 0x526B, 0x1904, 0x736C, 0xE698, 0xD658, 0xD658, 0xD616, // 0x03A0 (928) pixels
|
||||
0xF719, 0xFF5B, 0xF71A, 0xEED8, 0xD5F5, 0xEEFA, 0xE6B8, 0xA4F3, 0x29A8, 0x0000, 0xAC31, 0xEE36, 0x9C2E, 0x0000, 0x4145, 0xAB70, // 0x03B0 (944) pixels
|
||||
0xC4B4, 0x93F0, 0x0000, 0x0000, 0x4008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x03C0 (960) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x03D0 (976) pixels
|
||||
0x8B6B, 0x7B6A, 0x1124, 0x0000, 0x0000, 0x41E6, 0x0002, 0xB512, 0xFF7B, 0xFF9C, 0xFF9C, 0xFFDD, 0xFF9C, 0xFFBD, 0xFFFF, 0xFF9C, // 0x03E0 (992) pixels
|
||||
0xFF5B, 0xFFBD, 0xFF9C, 0xF71A, 0x9CB1, 0x0000, 0x0000, 0xACB2, 0xE6B6, 0x4A68, 0x0000, 0x0144, 0x738E, 0x6B4D, 0x0000, 0x0000, // 0x03F0 (1008) pixels
|
||||
0x500A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0400 (1024) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2145, 0x3144, 0x0002, 0x0000, 0x0000, // 0x0410 (1040) pixels
|
||||
0x0000, 0x39C7, 0x0083, 0xC594, 0xEED9, 0xEEB8, 0xEEFA, 0xC5F7, 0xEEFA, 0xFFDD, 0xDEFB, 0xA4F2, 0xEE97, 0xF6D8, 0xEEF9, 0xFF7B, // 0x0420 (1056) pixels
|
||||
0xDE56, 0x41C6, 0x0000, 0x0000, 0x9491, 0x7BCE, 0x0000, 0x6209, 0x0000, 0x0000, 0x6A49, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0430 (1072) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0440 (1088) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2965, 0x0000, 0xAD12, // 0x0450 (1104) pixels
|
||||
0xCE17, 0x534E, 0x02B0, 0x7472, 0xF73A, 0xFF7B, 0xF71A, 0xA4F2, 0x02AE, 0x4B6F, 0x9C91, 0xFF5B, 0xF6D9, 0x838C, 0x0000, 0x0000, // 0x0460 (1120) pixels
|
||||
0x0000, 0x0001, 0x2124, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0470 (1136) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0480 (1152) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x8400, 0x5000, 0x8410, 0x0000, 0xB4D3, 0x2965, 0x3985, 0xA4D1, 0xFFDF, 0xCEDC, 0x4413, 0xDEFA, // 0x0490 (1168) pixels
|
||||
0xFF9C, 0xEED9, 0xFF5A, 0xFF5A, 0x8D36, 0xBE59, 0xFFDE, 0xFF7B, 0xFF19, 0x8BEE, 0x0000, 0x0000, 0x0000, 0x632C, 0x0005, 0x0000, // 0x04A0 (1184) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x04B0 (1200) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x04C0 (1216) pixels
|
||||
0x0000, 0x0000, 0x8410, 0x0000, 0x7BCF, 0x2966, 0x5247, 0xBD95, 0xFFDE, 0xFF9C, 0xF73A, 0xFF7B, 0xF719, 0xCE17, 0xF75C, 0xFFDE, // 0x04D0 (1232) pixels
|
||||
0xFF7C, 0xFF5A, 0xFFDE, 0xFF3A, 0xFF5A, 0xACF1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x04E0 (1248) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x04F0 (1264) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8410, 0x0000, // 0x0500 (1280) pixels
|
||||
0x8C51, 0x2966, 0x62A9, 0x9CB2, 0xE6B9, 0xEEB8, 0xFF5B, 0xFF9C, 0xEEB8, 0xD637, 0xFF9C, 0xFFBD, 0xFF7B, 0xFF5B, 0xFF5B, 0xFF19, // 0x0510 (1296) pixels
|
||||
0xFF5A, 0xC574, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0520 (1312) pixels
|
||||
0x0000, 0x0000, 0x5000, 0x52AA, 0x8000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0530 (1328) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8410, 0x0000, 0xACF3, 0x3186, 0x5AA9, 0x940E, // 0x0540 (1344) pixels
|
||||
0x9C90, 0xD616, 0xEEF9, 0xFF7B, 0xDE78, 0xB533, 0xE697, 0xFF39, 0xFF5A, 0xFF5B, 0xFF3A, 0xFF5B, 0xFF5A, 0xC593, 0x0000, 0x0000, // 0x0550 (1360) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0560 (1376) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0570 (1392) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2125, 0x5248, 0xA490, 0xC5B5, 0xEED9, 0xF73A, 0xF71A, // 0x0580 (1408) pixels
|
||||
0xACF2, 0xBD74, 0xB533, 0xF71A, 0xFF9C, 0xFF3B, 0xFF7C, 0xFF9C, 0xFF9C, 0xB512, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0590 (1424) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x05A0 (1440) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x05B0 (1456) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2125, 0x41E7, 0xA4B1, 0xBD95, 0xE698, 0xF71A, 0xFF7B, 0xEEB8, 0xFF3A, 0xF6F9, 0xFFBD, // 0x05C0 (1472) pixels
|
||||
0xEEB9, 0xAC2F, 0xE71B, 0xFFBD, 0xFF9C, 0xB532, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x05D0 (1488) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x4208, 0x2965, 0x5248, 0xB512, 0xE676, 0xA46F, 0x0000, 0xFFF0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x05E0 (1504) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x05F0 (1520) pixels
|
||||
0x0000, 0x4208, 0x0000, 0xA490, 0xFF7C, 0xAD54, 0x91E6, 0xFF3B, 0xFFBC, 0xFF5A, 0xFF7B, 0xFFDD, 0xDC90, 0xB450, 0xF75B, 0xFF3A, // 0x0600 (1536) pixels
|
||||
0xFF9B, 0xA4D1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0610 (1552) pixels
|
||||
0x4A28, 0xC573, 0xFF7B, 0xFF5A, 0x7B4B, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x52AA, 0x0000, 0x0000, // 0x0620 (1568) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4208, 0x0000, 0x52AA, 0x1904, 0x62C9, // 0x0630 (1584) pixels
|
||||
0xFF5B, 0xE6BA, 0x5800, 0xDC0E, 0xFF1B, 0xFF7B, 0xFFBD, 0xF617, 0xB940, 0xD617, 0xFF5A, 0xFF19, 0xFF7B, 0x7B6C, 0x0000, 0x0000, // 0x0640 (1600) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5000, 0x0000, 0x08C4, 0x6B0A, 0x942F, 0xF6F9, 0xFF7A, 0xC574, // 0x0650 (1616) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0660 (1632) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8410, 0x0000, 0x738E, 0x4A49, 0x08A3, 0xCDB4, 0xFF7B, 0x9CB1, 0x9000, // 0x0670 (1648) pixels
|
||||
0xC267, 0xA3AD, 0xB34C, 0xA8E0, 0xBD14, 0xF71A, 0xFF39, 0xFF9B, 0xE698, 0x0000, 0x0000, 0x52AA, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0680 (1664) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x4200, 0x0000, 0x1904, 0x6AEA, 0x83AC, 0xC573, 0x8BEE, 0x0000, 0x52AA, 0x0000, 0x0000, 0x0000, // 0x0690 (1680) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x4229, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x06A0 (1696) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x4208, 0x0000, 0x5AAA, 0x2146, 0x83CD, 0xFF19, 0xFF19, 0xBD53, 0x9BEE, 0x9BAD, 0xACD3, 0xC658, // 0x06B0 (1712) pixels
|
||||
0xF73B, 0xFF5A, 0xFF5A, 0xF73A, 0x630C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x06C0 (1728) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00A7, // 0x06D0 (1744) pixels
|
||||
0x4A28, 0x4A48, 0x428B, 0x0000, 0x4208, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x06E0 (1760) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x4228, 0x3186, 0xCDF6, 0xFF7B, 0xFF7B, 0xF71A, 0xF73A, 0xFF9C, 0xFF7C, 0xFF3A, 0xFF3A, 0xFF9C, 0x9471, // 0x06F0 (1776) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2104, // 0x0700 (1792) pixels
|
||||
0x2104, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4208, 0x0000, 0x0000, 0xACD1, 0xE677, 0x836C, 0x0000, // 0x0710 (1808) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8410, 0x0000, 0x8C51, // 0x0720 (1824) pixels
|
||||
0x2945, 0x39C6, 0x9C90, 0xE6B9, 0xFF9C, 0xFF5A, 0xFF19, 0xFF3A, 0xFF7B, 0xFFDD, 0xB5B6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0730 (1840) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x39C7, 0x18C3, 0x3186, 0x0000, 0x0000, 0x0000, // 0x0740 (1856) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFF0, 0x10E4, 0xB512, 0xFF9B, 0xE6B8, 0x0002, 0x0000, 0x8410, 0x0000, 0x0000, // 0x0750 (1872) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0000, 0x52AA, 0x10E3, 0x0000, 0x83AD, // 0x0760 (1888) pixels
|
||||
0xE698, 0xFF19, 0xFF39, 0xEED8, 0xD658, 0x9492, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0770 (1904) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x18E3, 0x18E3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0780 (1920) pixels
|
||||
0x0000, 0x0000, 0xAD55, 0x2145, 0x9C4F, 0xBD32, 0x9450, 0x31A7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0790 (1936) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x52AA, 0x0000, 0x0000, 0x8C31, 0xB576, 0x41E7, 0x5AA9, 0x5A68, 0x8C0F, 0x8C0F, 0x5ACA, // 0x07A0 (1952) pixels
|
||||
0x4A6A, 0xB532, 0x8BCD, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x07B0 (1968) pixels
|
||||
0x0000, 0x0000, 0x18C3, 0x2945, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2965, // 0x07C0 (1984) pixels
|
||||
0x18C3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x07D0 (2000) pixels
|
||||
0x0000, 0x52AA, 0x0000, 0x1003, 0xCE1A, 0xEF1D, 0x62EC, 0x7B8C, 0xA4B1, 0x9C70, 0xB512, 0xB532, 0xD616, 0xF6D8, 0x6B0B, 0x0000, // 0x07E0 (2016) pixels
|
||||
0x3165, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x18E3, 0x18E3, 0x0000, // 0x07F0 (2032) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xA451, 0x2945, 0x18E3, // 0x0800 (2048) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x9E73, 0x0000, // 0x0810 (2064) pixels
|
||||
0x9493, 0xF77E, 0xCE39, 0x4A48, 0xCDF6, 0xC5B5, 0xEED9, 0xE6B8, 0xFF3A, 0x942F, 0x73AE, 0x8430, 0x39C7, 0x0000, 0x0000, 0x0000, // 0x0820 (2080) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2124, 0x18E3, 0x8410, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0830 (2096) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8410, 0x18E3, 0x18E3, 0x4A69, 0x0000, 0x0000, // 0x0840 (2112) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8410, 0x0000, 0x4268, 0x5A8C, 0x0003, 0xB557, 0xFFDF, 0xA555, // 0x0850 (2128) pixels
|
||||
0xA4B1, 0xDE57, 0xEEB8, 0xFFBC, 0xB554, 0xA534, 0xB595, 0xB576, 0x7BD0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0860 (2144) pixels
|
||||
0x0000, 0x0000, 0x4208, 0x18C3, 0x18E3, 0x31A6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0870 (2160) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x52AA, 0x0000, 0x0000, 0x2124, 0x18C3, 0x2104, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0880 (2176) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x4208, 0x0000, 0x4A68, 0x526B, 0x7B50, 0x62AD, 0xDEBC, 0xFFFF, 0x8430, 0xB554, 0xFF7B, 0xE6B9, // 0x0890 (2192) pixels
|
||||
0x636E, 0xF7BE, 0x8C71, 0xDE9B, 0xCE1A, 0x1063, 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x39E7, 0x18E3, 0x18E3, 0x2104, // 0x08A0 (2208) pixels
|
||||
0x8410, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x08B0 (2224) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3186, 0x18C3, 0x2104, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x08C0 (2240) pixels
|
||||
0x4208, 0x0000, 0x4A49, 0x4A0A, 0xACF7, 0x7B70, 0xA514, 0xFFFF, 0xF79E, 0x9491, 0xE6B8, 0x83EF, 0xDEDB, 0xE71C, 0x8410, 0xFFFF, // 0x08D0 (2256) pixels
|
||||
0xF77E, 0xA4D5, 0x0000, 0x0000, 0x0000, 0x0000, 0x3186, 0x2104, 0x18E3, 0x18E3, 0x39C7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x08E0 (2272) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x08F0 (2288) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x18C3, 0x2104, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x31C6, 0x734E, // 0x0900 (2304) pixels
|
||||
0xB537, 0xACB6, 0x5AAB, 0xE71C, 0xFFFF, 0xCE59, 0x0000, 0x9CD3, 0xFFFF, 0xA535, 0xBDF7, 0xFFFF, 0xF79E, 0xE6DD, 0xC5D8, 0x4228, // 0x0910 (2320) pixels
|
||||
0x0000, 0x3186, 0x18E3, 0x2104, 0x4208, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0920 (2336) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4A49, // 0x0930 (2352) pixels
|
||||
0x10A2, 0x18C3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3166, 0x9453, 0xBD58, 0xB518, 0x83B1, 0xAD75, // 0x0940 (2368) pixels
|
||||
0xD6BA, 0x2125, 0x3186, 0x736E, 0xB596, 0x7BF0, 0xE73C, 0xFFFF, 0xF77E, 0xF79E, 0xF79E, 0xC5F8, 0x10A1, 0x1082, 0x8410, 0x0000, // 0x0950 (2384) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0960 (2400) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x52AA, 0x18E3, 0x10A2, 0x18C3, // 0x0970 (2416) pixels
|
||||
0x18C3, 0x0861, 0x0861, 0x0000, 0x0000, 0x2985, 0x41E8, 0xA4D5, 0xACF7, 0xC5D9, 0xE6DC, 0x6B4D, 0x62ED, 0xA4D4, 0x9452, 0xC5B9, // 0x0980 (2432) pixels
|
||||
0x522A, 0x8430, 0xFFFF, 0xFFBF, 0xF77E, 0xF7BE, 0xF77E, 0xE6DD, 0x9CD4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0990 (2448) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x09A0 (2464) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2104, 0x18E3, 0x18E3, 0x18C3, 0x18C3, 0x2945, // 0x09B0 (2480) pixels
|
||||
0x39C7, 0x3186, 0x62CC, 0x9C54, 0x9C35, 0xD63A, 0xF75E, 0xA534, 0x83D0, 0xC5D8, 0x9CD3, 0xE6DD, 0x7B70, 0xB5B6, 0xFFFF, 0xEF5E, // 0x09C0 (2496) pixels
|
||||
0xF77E, 0xFFBF, 0xF77E, 0xE6FD, 0xBD98, 0x39A7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x09D0 (2512) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x09E0 (2528) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4A49, 0x5AAC, 0x8392, // 0x09F0 (2544) pixels
|
||||
0xB537, 0xCE1A, 0xE6FC, 0xF7BE, 0xDEDB, 0xD69A, 0x8C71, 0xFFFF, 0xEF7D, 0xEF7D, 0xFFFF, 0xEF5E, 0xF77E, 0xFFDF, 0xF79E, 0xF77E, // 0x0A00 (2560) pixels
|
||||
0xD65B, 0x7B70, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0A10 (2576) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0A20 (2592) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4208, 0x5A4B, 0xA495, 0xD67B, 0xC599, 0xDEBC, 0xFFFF, // 0x0A30 (2608) pixels
|
||||
0xFFBF, 0xE71C, 0x8C71, 0xE73C, 0xB5B6, 0xEF7D, 0xFFFF, 0xEF5E, 0xF77E, 0xFFFF, 0xFFDF, 0xF79E, 0xEF5E, 0xC5B9, 0x4A49, 0x0000, // 0x0A40 (2624) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0A50 (2640) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0A60 (2656) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x39E7, 0x4A2A, 0xACF6, 0xE6FC, 0xD63A, 0xE71D, 0xFFFF, 0xF79E, 0xEF3D, 0x9CD3, 0xD69A, // 0x0A70 (2672) pixels
|
||||
0xBDF7, 0xFFDE, 0xFFDF, 0xF77E, 0xF79E, 0xFFDF, 0xFFFF, 0xFFBF, 0xF7BF, 0xEF1D, 0xAD15, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0A80 (2688) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0A90 (2704) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0AA0 (2720) pixels
|
||||
0x0000, 0x2965, 0x62CC, 0xACD6, 0xEF3D, 0xE6DC, 0xE71D, 0xFFFF, 0xF7BF, 0xF75E, 0x9CF3, 0xDEDB, 0xFFDF, 0xE73C, 0xFFDF, 0xF7BE, // 0x0AB0 (2736) pixels
|
||||
0xF7BF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEF5E, 0xD65A, 0x41E8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0AC0 (2752) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0AD0 (2768) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1922, 0x734F, 0xB4F7, // 0x0AE0 (2784) pixels
|
||||
0xEF5E, 0xE6FC, 0xEF3D, 0xEF5D, 0xF79E, 0xF79E, 0xB5B6, 0xBDF7, 0xC638, 0xC638, 0xFFFF, 0xFFDF, 0xF79E, 0xFFFF, 0xFFFF, 0xFFFF, // 0x0AF0 (2800) pixels
|
||||
0xFFFF, 0xFFDF, 0xEF1D, 0x9452, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0B00 (2816) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0B10 (2832) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2144, 0x736F, 0xBD78, 0xEF5E, 0xDEBC, 0xEF3D, 0xE6FC, // 0x0B20 (2848) pixels
|
||||
0xF7BF, 0xF79E, 0xD69A, 0x9492, 0xFFFF, 0xFFDF, 0xFFFF, 0xFFDF, 0xF79E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF79F, 0xC5D9, // 0x0B30 (2864) pixels
|
||||
0x2144, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0B40 (2880) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0B50 (2896) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x31A6, 0x7B8F, 0xB537, 0xE6DC, 0xE71D, 0xF79E, 0xE6FD, 0xFFDF, 0xFFFF, 0xEF7D, 0x9492, // 0x0B60 (2912) pixels
|
||||
0xE71C, 0x738E, 0xEF7D, 0xFFDF, 0xFFBF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFDF, 0xD67B, 0x62ED, 0x0000, 0x8410, 0x0000, // 0x0B70 (2928) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0B80 (2944) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0B90 (2960) pixels
|
||||
0x0000, 0x39C7, 0x83F0, 0xACF7, 0xD65B, 0xF79E, 0xFFDF, 0xE6FC, 0xFFDF, 0xFFFF, 0xFFDF, 0x8C71, 0xE71C, 0xE71C, 0xFFFF, 0xFFDF, // 0x0BA0 (2976) pixels
|
||||
0xFFBF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xDE7B, 0x8BD2, 0x0000, 0x630C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0BB0 (2992) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0BC0 (3008) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x39C7, 0x8C31, 0xACD6, // 0x0BD0 (3024) pixels
|
||||
0xD65B, 0xF79E, 0xFFDF, 0xE6FD, 0xFFDF, 0xEF5E, 0xEF1D, 0x83F0, 0xE73C, 0xFFFF, 0xEF5D, 0xFFFF, 0xFFDF, 0xFFFF, 0xFFFF, 0xFFFF, // 0x0BE0 (3040) pixels
|
||||
0xFFFF, 0xFFFF, 0xDE9C, 0xD65B, 0x8430, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0BF0 (3056) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0C00 (3072) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x52AA, 0x0000, 0x31A6, 0x8C31, 0x9C74, 0xDE9B, 0xFFDF, 0xFFDF, 0xEF1D, // 0x0C10 (3088) pixels
|
||||
0xF79E, 0xEF5E, 0xE6FD, 0x9493, 0xCE79, 0xD6BA, 0xBDD7, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF77E, 0xBD78, 0x9472, // 0x0C20 (3104) pixels
|
||||
0x4A4C, 0x524B, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0C30 (3120) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0C40 (3136) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x4208, 0x0000, 0x3166, 0x73AE, 0x9C74, 0xE6DC, 0xFFDF, 0xF79E, 0xF79E, 0xF79E, 0xF79E, 0xE6DC, 0xC618, // 0x0C50 (3152) pixels
|
||||
0x9492, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xEF3D, 0xDE9C, 0xACD6, 0x6ACD, 0x3ACF, 0x9D9A, 0x7C94, 0x0000, 0x0000, // 0x0C60 (3168) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0C70 (3184) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0C80 (3200) pixels
|
||||
0x0000, 0x2945, 0x4A8B, 0xA4F5, 0xF77E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFBF, 0xFFDF, 0x8C51, 0xBDD8, 0xC5DA, 0xBDB9, // 0x0C90 (3216) pixels
|
||||
0xCE3A, 0xC5F9, 0x9C74, 0x622D, 0x3806, 0x2106, 0x3BF4, 0x7DBB, 0xAEBE, 0x8578, 0x0000, 0x0000, 0x4208, 0x0000, 0x0000, 0x0000, // 0x0CA0 (3232) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0CB0 (3248) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x52AA, 0x0000, 0x420A, 0x11CB, 0x632F, // 0x0CC0 (3264) pixels
|
||||
0x9CB5, 0xB597, 0xCE79, 0xD6BA, 0xD6BB, 0xAD77, 0xB5B7, 0xAD96, 0x6B30, 0x0809, 0x300C, 0x280C, 0x3009, 0x0003, 0x0000, 0x00A3, // 0x0CD0 (3280) pixels
|
||||
0x332F, 0x7D99, 0x8E1C, 0x8E1B, 0x9E7D, 0x95FB, 0x2986, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0CE0 (3296) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0CF0 (3312) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001F, 0x0000, 0x82B5, 0x398D, 0x18CC, 0x0170, 0x00B0, 0x000C, 0x100A, // 0x0D00 (3328) pixels
|
||||
0x180B, 0x000A, 0x0009, 0x0009, 0x380B, 0x518D, 0x48CC, 0x484B, 0x49AD, 0x3BF5, 0x5CF8, 0x6539, 0x7DDC, 0xBEDD, 0xCF1D, 0x759B, // 0x0D10 (3344) pixels
|
||||
0x9E7C, 0xA67D, 0x3AAC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0D20 (3360) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0D30 (3376) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x000A, 0x0000, 0x398C, 0x314B, 0x3A32, 0x53B7, 0x53B6, 0x42D4, 0x4314, 0x5375, 0x63B5, 0x6395, // 0x0D40 (3392) pixels
|
||||
0x4252, 0x496E, 0x4AF2, 0x5436, 0x5CD9, 0x5D5B, 0x8DFC, 0x9E7D, 0xAE9D, 0xBEDD, 0xCEFD, 0x5D5A, 0xA67C, 0xA69D, 0x5390, 0x0000, // 0x0D50 (3408) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0D60 (3424) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0D70 (3440) pixels
|
||||
0x4208, 0x0000, 0x318A, 0x292A, 0x30ED, 0x52F4, 0x53B7, 0x4BF7, 0x5438, 0x5458, 0x5C17, 0x5376, 0x4B36, 0x6CD9, 0x5D5A, 0x75DB, // 0x0D80 (3456) pixels
|
||||
0x85FC, 0x963C, 0xA67C, 0xA67C, 0x9E5C, 0xA67C, 0x8DFB, 0x5D5A, 0xA67C, 0xBEFE, 0x74B5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0D90 (3472) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0DA0 (3488) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x02AA, 0x0000, 0x31C9, 0x292A, // 0x0DB0 (3504) pixels
|
||||
0x394D, 0x4212, 0x4315, 0x43B6, 0x5CB9, 0x4B96, 0x5BB6, 0x7458, 0x6C58, 0x755A, 0x5D5A, 0x85DB, 0xAE9D, 0x9E5C, 0xBEDD, 0xAE9D, // 0x0DC0 (3520) pixels
|
||||
0x963C, 0x9E5C, 0x75BB, 0x657B, 0xBEBD, 0xB6DE, 0x74F7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0DD0 (3536) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0DE0 (3552) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2108, 0x396E, 0x41D0, 0x42D4, 0x3356, // 0x0DF0 (3568) pixels
|
||||
0x3BF7, 0x43B7, 0x53D7, 0x5C99, 0x5417, 0x651A, 0x5D5A, 0x7DBB, 0x85FB, 0x8E1C, 0x9E5C, 0x8E1C, 0x85FB, 0x963C, 0x961C, 0x7DDB, // 0x0E00 (3584) pixels
|
||||
0xD73E, 0xAEBD, 0x8517, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0E10 (3600) pixels
|
||||
};
|
||||
@@ -1,109 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - epierre
|
||||
* Contribution: bulldoglowell, gizmocuz
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Arduino UVM-30A
|
||||
* Index table taken from: http://www.elecrow.com/sensors-c-111/environment-c-111_112/uv-sensor-moduleuvm30a-p-716.html
|
||||
* Because this table is pretty lineair, we can calculate a UVI with one decimal
|
||||
*
|
||||
* Connect sensor:
|
||||
*
|
||||
* + >>> 5V
|
||||
* - >>> GND
|
||||
* out >>> A0
|
||||
*
|
||||
* License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define UV_SENSOR_ANALOG_PIN 0
|
||||
|
||||
#define CHILD_ID_UV 0
|
||||
|
||||
unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds)
|
||||
|
||||
MyMessage uvMsg(CHILD_ID_UV, V_UV);
|
||||
|
||||
unsigned long lastSend =0;
|
||||
float uvIndex;
|
||||
float lastUV = -1;
|
||||
uint16_t uvIndexValue [12] = { 50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170};
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("UV Sensor", "1.2");
|
||||
|
||||
// Register all sensors to gateway (they will be created as child devices)
|
||||
present(CHILD_ID_UV, S_UV);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
uint16_t uv = analogRead(UV_SENSOR_ANALOG_PIN);// Get UV value
|
||||
if (uv>1170)
|
||||
uv=1170;
|
||||
|
||||
//Serial.print("UV Analog reading: ");
|
||||
//Serial.println(uv);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
if (uv <= uvIndexValue[i])
|
||||
{
|
||||
uvIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//calculate 1 decimal if possible
|
||||
if (i>0) {
|
||||
float vRange=uvIndexValue[i]-uvIndexValue[i-1];
|
||||
float vCalc=uv-uvIndexValue[i-1];
|
||||
uvIndex+=(1.0/vRange)*vCalc-1.0;
|
||||
}
|
||||
|
||||
//Serial.print("UVI: ");
|
||||
//Serial.println(uvIndex,2);
|
||||
|
||||
//Send value to gateway if changed, or at least every 5 minutes
|
||||
if ((uvIndex != lastUV)||(currentTime-lastSend >= 5UL*60UL*1000UL)) {
|
||||
lastSend=currentTime;
|
||||
send(uvMsg.set(uvIndex,2));
|
||||
lastUV = uvIndex;
|
||||
}
|
||||
|
||||
sleep(SLEEP_TIME);
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Vibration Sensor
|
||||
*
|
||||
* connect the sensor as follows :
|
||||
*
|
||||
* VCC >>> 5V
|
||||
* S >>> D3
|
||||
* GND >>> GND
|
||||
*
|
||||
* Based on: http://www.dfrobot.com/wiki/index.php/DFRobot_Digital_Vibration_Sensor_V2_SKU:DFR0027
|
||||
* Contributor: epierre
|
||||
**/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
#include <Wire.h>
|
||||
|
||||
#define CHILD_ID_VIBRATION 0
|
||||
#define VIBRATION_SENSOR_DIGITAL_PIN 3
|
||||
#define SensorLED 13
|
||||
|
||||
unsigned long SLEEP_TIME = 10*1000; // Sleep time between reads (in seconds)
|
||||
|
||||
//VARIABLES
|
||||
int val = 0; // variable to store the value coming from the sensor
|
||||
float valVIBRATION =0.0;
|
||||
float lastVIBRATION =0.0;
|
||||
unsigned char state = 0;
|
||||
|
||||
MyMessage vibrationMsg(CHILD_ID_VIBRATION, V_LEVEL);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("VIBRATION Sensor", "1.0");
|
||||
|
||||
// Register all sensors to gateway (they will be created as child devices)
|
||||
present(CHILD_ID_VIBRATION, S_VIBRATION);
|
||||
|
||||
|
||||
pinMode(VIBRATION_SENSOR_DIGITAL_PIN, INPUT);
|
||||
attachInterrupt(1, blink, FALLING);// Trigger the blink function when the falling edge is detected
|
||||
pinMode(SensorLED, OUTPUT);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
if(state>=40){ // basically below 40 so ignire basic level
|
||||
send(vibrationMsg.set(int(state)));
|
||||
state = 0;
|
||||
digitalWrite(SensorLED,HIGH);
|
||||
} else {
|
||||
state = 0;
|
||||
digitalWrite(SensorLED,LOW);
|
||||
}
|
||||
|
||||
|
||||
// Power down the radio. Note that the radio will get powered back up
|
||||
// on the next write() call.
|
||||
delay(1000); //delay to allow serial to fully print before sleep
|
||||
|
||||
sleep(SLEEP_TIME); //sleep for: sleepTime
|
||||
}
|
||||
|
||||
void blink()//Interrupts function
|
||||
{
|
||||
state++;
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2015 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
|
||||
*
|
||||
* Documentation: http://www.mysensors.org
|
||||
* Support Forum: http://forum.mysensors.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*******************************
|
||||
*
|
||||
* REVISION HISTORY
|
||||
* Version 1.0 - Henrik Ekblad
|
||||
* Version 1.1 - GizMoCuz
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Use this sensor to measure volume and flow of your house watermeter.
|
||||
* You need to set the correct pulsefactor of your meter (pulses per m3).
|
||||
* The sensor starts by fetching current volume reading from gateway (VAR 1).
|
||||
* Reports both volume and flow back to gateway.
|
||||
*
|
||||
* Unfortunately millis() won't increment when the Arduino is in
|
||||
* sleepmode. So we cannot make this sensor sleep if we also want
|
||||
* to calculate/report flow.
|
||||
* http://www.mysensors.org/build/pulse_water
|
||||
*/
|
||||
|
||||
// Enable debug prints to serial monitor
|
||||
#define MY_DEBUG
|
||||
|
||||
// Enable and select radio type attached
|
||||
#define MY_RADIO_NRF24
|
||||
//#define MY_RADIO_RFM69
|
||||
|
||||
#include <MySensor.h>
|
||||
|
||||
#define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!)
|
||||
#define SENSOR_INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
|
||||
|
||||
#define PULSE_FACTOR 1000 // Nummber of blinks per m3 of your meter (One rotation/liter)
|
||||
|
||||
#define SLEEP_MODE false // flowvalue can only be reported when sleep mode is false.
|
||||
|
||||
#define MAX_FLOW 40 // Max flow (l/min) value to report. This filters outliers.
|
||||
|
||||
#define CHILD_ID 1 // Id of the sensor child
|
||||
|
||||
unsigned long SEND_FREQUENCY = 30000; // Minimum time between send (in milliseconds). We don't want to spam the gateway.
|
||||
|
||||
MyMessage flowMsg(CHILD_ID,V_FLOW);
|
||||
MyMessage volumeMsg(CHILD_ID,V_VOLUME);
|
||||
MyMessage lastCounterMsg(CHILD_ID,V_VAR1);
|
||||
|
||||
double ppl = ((double)PULSE_FACTOR)/1000; // Pulses per liter
|
||||
|
||||
volatile unsigned long pulseCount = 0;
|
||||
volatile unsigned long lastBlink = 0;
|
||||
volatile double flow = 0;
|
||||
boolean pcReceived = false;
|
||||
unsigned long oldPulseCount = 0;
|
||||
unsigned long newBlink = 0;
|
||||
double oldflow = 0;
|
||||
double volume =0;
|
||||
double oldvolume =0;
|
||||
unsigned long lastSend =0;
|
||||
unsigned long lastPulse =0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
setIncomingCallback(incomingMessage);
|
||||
|
||||
// initialize our digital pins internal pullup resistor so one pulse switches from high to low (less distortion)
|
||||
pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP);
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
sendSketchInfo("Water Meter", "1.1");
|
||||
|
||||
// Register this device as Waterflow sensor
|
||||
present(CHILD_ID, S_WATER);
|
||||
|
||||
pulseCount = oldPulseCount = 0;
|
||||
|
||||
// Fetch last known pulse count value from gw
|
||||
request(CHILD_ID, V_VAR1);
|
||||
|
||||
lastSend = lastPulse = millis();
|
||||
|
||||
attachInterrupt(SENSOR_INTERRUPT, onPulse, FALLING);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
// Only send values at a maximum frequency or woken up from sleep
|
||||
if (SLEEP_MODE || (currentTime - lastSend > SEND_FREQUENCY))
|
||||
{
|
||||
lastSend=currentTime;
|
||||
|
||||
if (!pcReceived) {
|
||||
//Last Pulsecount not yet received from controller, request it again
|
||||
request(CHILD_ID, V_VAR1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SLEEP_MODE && flow != oldflow) {
|
||||
oldflow = flow;
|
||||
|
||||
Serial.print("l/min:");
|
||||
Serial.println(flow);
|
||||
|
||||
// Check that we dont get unresonable large flow value.
|
||||
// could hapen when long wraps or false interrupt triggered
|
||||
if (flow<((unsigned long)MAX_FLOW)) {
|
||||
send(flowMsg.set(flow, 2)); // Send flow value to gw
|
||||
}
|
||||
}
|
||||
|
||||
// No Pulse count received in 2min
|
||||
if(currentTime - lastPulse > 120000){
|
||||
flow = 0;
|
||||
}
|
||||
|
||||
// Pulse count has changed
|
||||
if ((pulseCount != oldPulseCount)||(!SLEEP_MODE)) {
|
||||
oldPulseCount = pulseCount;
|
||||
|
||||
Serial.print("pulsecount:");
|
||||
Serial.println(pulseCount);
|
||||
|
||||
send(lastCounterMsg.set(pulseCount)); // Send pulsecount value to gw in VAR1
|
||||
|
||||
double volume = ((double)pulseCount/((double)PULSE_FACTOR));
|
||||
if ((volume != oldvolume)||(!SLEEP_MODE)) {
|
||||
oldvolume = volume;
|
||||
|
||||
Serial.print("volume:");
|
||||
Serial.println(volume, 3);
|
||||
|
||||
send(volumeMsg.set(volume, 3)); // Send volume value to gw
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SLEEP_MODE) {
|
||||
sleep(SEND_FREQUENCY);
|
||||
}
|
||||
}
|
||||
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
if (message.type==V_VAR1) {
|
||||
unsigned long gwPulseCount=message.getULong();
|
||||
pulseCount += gwPulseCount;
|
||||
flow=oldflow=0;
|
||||
Serial.print("Received last pulse count from gw:");
|
||||
Serial.println(pulseCount);
|
||||
pcReceived = true;
|
||||
}
|
||||
}
|
||||
|
||||
void onPulse()
|
||||
{
|
||||
if (!SLEEP_MODE)
|
||||
{
|
||||
unsigned long newBlink = micros();
|
||||
unsigned long interval = newBlink-lastBlink;
|
||||
|
||||
if (interval!=0)
|
||||
{
|
||||
lastPulse = millis();
|
||||
if (interval<500000L) {
|
||||
// Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min)
|
||||
return;
|
||||
}
|
||||
flow = (60000000.0 /interval) / ppl;
|
||||
}
|
||||
lastBlink = newBlink;
|
||||
}
|
||||
pulseCount++;
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
MyMessage KEYWORD1
|
||||
MySensor KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
setIncomingCallback KEYWORD2
|
||||
present KEYWORD2
|
||||
send KEYWORD2
|
||||
sendSketchInfo KEYWORD2
|
||||
sendBatteryLevel KEYWORD2
|
||||
sendHeartbeat KEYWORD2
|
||||
getNodeId KEYWORD2
|
||||
request KEYWORD2
|
||||
requestTime KEYWORD2
|
||||
saveState KEYWORD2
|
||||
loadState KEYWORD2
|
||||
wait KEYWORD2
|
||||
|
||||
######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
AUTO LITERAL1
|
||||
MY_DEBUG LITERAL1
|
||||
MY_REPEATER_FEATURE LITERAL1
|
||||
MY_RADIO_NRF24 LITERAL1
|
||||
MY_RADIO_RFM69 LITERAL1
|
||||
MY_BAUD_RATE LITERAL1
|
||||
MY_NODE_ID LITERAL1
|
||||
MY_PARENT_NODE_ID LITERAL1
|
||||
MY_OTA_FIRMWARE_FEATURE LITERAL1
|
||||
MY_OTA_FLASH_SS LITERAL1
|
||||
MY_OTA_FLASH_JDECID LITERAL1
|
||||
MY_LEDS_BLINKING_FEATURE LITERAL1
|
||||
WITH_LEDS_BLINKING_INVERSE LITERAL1
|
||||
MY_DEFAULT_LED_BLINK_PERIOD LITERAL1
|
||||
MY_WITH_LEDS_BLINKING_INVERSE LITERAL1
|
||||
MY_DEFAULT_RX_LED_PIN LITERAL1
|
||||
MY_DEFAULT_TX_LED_PIN LITERAL1
|
||||
MY_DEFAULT_ERR_LED_PIN LITERAL1
|
||||
MY_INCLUSION_MODE_FEATURE LITERAL1
|
||||
MY_INCLUSION_BUTTON_FEATURE LITERAL1
|
||||
MY_INCLUSION_MODE_BUTTON_PIN LITERAL1
|
||||
MY_INCLUSION_MODE_DURATION LITERAL1
|
||||
MY_SIGNING_ATSHA204 LITERAL1
|
||||
MY_SIGNING_SOFT LITERAL1
|
||||
MY_VERIFICATION_TIMEOUT_MS LITERAL1
|
||||
MY_SIGNING_NODE_WHITELIST LITERAL1
|
||||
MY_SIGNING_ATSHA204_PIN LITERAL1
|
||||
MY_SIGNING_SOFT_RANDOMSEED_PIN LITERAL1
|
||||
MY_SIGNING_SOFT_SERIAL LITERAL1
|
||||
MY_SIGNING_SOFT_HMAC_KEY LITERAL1
|
||||
MY_RF24_ENABLE_ENCRYPTION LITERAL1
|
||||
MY_RF24_ENCRYPTKEY LITERAL1
|
||||
MY_RF24_CE_PIN LITERAL1
|
||||
MY_RF24_CS_PIN LITERAL1
|
||||
MY_RF24_PA_LEVEL LITERAL1
|
||||
MY_RF24_CHANNEL LITERAL1
|
||||
MY_RF24_DATARATE LITERAL1
|
||||
MY_RF24_BASE_RADIO_ID LITERAL1
|
||||
MY_SOFTSPI LITERAL1
|
||||
MY_SOFT_SPI_SCK_PIN LITERAL1
|
||||
MY_SOFT_SPI_MISO_PIN LITERAL1
|
||||
MY_SOFT_SPI_MOSI_PIN LITERAL1
|
||||
MY_RFM69_FREQUENCY LITERAL1
|
||||
MY_RFM69_FREQUENCY LITERAL1
|
||||
MY_IS_RFM69HW LITERAL1
|
||||
MY_RFM69_NETWORKID LITERAL1
|
||||
MY_RF69_IRQ_PIN LITERAL1
|
||||
MY_RF69_SPI_CS LITERAL1
|
||||
MY_RF69_IRQ_NUM LITERAL1
|
||||
MY_RFM69_ENCRYPTKEY LITERAL1
|
||||
MY_GATEWAY_W5100 LITERAL1
|
||||
MY_GATEWAY_ENC28J60 LITERAL1
|
||||
MY_GATEWAY_ESP8266 LITERAL1
|
||||
MY_PORT LITERAL1
|
||||
MY_IP_ADDRESS LITERAL1
|
||||
MY_USE_UDP LITERAL1
|
||||
MY_IP_RENEWAL_INTERVAL LITERAL1
|
||||
MY_MAC_ADDRESS LITERAL1
|
||||
MY_CONTROLLER_IP_ADDRESS LITERAL1
|
||||
@@ -1,231 +0,0 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// Created by Tim Eckel - teckel@leethost.com
|
||||
// Copyright 2012 License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html
|
||||
//
|
||||
// See "NewPing.h" for purpose, syntax, version history, links, and more.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include "NewPing.h"
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// NewPing constructor
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
NewPing::NewPing(uint8_t trigger_pin, uint8_t echo_pin, int max_cm_distance) {
|
||||
_triggerBit = digitalPinToBitMask(trigger_pin); // Get the port register bitmask for the trigger pin.
|
||||
_echoBit = digitalPinToBitMask(echo_pin); // Get the port register bitmask for the echo pin.
|
||||
|
||||
_triggerOutput = portOutputRegister(digitalPinToPort(trigger_pin)); // Get the output port register for the trigger pin.
|
||||
_echoInput = portInputRegister(digitalPinToPort(echo_pin)); // Get the input port register for the echo pin.
|
||||
|
||||
_triggerMode = (uint8_t *) portModeRegister(digitalPinToPort(trigger_pin)); // Get the port mode register for the trigger pin.
|
||||
|
||||
_maxEchoTime = min(max_cm_distance, MAX_SENSOR_DISTANCE) * US_ROUNDTRIP_CM + (US_ROUNDTRIP_CM / 2); // Calculate the maximum distance in uS.
|
||||
|
||||
#if DISABLE_ONE_PIN == true
|
||||
*_triggerMode |= _triggerBit; // Set trigger pin to output.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Standard ping methods
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
unsigned int NewPing::ping() {
|
||||
if (!ping_trigger()) return NO_ECHO; // Trigger a ping, if it returns false, return NO_ECHO to the calling function.
|
||||
while (*_echoInput & _echoBit) // Wait for the ping echo.
|
||||
if (micros() > _max_time) return NO_ECHO; // Stop the loop and return NO_ECHO (false) if we're beyond the set maximum distance.
|
||||
return (micros() - (_max_time - _maxEchoTime) - 5); // Calculate ping time, 5uS of overhead.
|
||||
}
|
||||
|
||||
|
||||
unsigned int NewPing::ping_in() {
|
||||
unsigned int echoTime = NewPing::ping(); // Calls the ping method and returns with the ping echo distance in uS.
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_IN); // Convert uS to inches.
|
||||
}
|
||||
|
||||
|
||||
unsigned int NewPing::ping_cm() {
|
||||
unsigned int echoTime = NewPing::ping(); // Calls the ping method and returns with the ping echo distance in uS.
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters.
|
||||
}
|
||||
|
||||
|
||||
unsigned int NewPing::ping_median(uint8_t it) {
|
||||
unsigned int uS[it], last;
|
||||
uint8_t j, i = 0;
|
||||
uS[0] = NO_ECHO;
|
||||
while (i < it) {
|
||||
last = ping(); // Send ping.
|
||||
if (last == NO_ECHO) { // Ping out of range.
|
||||
it--; // Skip, don't include as part of median.
|
||||
last = _maxEchoTime; // Adjust "last" variable so delay is correct length.
|
||||
} else { // Ping in range, include as part of median.
|
||||
if (i > 0) { // Don't start sort till second ping.
|
||||
for (j = i; j > 0 && uS[j - 1] < last; j--) // Insertion sort loop.
|
||||
uS[j] = uS[j - 1]; // Shift ping array to correct position for sort insertion.
|
||||
} else j = 0; // First ping is starting point for sort.
|
||||
uS[j] = last; // Add last ping to array in sorted position.
|
||||
i++; // Move to next ping.
|
||||
}
|
||||
if (i < it) delay(PING_MEDIAN_DELAY - (last >> 10)); // Millisecond delay between pings.
|
||||
}
|
||||
return (uS[it >> 1]); // Return the ping distance median.
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Standard ping method support functions (not called directly)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
boolean NewPing::ping_trigger() {
|
||||
#if DISABLE_ONE_PIN != true
|
||||
*_triggerMode |= _triggerBit; // Set trigger pin to output.
|
||||
#endif
|
||||
*_triggerOutput &= ~_triggerBit; // Set the trigger pin low, should already be low, but this will make sure it is.
|
||||
delayMicroseconds(4); // Wait for pin to go low, testing shows it needs 4uS to work every time.
|
||||
*_triggerOutput |= _triggerBit; // Set trigger pin high, this tells the sensor to send out a ping.
|
||||
delayMicroseconds(10); // Wait long enough for the sensor to realize the trigger pin is high. Sensor specs say to wait 10uS.
|
||||
*_triggerOutput &= ~_triggerBit; // Set trigger pin back to low.
|
||||
#if DISABLE_ONE_PIN != true
|
||||
*_triggerMode &= ~_triggerBit; // Set trigger pin to input (when using one Arduino pin this is technically setting the echo pin to input as both are tied to the same Arduino pin).
|
||||
#endif
|
||||
|
||||
_max_time = micros() + MAX_SENSOR_DELAY; // Set a timeout for the ping to trigger.
|
||||
while (*_echoInput & _echoBit && micros() <= _max_time) {} // Wait for echo pin to clear.
|
||||
while (!(*_echoInput & _echoBit)) // Wait for ping to start.
|
||||
if (micros() > _max_time) return false; // Something went wrong, abort.
|
||||
|
||||
_max_time = micros() + _maxEchoTime; // Ping started, set the timeout.
|
||||
return true; // Ping started successfully.
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Timer interrupt ping methods (won't work with ATmega8 and ATmega128)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void NewPing::ping_timer(void (*userFunc)(void)) {
|
||||
if (!ping_trigger()) return; // Trigger a ping, if it returns false, return without starting the echo timer.
|
||||
timer_us(ECHO_TIMER_FREQ, userFunc); // Set ping echo timer check every ECHO_TIMER_FREQ uS.
|
||||
}
|
||||
|
||||
|
||||
boolean NewPing::check_timer() {
|
||||
if (micros() > _max_time) { // Outside the timeout limit.
|
||||
timer_stop(); // Disable timer interrupt
|
||||
return false; // Cancel ping timer.
|
||||
}
|
||||
|
||||
if (!(*_echoInput & _echoBit)) { // Ping echo received.
|
||||
timer_stop(); // Disable timer interrupt
|
||||
ping_result = (micros() - (_max_time - _maxEchoTime) - 13); // Calculate ping time, 13uS of overhead.
|
||||
return true; // Return ping echo true.
|
||||
}
|
||||
|
||||
return false; // Return false because there's no ping echo yet.
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Timer2/Timer4 interrupt methods (can be used for non-ultrasonic needs)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Variables used for timer functions
|
||||
void (*intFunc)();
|
||||
void (*intFunc2)();
|
||||
unsigned long _ms_cnt_reset;
|
||||
volatile unsigned long _ms_cnt;
|
||||
|
||||
|
||||
void NewPing::timer_us(unsigned int frequency, void (*userFunc)(void)) {
|
||||
timer_setup(); // Configure the timer interrupt.
|
||||
intFunc = userFunc; // User's function to call when there's a timer event.
|
||||
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
OCR4C = min((frequency>>2) - 1, 255); // Every count is 4uS, so divide by 4 (bitwise shift right 2) subtract one, then make sure we don't go over 255 limit.
|
||||
TIMSK4 = (1<<TOIE4); // Enable Timer4 interrupt.
|
||||
#else
|
||||
OCR2A = min((frequency>>2) - 1, 255); // Every count is 4uS, so divide by 4 (bitwise shift right 2) subtract one, then make sure we don't go over 255 limit.
|
||||
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 interrupt.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_ms(unsigned long frequency, void (*userFunc)(void)) {
|
||||
timer_setup(); // Configure the timer interrupt.
|
||||
intFunc = NewPing::timer_ms_cntdwn; // Timer events are sent here once every ms till user's frequency is reached.
|
||||
intFunc2 = userFunc; // User's function to call when user's frequency is reached.
|
||||
_ms_cnt = _ms_cnt_reset = frequency; // Current ms counter and reset value.
|
||||
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
OCR4C = 249; // Every count is 4uS, so 1ms = 250 counts - 1.
|
||||
TIMSK4 = (1<<TOIE4); // Enable Timer4 interrupt.
|
||||
#else
|
||||
OCR2A = 249; // Every count is 4uS, so 1ms = 250 counts - 1.
|
||||
TIMSK2 |= (1<<OCIE2A); // Enable Timer2 interrupt.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_stop() { // Disable timer interrupt.
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
TIMSK4 = 0;
|
||||
#else
|
||||
TIMSK2 &= ~(1<<OCIE2A);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Timer2/Timer4 interrupt method support functions (not called directly)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void NewPing::timer_setup() {
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
timer_stop(); // Disable Timer4 interrupt.
|
||||
TCCR4A = TCCR4C = TCCR4D = TCCR4E = 0;
|
||||
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<CS40) | (1<<PSR4); // Set Timer4 prescaler to 64 (4uS/count, 4uS-1020uS range).
|
||||
TIFR4 = (1<<TOV4);
|
||||
TCNT4 = 0; // Reset Timer4 counter.
|
||||
#else
|
||||
timer_stop(); // Disable Timer2 interrupt.
|
||||
ASSR &= ~(1<<AS2); // Set clock, not pin.
|
||||
TCCR2A = (1<<WGM21); // Set Timer2 to CTC mode.
|
||||
TCCR2B = (1<<CS22); // Set Timer2 prescaler to 64 (4uS/count, 4uS-1020uS range).
|
||||
TCNT2 = 0; // Reset Timer2 counter.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NewPing::timer_ms_cntdwn() {
|
||||
if (!_ms_cnt--) { // Count down till we reach zero.
|
||||
intFunc2(); // Scheduled time reached, run the main timer event function.
|
||||
_ms_cnt = _ms_cnt_reset; // Reset the ms timer.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined (__AVR_ATmega32U4__) // Use Timer4 for ATmega32U4 (Teensy/Leonardo).
|
||||
ISR(TIMER4_OVF_vect) {
|
||||
#else
|
||||
ISR(TIMER2_COMPA_vect) {
|
||||
#endif
|
||||
if(intFunc) intFunc(); // If wrapped function is set, call it.
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Conversion methods (rounds result to nearest inch or cm).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
unsigned int NewPing::convert_in(unsigned int echoTime) {
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_IN); // Convert uS to inches.
|
||||
}
|
||||
|
||||
|
||||
unsigned int NewPing::convert_cm(unsigned int echoTime) {
|
||||
return NewPingConvert(echoTime, US_ROUNDTRIP_CM); // Convert uS to centimeters.
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// NewPing Library - v1.5 - 08/15/2012
|
||||
//
|
||||
// AUTHOR/LICENSE:
|
||||
// Created by Tim Eckel - teckel@leethost.com
|
||||
// Copyright 2012 License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html
|
||||
//
|
||||
// LINKS:
|
||||
// Project home: http://code.google.com/p/arduino-new-ping/
|
||||
// Blog: http://arduino.cc/forum/index.php/topic,106043.0.html
|
||||
//
|
||||
// DISCLAIMER:
|
||||
// This software is furnished "as is", without technical support, and with no
|
||||
// warranty, express or implied, as to its usefulness for any purpose.
|
||||
//
|
||||
// BACKGROUND:
|
||||
// When I first received an ultrasonic sensor I was not happy with how poorly
|
||||
// it worked. Quickly I realized the problem wasn't the sensor, it was the
|
||||
// available ping and ultrasonic libraries causing the problem. The NewPing
|
||||
// library totally fixes these problems, adds many new features, and breaths
|
||||
// new life into these very affordable distance sensors.
|
||||
//
|
||||
// FEATURES:
|
||||
// * Works with many different ultrasonic sensor models: SR04, SRF05, SRF06, DYP-ME007 & Parallax PING)))™.
|
||||
// * Interface with all but the SRF06 sensor using only one Arduino pin.
|
||||
// * Doesn't lag for a full second if no ping/echo is received.
|
||||
// * Ping sensors consistently and reliably at up to 30 times per second.
|
||||
// * Timer interrupt method for event-driven sketches.
|
||||
// * Built-in digital filter method ping_median() for easy error correction.
|
||||
// * Uses port registers for a faster pin interface and smaller code size.
|
||||
// * Allows you to set a maximum distance where pings beyond that distance are read as no ping "clear".
|
||||
// * Ease of using multiple sensors (example sketch with 15 sensors).
|
||||
// * More accurate distance calculation (cm, inches & uS).
|
||||
// * Doesn't use pulseIn, which is slow and gives incorrect results with some ultrasonic sensor models.
|
||||
// * Actively developed with features being added and bugs/issues addressed.
|
||||
//
|
||||
// CONSTRUCTOR:
|
||||
// NewPing sonar(trigger_pin, echo_pin [, max_cm_distance])
|
||||
// trigger_pin & echo_pin - Arduino pins connected to sensor trigger and echo.
|
||||
// NOTE: To use the same Arduino pin for trigger and echo, specify the same pin for both values.
|
||||
// max_cm_distance - [Optional] Maximum distance you wish to sense. Default=500cm.
|
||||
//
|
||||
// SYNTAX:
|
||||
// sonar.ping() - Send a ping and get the echo time (in microseconds) as a result.
|
||||
// sonar.ping_in() - Send a ping and get the distance in whole inches.
|
||||
// sonar.ping_cm() - Send a ping and get the distance in whole centimeters.
|
||||
// sonar.ping_median(iterations) - Do multiple pings (default=5), discard out of range pings and return median in microseconds.
|
||||
// sonar.convert_in(echoTime) - Convert echoTime from microseconds to inches (rounds to nearest inch).
|
||||
// sonar.convert_cm(echoTime) - Convert echoTime from microseconds to centimeters (rounds to nearest cm).
|
||||
// sonar.ping_timer(function) - Send a ping and call function to test if ping is complete.
|
||||
// sonar.check_timer() - Check if ping has returned within the set distance limit.
|
||||
// NewPing::timer_us(frequency, function) - Call function every frequency microseconds.
|
||||
// NewPing::timer_ms(frequency, function) - Call function every frequency milliseconds.
|
||||
// NewPing::timer_stop() - Stop the timer.
|
||||
//
|
||||
// HISTORY:
|
||||
// 08/15/2012 v1.5 - Added ping_median() method which does a user specified
|
||||
// number of pings (default=5) and returns the median ping in microseconds
|
||||
// (out of range pings ignored). This is a very effective digital filter.
|
||||
// Optimized for smaller compiled size (even smaller than skteches that
|
||||
// don't use a library).
|
||||
//
|
||||
// 07/14/2012 v1.4 - Added support for the Parallax PING)))™ sensor. Interface
|
||||
// with all but the SRF06 sensor using only one Arduino pin. You can also
|
||||
// interface with the SRF06 using one pin if you install a 0.1uf capacitor
|
||||
// on the trigger and echo pins of the sensor then tie the trigger pin to
|
||||
// the Arduino pin (doesn't work with Teensy). To use the same Arduino pin
|
||||
// for trigger and echo, specify the same pin for both values. Various bug
|
||||
// fixes.
|
||||
//
|
||||
// 06/08/2012 v1.3 - Big feature addition, event-driven ping! Uses Timer2
|
||||
// interrupt, so be mindful of PWM or timing conflicts messing with Timer2
|
||||
// may cause (namely PWM on pins 3 & 11 on Arduino, PWM on pins 9 and 10 on
|
||||
// Mega, and Tone library). Simple to use timer interrupt functions you can
|
||||
// use in your sketches totaly unrelated to ultrasonic sensors (don't use if
|
||||
// you're also using NewPing's ping_timer because both use Timer2 interrupts).
|
||||
// Loop counting ping method deleted in favor of timing ping method after
|
||||
// inconsistant results kept surfacing with the loop timing ping method.
|
||||
// Conversion to cm and inches now rounds to the nearest cm or inch. Code
|
||||
// optimized to save program space and fixed a couple minor bugs here and
|
||||
// there. Many new comments added as well as line spacing to group code
|
||||
// sections for better source readability.
|
||||
//
|
||||
// 05/25/2012 v1.2 - Lots of code clean-up thanks to Adruino Forum members.
|
||||
// Rebuilt the ping timing code from scratch, ditched the pulseIn code as it
|
||||
// doesn't give correct results (at least with ping sensors). The NewPing
|
||||
// library is now VERY accurate and the code was simplified as a bonus.
|
||||
// Smaller and faster code as well. Fixed some issues with very close ping
|
||||
// results when converting to inches. All functions now return 0 only when
|
||||
// there's no ping echo (out of range) and a positive value for a successful
|
||||
// ping. This can effectively be used to detect if something is out of range
|
||||
// or in-range and at what distance. Now compatible with Arduino 0023.
|
||||
//
|
||||
// 05/16/2012 v1.1 - Changed all I/O functions to use low-level port registers
|
||||
// for ultra-fast and lean code (saves from 174 to 394 bytes). Tested on both
|
||||
// the Arduino Uno and Teensy 2.0 but should work on all Arduino-based
|
||||
// platforms because it calls standard functions to retrieve port registers
|
||||
// and bit masks. Also made a couple minor fixes to defines.
|
||||
//
|
||||
// 05/15/2012 v1.0 - Initial release.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#ifndef NewPing_h
|
||||
#define NewPing_h
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <pins_arduino.h>
|
||||
#endif
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
// Shoudln't need to changed these values unless you have a specific need to do so.
|
||||
#define MAX_SENSOR_DISTANCE 500 // Maximum sensor distance can be as high as 500cm, no reason to wait for ping longer than sound takes to travel this distance and back.
|
||||
#define US_ROUNDTRIP_IN 146 // Microseconds (uS) it takes sound to travel round-trip 1 inch (2 inches total), uses integer to save compiled code space.
|
||||
#define US_ROUNDTRIP_CM 57 // Microseconds (uS) it takes sound to travel round-trip 1cm (2cm total), uses integer to save compiled code space.
|
||||
#define DISABLE_ONE_PIN false // Set to "true" to save up to 26 bytes of compiled code space if you're not using one pin sensor connections.
|
||||
|
||||
// Probably shoudln't change these values unless you really know what you're doing.
|
||||
#define NO_ECHO 0 // Value returned if there's no ping echo within the specified MAX_SENSOR_DISTANCE or max_cm_distance.
|
||||
#define MAX_SENSOR_DELAY 18000 // Maximum uS it takes for sensor to start the ping (SRF06 is the highest measured, just under 18ms).
|
||||
#define ECHO_TIMER_FREQ 24 // Frequency to check for a ping echo (every 24uS is about 0.4cm accuracy).
|
||||
#define PING_MEDIAN_DELAY 29 // Millisecond delay between pings in the ping_median method.
|
||||
|
||||
// Conversion from uS to distance (round result to nearest cm or inch).
|
||||
#define NewPingConvert(echoTime, conversionFactor) (max((echoTime + conversionFactor / 2) / conversionFactor, (echoTime ? 1 : 0)))
|
||||
|
||||
|
||||
class NewPing {
|
||||
public:
|
||||
NewPing(uint8_t trigger_pin, uint8_t echo_pin, int max_cm_distance = MAX_SENSOR_DISTANCE);
|
||||
unsigned int ping();
|
||||
unsigned int ping_in();
|
||||
unsigned int ping_cm();
|
||||
unsigned int ping_median(uint8_t it = 5);
|
||||
unsigned int convert_in(unsigned int echoTime);
|
||||
unsigned int convert_cm(unsigned int echoTime);
|
||||
void ping_timer(void (*userFunc)(void));
|
||||
boolean check_timer();
|
||||
unsigned long ping_result;
|
||||
static void timer_us(unsigned int frequency, void (*userFunc)(void));
|
||||
static void timer_ms(unsigned long frequency, void (*userFunc)(void));
|
||||
static void timer_stop();
|
||||
private:
|
||||
boolean ping_trigger();
|
||||
boolean ping_wait_timer();
|
||||
uint8_t _triggerBit;
|
||||
uint8_t _echoBit;
|
||||
volatile uint8_t *_triggerOutput;
|
||||
volatile uint8_t *_triggerMode;
|
||||
volatile uint8_t *_echoInput;
|
||||
unsigned int _maxEchoTime;
|
||||
unsigned long _max_time;
|
||||
static void timer_setup();
|
||||
static void timer_ms_cntdwn();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,74 +0,0 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// This example code was used to successfully communicate with 15 ultrasonic sensors. You can adjust
|
||||
// the number of sensors in your project by changing SONAR_NUM and the number of NewPing objects in the
|
||||
// "sonar" array. You also need to change the pins for each sensor for the NewPing objects. Each sensor
|
||||
// is pinged at 33ms intervals. So, one cycle of all sensors takes 495ms (33 * 15 = 495ms). The results
|
||||
// are sent to the "oneSensorCycle" function which currently just displays the distance data. Your project
|
||||
// would normally process the sensor results in this function (for example, decide if a robot needs to
|
||||
// turn and call the turn function). Keep in mind this example is event-driven. Your complete sketch needs
|
||||
// to be written so there's no "delay" commands and the loop() cycles at faster than a 33ms rate. If other
|
||||
// processes take longer than 33ms, you'll need to increase PING_INTERVAL so it doesn't get behind.
|
||||
// ---------------------------------------------------------------------------
|
||||
#include <NewPing.h>
|
||||
|
||||
#define SONAR_NUM 15 // Number or sensors.
|
||||
#define MAX_DISTANCE 200 // Maximum distance (in cm) to ping.
|
||||
#define PING_INTERVAL 33 // Milliseconds between sensor pings (29ms is about the min to avoid cross-sensor echo).
|
||||
|
||||
unsigned long pingTimer[SONAR_NUM]; // Holds the times when the next ping should happen for each sensor.
|
||||
unsigned int cm[SONAR_NUM]; // Where the ping distances are stored.
|
||||
uint8_t currentSensor = 0; // Keeps track of which sensor is active.
|
||||
|
||||
NewPing sonar[SONAR_NUM] = { // Sensor object array.
|
||||
NewPing(41, 42, MAX_DISTANCE), // Each sensor's trigger pin, echo pin, and max distance to ping.
|
||||
NewPing(43, 44, MAX_DISTANCE),
|
||||
NewPing(45, 20, MAX_DISTANCE),
|
||||
NewPing(21, 22, MAX_DISTANCE),
|
||||
NewPing(23, 24, MAX_DISTANCE),
|
||||
NewPing(25, 26, MAX_DISTANCE),
|
||||
NewPing(27, 28, MAX_DISTANCE),
|
||||
NewPing(29, 30, MAX_DISTANCE),
|
||||
NewPing(31, 32, MAX_DISTANCE),
|
||||
NewPing(34, 33, MAX_DISTANCE),
|
||||
NewPing(35, 36, MAX_DISTANCE),
|
||||
NewPing(37, 38, MAX_DISTANCE),
|
||||
NewPing(39, 40, MAX_DISTANCE),
|
||||
NewPing(50, 51, MAX_DISTANCE),
|
||||
NewPing(52, 53, MAX_DISTANCE)
|
||||
};
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
pingTimer[0] = millis() + 75; // First ping starts at 75ms, gives time for the Arduino to chill before starting.
|
||||
for (uint8_t i = 1; i < SONAR_NUM; i++) // Set the starting time for each sensor.
|
||||
pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
for (uint8_t i = 0; i < SONAR_NUM; i++) { // Loop through all the sensors.
|
||||
if (millis() >= pingTimer[i]) { // Is it this sensor's time to ping?
|
||||
pingTimer[i] += PING_INTERVAL * SONAR_NUM; // Set next time this sensor will be pinged.
|
||||
if (i == 0 && currentSensor == SONAR_NUM - 1) oneSensorCycle(); // Sensor ping cycle complete, do something with the results.
|
||||
sonar[currentSensor].timer_stop(); // Make sure previous timer is canceled before starting a new ping (insurance).
|
||||
currentSensor = i; // Sensor being accessed.
|
||||
cm[currentSensor] = 0; // Make distance zero in case there's no ping echo for this sensor.
|
||||
sonar[currentSensor].ping_timer(echoCheck); // Do the ping (processing continues, interrupt will call echoCheck to look for echo).
|
||||
}
|
||||
}
|
||||
// The rest of your code would go here.
|
||||
}
|
||||
|
||||
void echoCheck() { // If ping received, set the sensor distance to array.
|
||||
if (sonar[currentSensor].check_timer())
|
||||
cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
|
||||
}
|
||||
|
||||
void oneSensorCycle() { // Sensor ping cycle complete, do something with the results.
|
||||
for (uint8_t i = 0; i < SONAR_NUM; i++) {
|
||||
Serial.print(i);
|
||||
Serial.print("=");
|
||||
Serial.print(cm[i]);
|
||||
Serial.print("cm ");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// This example shows how to use NewPing's ping_timer method which uses the Timer2 interrupt to get the
|
||||
// ping time. The advantage of using this method over the standard ping method is that it permits a more
|
||||
// event-driven sketch which allows you to appear to do two things at once. An example would be to ping
|
||||
// an ultrasonic sensor for a possible collision while at the same time navigating. This allows a
|
||||
// properly developed sketch to multitask. Be aware that because the ping_timer method uses Timer2,
|
||||
// other features or libraries that also use Timer2 would be effected. For example, the PWM function on
|
||||
// pins 3 & 11 on Arduino Uno (pins 9 and 11 on Arduino Mega) and the Tone library. Note, only the PWM
|
||||
// functionality of the pins is lost (as they use Timer2 to do PWM), the pins are still available to use.
|
||||
// NOTE: For Teensy/Leonardo (ATmega32U4) the library uses Timer4 instead of Timer2.
|
||||
// ---------------------------------------------------------------------------
|
||||
#include <NewPing.h>
|
||||
|
||||
#define TRIGGER_PIN 12 // Arduino pin tied to trigger pin on ping sensor.
|
||||
#define ECHO_PIN 11 // Arduino pin tied to echo pin on ping sensor.
|
||||
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
|
||||
|
||||
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
|
||||
|
||||
unsigned int pingSpeed = 50; // How frequently are we going to send out a ping (in milliseconds). 50ms would be 20 times a second.
|
||||
unsigned long pingTimer; // Holds the next ping time.
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
|
||||
pingTimer = millis(); // Start now.
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Notice how there's no delays in this sketch to allow you to do other processing in-line while doing distance pings.
|
||||
if (millis() >= pingTimer) { // pingSpeed milliseconds since last ping, do another ping.
|
||||
pingTimer += pingSpeed; // Set the next ping time.
|
||||
sonar.ping_timer(echoCheck); // Send out the ping, calls "echoCheck" function every 24uS where you can check the ping status.
|
||||
}
|
||||
// Do other stuff here, really. Think of it as multi-tasking.
|
||||
}
|
||||
|
||||
void echoCheck() { // Timer2 interrupt calls this function every 24uS where you can check the ping status.
|
||||
// Don't do anything here!
|
||||
if (sonar.check_timer()) { // This is how you check to see if the ping was received.
|
||||
// Here's where you can add code.
|
||||
Serial.print("Ping: ");
|
||||
Serial.print(sonar.ping_result / US_ROUNDTRIP_CM); // Ping returned, uS result in ping_result, convert to cm with US_ROUNDTRIP_CM.
|
||||
Serial.println("cm");
|
||||
}
|
||||
// Don't do anything here!
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// Example NewPing library sketch that does a ping about 20 times per second.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include <NewPing.h>
|
||||
|
||||
#define TRIGGER_PIN 12 // Arduino pin tied to trigger pin on the ultrasonic sensor.
|
||||
#define ECHO_PIN 11 // Arduino pin tied to echo pin on the ultrasonic sensor.
|
||||
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
|
||||
|
||||
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
|
||||
}
|
||||
|
||||
void loop() {
|
||||
delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
|
||||
unsigned int uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
|
||||
Serial.print("Ping: ");
|
||||
Serial.print(uS / US_ROUNDTRIP_CM); // Convert ping time to distance in cm and print result (0 = outside set distance range)
|
||||
Serial.println("cm");
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// While the NewPing library's primary goal is to interface with ultrasonic sensors, interfacing with
|
||||
// the Timer2 interrupt was a result of creating an interrupt-based ping method. Since these Timer2
|
||||
// interrupt methods were built, the library may as well provide the functionality to use these methods
|
||||
// in your sketches. This shows how simple it is (no ultrasonic sensor required). Keep in mind that
|
||||
// these methods use Timer2, as does NewPing's ping_timer method for using ultrasonic sensors. You
|
||||
// can't use ping_timer at the same time you're using timer_ms or timer_us as all use the same timer.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#include <NewPing.h>
|
||||
|
||||
#define LED_PIN 13 // Pin with LED attached.
|
||||
|
||||
void setup() {
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
NewPing::timer_ms(500, toggleLED); // Create a Timer2 interrupt that calls toggleLED in your sketch once every 500 milliseconds.
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Do anything here, the Timer2 interrupt will take care of the flashing LED without your intervention.
|
||||
}
|
||||
|
||||
void toggleLED() {
|
||||
digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Toggle the LED.
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
###################################
|
||||
# Syntax Coloring Map For NewPing
|
||||
###################################
|
||||
|
||||
###################################
|
||||
# Datatypes (KEYWORD1)
|
||||
###################################
|
||||
|
||||
NewPing KEYWORD1
|
||||
|
||||
###################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
###################################
|
||||
|
||||
ping KEYWORD2
|
||||
ping_in KEYWORD2
|
||||
ping_cm KEYWORD2
|
||||
ping_median KEYWORD2
|
||||
ping_timer KEYWORD2
|
||||
check_timer KEYWORD2
|
||||
timer_us KEYWORD2
|
||||
timer_ms KEYWORD2
|
||||
timer_stop KEYWORD2
|
||||
convert_in KEYWORD2
|
||||
convert_cm KEYWORD2
|
||||
|
||||
###################################
|
||||
# Constants (LITERAL1)
|
||||
###################################
|
||||
@@ -1,318 +0,0 @@
|
||||
/*
|
||||
* NewRemoteSwitch library v1.1.0 (20130601) made by Randy Simons http://randysimons.nl/
|
||||
* See NewRemoteReceiver.h for details.
|
||||
*
|
||||
* License: GPLv3. See license.txt
|
||||
*/
|
||||
|
||||
#include "NewRemoteReceiver.h"
|
||||
|
||||
|
||||
/************
|
||||
* NewRemoteReceiver
|
||||
|
||||
Protocol. (Copied from Wieltje, http://www.circuitsonline.net/forum/view/message/1181410#1181410,
|
||||
but with slightly different timings, as measured on my device.)
|
||||
_ _
|
||||
'0': | |_| |_____ (T,T,T,5T)
|
||||
_ _
|
||||
'1': | |_____| |_ (T,5T,T,T)
|
||||
_ _
|
||||
dim: | |_| |_ (T,T,T,T)
|
||||
|
||||
T = short period of ~260µs. However, this code tries
|
||||
to figure out the correct period
|
||||
|
||||
A full frame looks like this:
|
||||
|
||||
- start pulse: 1T high, 10.44T low
|
||||
- 26 bit: Address
|
||||
- 1 bit: group bit
|
||||
- 1 bit: on/off/[dim]
|
||||
- 4 bit: unit
|
||||
- [4 bit: dim level. Only present of [dim] is chosen]
|
||||
- stop pulse: 1T high, 40T low
|
||||
|
||||
************/
|
||||
|
||||
int8_t NewRemoteReceiver::_interrupt;
|
||||
volatile short NewRemoteReceiver::_state;
|
||||
byte NewRemoteReceiver::_minRepeats;
|
||||
NewRemoteReceiverCallBack NewRemoteReceiver::_callback;
|
||||
boolean NewRemoteReceiver::_inCallback = false;
|
||||
boolean NewRemoteReceiver::_enabled = false;
|
||||
|
||||
void NewRemoteReceiver::init(int8_t interrupt, byte minRepeats, NewRemoteReceiverCallBack callback) {
|
||||
_interrupt = interrupt;
|
||||
_minRepeats = minRepeats;
|
||||
_callback = callback;
|
||||
|
||||
enable();
|
||||
if (_interrupt >= 0) {
|
||||
attachInterrupt(_interrupt, interruptHandler, CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteReceiver::enable() {
|
||||
_state = -1;
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
void NewRemoteReceiver::disable() {
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
void NewRemoteReceiver::deinit() {
|
||||
_enabled = false;
|
||||
if (_interrupt >= 0) {
|
||||
detachInterrupt(_interrupt);
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteReceiver::interruptHandler() {
|
||||
// This method is written as compact code to keep it fast. While breaking up this method into more
|
||||
// methods would certainly increase the readability, it would also be much slower to execute.
|
||||
// Making calls to other methods is quite expensive on AVR. As These interrupt handlers are called
|
||||
// many times a second, calling other methods should be kept to a minimum.
|
||||
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
static byte receivedBit; // Contains "bit" currently receiving
|
||||
static NewRemoteCode receivedCode; // Contains received code
|
||||
static NewRemoteCode previousCode; // Contains previous received code
|
||||
static byte repeats = 0; // The number of times the an identical code is received in a row.
|
||||
static unsigned long edgeTimeStamp[3] = {0, }; // Timestamp of edges
|
||||
static unsigned int min1Period, max1Period, min5Period, max5Period;
|
||||
static bool skip;
|
||||
|
||||
// Filter out too short pulses. This method works as a low pass filter.
|
||||
edgeTimeStamp[1] = edgeTimeStamp[2];
|
||||
edgeTimeStamp[2] = micros();
|
||||
|
||||
if (skip) {
|
||||
skip = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_state >= 0 && edgeTimeStamp[2]-edgeTimeStamp[1] < min1Period) {
|
||||
// Last edge was too short.
|
||||
// Skip this edge, and the next too.
|
||||
skip = true;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int duration = edgeTimeStamp[1] - edgeTimeStamp[0];
|
||||
edgeTimeStamp[0] = edgeTimeStamp[1];
|
||||
|
||||
// Note that if state>=0, duration is always >= 1 period.
|
||||
|
||||
if (_state == -1) {
|
||||
// wait for the long low part of a stop bit.
|
||||
// Stopbit: 1T high, 40T low
|
||||
// By default 1T is 260µs, but for maximum compatibility go as low as 120µs
|
||||
if (duration > 4800) { // =40*120µs, minimal time between two edges before decoding starts.
|
||||
// Sync signal received.. Preparing for decoding
|
||||
repeats = 0;
|
||||
|
||||
receivedCode.period = duration / 40; // Measured signal is 40T, so 1T (period) is measured signal / 40.
|
||||
|
||||
// Allow for large error-margin. ElCheapo-hardware :(
|
||||
min1Period = receivedCode.period * 3 / 10; // Lower limit for 1 period is 0.3 times measured period; high signals can "linger" a bit sometimes, making low signals quite short.
|
||||
max1Period = receivedCode.period * 3; // Upper limit for 1 period is 3 times measured period
|
||||
min5Period = receivedCode.period * 3; // Lower limit for 5 periods is 3 times measured period
|
||||
max5Period = receivedCode.period * 8; // Upper limit for 5 periods is 8 times measured period
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
} else if (_state == 0) { // Verify start bit part 1 of 2
|
||||
// Duration must be ~1T
|
||||
if (duration > max1Period) {
|
||||
_state = -1;
|
||||
return;
|
||||
}
|
||||
// Start-bit passed. Do some clean-up.
|
||||
receivedCode.address = receivedCode.unit = receivedCode.dimLevel = 0;
|
||||
} else if (_state == 1) { // Verify start bit part 2 of 2
|
||||
// Duration must be ~10.44T
|
||||
if (duration < 7 * receivedCode.period || duration > 15 * receivedCode.period) {
|
||||
_state = -1;
|
||||
return;
|
||||
}
|
||||
} else if (_state < 148) { // state 146 is first edge of stop-sequence. All bits before that adhere to default protocol, with exception of dim-bit
|
||||
receivedBit <<= 1;
|
||||
|
||||
// One bit consists out of 4 bit parts.
|
||||
// bit part durations can ONLY be 1 or 5 periods.
|
||||
if (duration <= max1Period) {
|
||||
receivedBit &= B1110; // Clear LSB of receivedBit
|
||||
} else if (duration >= min5Period && duration <= max5Period) {
|
||||
receivedBit |= B1; // Set LSB of receivedBit
|
||||
} else if (
|
||||
// Check if duration matches the second part of stopbit (duration must be ~40T), and ...
|
||||
(duration >= 20 * receivedCode.period && duration <= 80 * receivedCode.period) &&
|
||||
// if first part op stopbit was a short signal (short signal yielded a 0 as second bit in receivedBit), and ...
|
||||
((receivedBit & B10) == B00) &&
|
||||
// we are in a state in which a stopbit is actually valid, only then ...
|
||||
(_state == 147 || _state == 131) ) {
|
||||
// If a dim-level was present...
|
||||
if (_state == 147) {
|
||||
// ... test if it was an "on" signal ...
|
||||
if (receivedCode.switchType == NewRemoteCode::on) {
|
||||
// ... set the appropriate switch type
|
||||
receivedCode.switchType = NewRemoteCode::on_with_dim;
|
||||
} else {
|
||||
// ... otherwise it was wrong (e.g. off-signal with dim)
|
||||
_state = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// a valid signal was found!
|
||||
if (
|
||||
receivedCode.address != previousCode.address ||
|
||||
receivedCode.unit != previousCode.unit ||
|
||||
receivedCode.dimLevel != previousCode.dimLevel ||
|
||||
receivedCode.groupBit != previousCode.groupBit ||
|
||||
receivedCode.switchType != previousCode.switchType
|
||||
) { // memcmp isn't deemed safe
|
||||
repeats=0;
|
||||
previousCode = receivedCode;
|
||||
}
|
||||
|
||||
repeats++;
|
||||
|
||||
if (repeats>=_minRepeats) {
|
||||
if (!_inCallback) {
|
||||
_inCallback = true;
|
||||
(_callback)(receivedCode);
|
||||
_inCallback = false;
|
||||
}
|
||||
// Reset after callback.
|
||||
_state=-1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset for next round
|
||||
_state=0; // no need to wait for another sync-bit!
|
||||
return;
|
||||
}
|
||||
else { // Otherwise the entire sequence is invalid
|
||||
_state = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_state % 4 == 1) { // Last bit part? Note: this is the short version of "if ( (_state-2) % 4 == 3 )"
|
||||
// There are 3 valid options for receivedBit:
|
||||
// 0, indicated by short short short long == B0001.
|
||||
// 1, short long shot short == B0100.
|
||||
// dim, short shot short shot == B0000.
|
||||
// Everything else: inconsistent data, trash the whole sequence.
|
||||
|
||||
|
||||
if (_state < 106) {
|
||||
// States 2 - 105 are address bit states
|
||||
|
||||
receivedCode.address <<= 1;
|
||||
|
||||
// Decode bit. Only 4 LSB's of receivedBit are used; trim the rest.
|
||||
switch (receivedBit & B1111) {
|
||||
case B0001: // Bit "0" received.
|
||||
// receivedCode.address |= 0; But let's not do that, as it is wasteful.
|
||||
break;
|
||||
case B0100: // Bit "1" received.
|
||||
receivedCode.address |= 1;
|
||||
break;
|
||||
default: // Bit was invalid. Abort.
|
||||
_state = -1;
|
||||
return;
|
||||
}
|
||||
} else if (_state < 110) {
|
||||
// States 106 - 109 are group bit states.
|
||||
switch (receivedBit & B1111) {
|
||||
case B0001: // Bit "0" received.
|
||||
receivedCode.groupBit = false;
|
||||
break;
|
||||
case B0100: // Bit "1" received.
|
||||
receivedCode.groupBit = true;
|
||||
break;
|
||||
default: // Bit was invalid. Abort.
|
||||
_state = -1;
|
||||
return;
|
||||
}
|
||||
} else if (_state < 114) {
|
||||
// States 110 - 113 are switch bit states.
|
||||
switch (receivedBit & B1111) {
|
||||
case B0001: // Bit "0" received.
|
||||
receivedCode.switchType = NewRemoteCode::off;
|
||||
break;
|
||||
case B0100: // Bit "1" received. Note: this might turn out to be a on_with_dim signal.
|
||||
receivedCode.switchType = NewRemoteCode::on;
|
||||
break;
|
||||
case B0000: // Bit "dim" received.
|
||||
receivedCode.switchType = NewRemoteCode::dim;
|
||||
break;
|
||||
default: // Bit was invalid. Abort.
|
||||
_state = -1;
|
||||
return;
|
||||
}
|
||||
} else if (_state < 130){
|
||||
// States 114 - 129 are unit bit states.
|
||||
receivedCode.unit <<= 1;
|
||||
|
||||
// Decode bit.
|
||||
switch (receivedBit & B1111) {
|
||||
case B0001: // Bit "0" received.
|
||||
// receivedCode.unit |= 0; But let's not do that, as it is wasteful.
|
||||
break;
|
||||
case B0100: // Bit "1" received.
|
||||
receivedCode.unit |= 1;
|
||||
break;
|
||||
default: // Bit was invalid. Abort.
|
||||
_state = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (_state < 146) {
|
||||
// States 130 - 145 are dim bit states.
|
||||
// If switchType == 0 these are never present.
|
||||
// If switchType == 2 these are always present.
|
||||
// If switchType == 1 these are or are not present, depending on the revision of the transmitter.
|
||||
|
||||
receivedCode.dimLevel <<= 1;
|
||||
|
||||
// Decode bit.
|
||||
switch (receivedBit & B1111) {
|
||||
case B0001: // Bit "0" received.
|
||||
// receivedCode.dimLevel |= 0; But let's not do that, as it is wasteful.
|
||||
break;
|
||||
case B0100: // Bit "1" received.
|
||||
receivedCode.dimLevel |= 1;
|
||||
break;
|
||||
default: // Bit was invalid. Abort.
|
||||
_state = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_state++;
|
||||
return;
|
||||
}
|
||||
|
||||
boolean NewRemoteReceiver::isReceiving(int waitMillis) {
|
||||
unsigned long startTime=millis();
|
||||
|
||||
int waited; // Signed int!
|
||||
do {
|
||||
if (_state >= 34) { // Abort if a significant part of a code (start pulse + 8 bits) has been received
|
||||
return true;
|
||||
}
|
||||
waited = (millis()-startTime);
|
||||
} while(waited>=0 && waited <= waitMillis); // Yes, clock wraps every 50 days. And then you'd have to wait for a looooong time.
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* NewRemoteSwitch library v1.1.0 (20130601) made by Randy Simons http://randysimons.nl/
|
||||
*
|
||||
* License: GPLv3. See license.txt
|
||||
*/
|
||||
|
||||
#ifndef NewRemoteReceiver_h
|
||||
#define NewRemoteReceiver_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
struct NewRemoteCode {
|
||||
enum SwitchType {
|
||||
off = 0,
|
||||
on = 1,
|
||||
dim = 2,
|
||||
on_with_dim = 3
|
||||
};
|
||||
|
||||
unsigned int period; // Detected duration in microseconds of 1T in the received signal
|
||||
unsigned long address; // Address of received code. [0..2^26-1]
|
||||
boolean groupBit; // Group bit set or not
|
||||
SwitchType switchType; // off, on, dim, on_with_dim.
|
||||
byte unit; // Unit code of received code [0..15]
|
||||
byte dimLevel; // Dim level [0..15] iff switchType == 2
|
||||
};
|
||||
|
||||
typedef void (*NewRemoteReceiverCallBack)(NewRemoteCode);
|
||||
|
||||
/**
|
||||
* See RemoteSwitch for introduction.
|
||||
*
|
||||
* NewRemoteReceiver decodes the signal received from a 433MHz-receiver, like the "KlikAanKlikUit"-system
|
||||
* as well as the signal sent by the RemoteSwtich class. When a correct signal is received,
|
||||
* a user-defined callback function is called.
|
||||
*
|
||||
* Note that in the callback function, the interrupts are still disabled. You can enabled them, if needed.
|
||||
* A call to the callback must be finished before NewRemoteReceiver will call the callback function again, thus
|
||||
* there is no re-entrant problem.
|
||||
*
|
||||
* When sending your own code using NewRemoteSwich, disable() the receiver first.
|
||||
*
|
||||
* This is a pure static class, for simplicity and to limit memory-use.
|
||||
*/
|
||||
|
||||
class NewRemoteReceiver {
|
||||
public:
|
||||
/**
|
||||
* Initializes the decoder.
|
||||
*
|
||||
* If interrupt >= 0, init will register pin <interrupt> to this library.
|
||||
* If interrupt < 0, no interrupt is registered. In that case, you have to call interruptHandler()
|
||||
* yourself whenever the output of the receiver changes, or you can use InterruptChain.
|
||||
*
|
||||
* @param interrupt The interrupt as is used by Arduino's attachInterrupt function. See attachInterrupt for details.
|
||||
If < 0, you must call interruptHandler() yourself.
|
||||
* @param minRepeats The number of times the same code must be received in a row before the callback is calles
|
||||
* @param callback Pointer to a callback function, with signature void (*func)(NewRemoteCode)
|
||||
*/
|
||||
static void init(int8_t interrupt, byte minRepeats, NewRemoteReceiverCallBack callback);
|
||||
|
||||
/**
|
||||
* Enable decoding. No need to call enable() after init().
|
||||
*/
|
||||
static void enable();
|
||||
|
||||
/**
|
||||
* Disable decoding. You can re-enable decoding by calling enable();
|
||||
*/
|
||||
static void disable();
|
||||
|
||||
/**
|
||||
* Deinitializes the decoder. Disables decoding and detaches the interrupt handler. If you want to
|
||||
* re-enable decoding, call init() again.
|
||||
*/
|
||||
static void deinit();
|
||||
|
||||
/**
|
||||
* Tells wether a signal is being received. If a compatible signal is detected within the time out, isReceiving returns true.
|
||||
* Since it makes no sense to transmit while another transmitter is active, it's best to wait for isReceiving() to false.
|
||||
* By default it waits for 150ms, in which a (relative slow) KaKu signal can be broadcasted three times.
|
||||
*
|
||||
* Note: isReceiving() depends on interrupts enabled. Thus, when disabled()'ed, or when interrupts are disabled (as is
|
||||
* the case in the callback), isReceiving() will not work properly.
|
||||
*
|
||||
* @param waitMillis number of milliseconds to monitor for signal.
|
||||
* @return boolean If after waitMillis no signal was being processed, returns false. If before expiration a signal was being processed, returns true.
|
||||
*/
|
||||
static boolean isReceiving(int waitMillis = 150);
|
||||
|
||||
/**
|
||||
* Called every time the signal level changes (high to low or vice versa). Usually called by interrupt.
|
||||
*/
|
||||
static void interruptHandler();
|
||||
|
||||
private:
|
||||
|
||||
static int8_t _interrupt; // Radio input interrupt
|
||||
volatile static short _state; // State of decoding process.
|
||||
static byte _minRepeats;
|
||||
static NewRemoteReceiverCallBack _callback;
|
||||
static boolean _inCallback; // When true, the callback function is being executed; prevents re-entrance.
|
||||
static boolean _enabled; // If true, monitoring and decoding is enabled. If false, interruptHandler will return immediately.
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* NewRemoteSwitch library v1.1.0 (20130601) made by Randy Simons http://randysimons.nl/
|
||||
* See NewRemoteTransmitter.h for details.
|
||||
*
|
||||
* License: GPLv3. See license.txt
|
||||
*/
|
||||
|
||||
#include "NewRemoteTransmitter.h"
|
||||
|
||||
|
||||
NewRemoteTransmitter::NewRemoteTransmitter(unsigned long address, byte pin, unsigned int periodusec, byte repeats) {
|
||||
_address = address;
|
||||
_pin = pin;
|
||||
_periodusec = periodusec;
|
||||
_repeats = (1 << repeats) - 1; // I.e. _repeats = 2^repeats - 1
|
||||
|
||||
pinMode(_pin, OUTPUT);
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::sendGroup(boolean switchOn) {
|
||||
for (int8_t i = _repeats; i >= 0; i--) {
|
||||
_sendStartPulse();
|
||||
|
||||
_sendAddress();
|
||||
|
||||
// Do send group bit
|
||||
_sendBit(true);
|
||||
|
||||
// Switch on | off
|
||||
_sendBit(switchOn);
|
||||
|
||||
// No unit. Is this actually ignored?..
|
||||
_sendUnit(0);
|
||||
|
||||
_sendStopPulse();
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::sendUnit(byte unit, boolean switchOn) {
|
||||
for (int8_t i = _repeats; i >= 0; i--) {
|
||||
_sendStartPulse();
|
||||
|
||||
_sendAddress();
|
||||
|
||||
// No group bit
|
||||
_sendBit(false);
|
||||
|
||||
// Switch on | off
|
||||
_sendBit(switchOn);
|
||||
|
||||
_sendUnit(unit);
|
||||
|
||||
_sendStopPulse();
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::sendDim(byte unit, byte dimLevel) {
|
||||
for (int8_t i = _repeats; i >= 0; i--) {
|
||||
_sendStartPulse();
|
||||
|
||||
_sendAddress();
|
||||
|
||||
// No group bit
|
||||
_sendBit(false);
|
||||
|
||||
// Switch type 'dim'
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec);
|
||||
|
||||
_sendUnit(unit);
|
||||
|
||||
for (int8_t j=3; j>=0; j--) {
|
||||
_sendBit(dimLevel & 1<<j);
|
||||
}
|
||||
|
||||
_sendStopPulse();
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendStartPulse(){
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 10 + (_periodusec >> 1)); // Actually 10.5T insteat of 10.44T. Close enough.
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendAddress() {
|
||||
for (int8_t i=25; i>=0; i--) {
|
||||
_sendBit((_address >> i) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendUnit(byte unit) {
|
||||
for (int8_t i=3; i>=0; i--) {
|
||||
_sendBit(unit & 1<<i);
|
||||
}
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendStopPulse() {
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 40);
|
||||
}
|
||||
|
||||
void NewRemoteTransmitter::_sendBit(boolean isBitOne) {
|
||||
if (isBitOne) {
|
||||
// Send '1'
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 5);
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec);
|
||||
} else {
|
||||
// Send '0'
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, HIGH);
|
||||
delayMicroseconds(_periodusec);
|
||||
digitalWrite(_pin, LOW);
|
||||
delayMicroseconds(_periodusec * 5);
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* NewRemoteSwitch library v1.1.0 (20130601) made by Randy Simons http://randysimons.nl/
|
||||
*
|
||||
* License: GPLv3. See license.txt
|
||||
*/
|
||||
|
||||
#ifndef NewRemoteTransmitter_h
|
||||
#define NewRemoteTransmitter_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/**
|
||||
* NewRemoteTransmitter provides a generic class for simulation of common RF remote controls, like the A-series
|
||||
* 'Klik aan Klik uit'-system (http://www.klikaanklikuit.nl/), used to remotely switch lights etc.
|
||||
*
|
||||
* This class is meant for new-style remotes, usually accompanied by receivers with "code learning"
|
||||
* capabilities. For other remotes, use the RemoteTransmitter class.
|
||||
*
|
||||
* Hardware required for this library: a 433MHz/434MHz SAW oscillator transmitter, e.g.
|
||||
* http://www.sparkfun.com/products/10534
|
||||
* http://www.conrad.nl/goto/?product=130428
|
||||
*
|
||||
* Notes:
|
||||
* - I measured the period length with an oscilloscope, using a A-series KAKU transmitter. Other devices
|
||||
* or manufacturers may use other period length. Use the ShowReceivedCodeNewRemote example to find the
|
||||
* period length for your devices.
|
||||
* - You can copy the address of your "real" remotes, so you won't have to learn new codes into the receivers.
|
||||
* In effect this duplicates a remote. But you can also pick a random number in the range 0..2^26-1.
|
||||
*/
|
||||
class NewRemoteTransmitter {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* To obtain the correct period length, use the ShowReceivedCodeNewRemote example, or you
|
||||
* can use an oscilloscope.
|
||||
*
|
||||
* @param address Address of this transmitter [0..2^26-1] Duplicate the address of your hardware, or choose a random number.
|
||||
* @param pin Output pin on Arduino to which the transmitter is connected
|
||||
* @param periodusec Duration of one period, in microseconds. One bit takes 8 periods (but only 4 for 'dim' signal).
|
||||
* @param repeats [0..8] The 2log-Number of times the signal is repeated. The actual number of repeats will be 2^repeats. 2 would be bare minimum, 4 seems robust, 8 is maximum (and overkill).
|
||||
*/
|
||||
NewRemoteTransmitter(unsigned long address, byte pin, unsigned int periodusec = 260, byte repeats = 4);
|
||||
|
||||
/**
|
||||
* Send on/off command to the address group.
|
||||
*
|
||||
* @param switchOn True to send "on" signal, false to send "off" signal.
|
||||
*/
|
||||
void sendGroup(boolean switchOn);
|
||||
|
||||
/**
|
||||
* Send on/off command to an unit on the current address.
|
||||
*
|
||||
* @param unit [0..15] target unit.
|
||||
* @param switchOn True to send "on" signal, false to send "off" signal.
|
||||
*/
|
||||
void sendUnit(byte unit, boolean switchOn);
|
||||
|
||||
/**
|
||||
* Send dim value to an unit on the current address.
|
||||
*
|
||||
* @param unit [0..15] target unit.
|
||||
* @param dimLevel [0..15] Dim level. 0 for off, 15 for brightest level.
|
||||
*/
|
||||
void sendDim(byte unit, byte dimLevel);
|
||||
|
||||
protected:
|
||||
unsigned long _address; // Address of this transmitter.
|
||||
byte _pin; // Transmitter output pin
|
||||
unsigned int _periodusec; // Oscillator period in microseconds
|
||||
byte _repeats; // Number over repetitions of one telegram
|
||||
|
||||
/**
|
||||
* Transmits start-pulse
|
||||
*/
|
||||
void _sendStartPulse();
|
||||
|
||||
/**
|
||||
* Transmits address part
|
||||
*/
|
||||
void _sendAddress();
|
||||
|
||||
/**
|
||||
* Transmits unit part.
|
||||
*
|
||||
* @param unit [0-15] target unit.
|
||||
*/
|
||||
void _sendUnit(byte unit);
|
||||
|
||||
/**
|
||||
* Transmits stop pulse.
|
||||
*/
|
||||
void _sendStopPulse();
|
||||
|
||||
/**
|
||||
* Transmits a single bit.
|
||||
*
|
||||
* @param isBitOne True, to send '1', false to send '0'.
|
||||
*/
|
||||
void _sendBit(boolean isBitOne);
|
||||
};
|
||||
#endif
|
||||
@@ -1,48 +0,0 @@
|
||||
NewRemoteSwitch library v1.1.0 (BETA) for Arduino 1.0
|
||||
Made by Randy Simons http://randysimons.nl/
|
||||
|
||||
This library provides an easy class for Arduino, to send and receive signals
|
||||
used by some common "new style" 433MHz remote control switches.
|
||||
|
||||
There are two styles of remote:
|
||||
- "old style", which uses switches or a dial to set the house code. Use the
|
||||
RemoteSwitch library instead.
|
||||
- "new style", which use a button on the receivers to "learn" a signal. Use
|
||||
this library.
|
||||
|
||||
License: GPLv3. See ./NewRemoteSwitch/license.txt
|
||||
|
||||
Latest source and wiki: https://bitbucket.org/fuzzillogic/433mhzforarduino
|
||||
|
||||
|
||||
Installation of library:
|
||||
- Make sure Arduino is closed
|
||||
- Copy the directory NewRemoteSwitch to the Arduino library directory (usually
|
||||
<Sketchbook directory>/libraries/)
|
||||
See http://arduino.cc/en/Guide/Libraries for detailed instructions.
|
||||
|
||||
Default installation demo:
|
||||
- Connect the data-out-pin of a 433MHz receiver to digital pin 2. See photo.
|
||||
(Note: your hardware may have a different pin configuration!)
|
||||
- Start Arduino, and open the example: File -> Examples -> NewRemoteSwitch ->
|
||||
ShowReceivedCode or ShowReceivedCodeNewRemote.
|
||||
- Compile, upload and run
|
||||
- Open serial monitor in Arduino (115200 baud)
|
||||
- Press buttons on a 433MHz-remote, and watch the serial monitor
|
||||
|
||||
|
||||
Changelog:
|
||||
NewRemoteSwitch library v1.1.0 (20130601) for Arduino 1.0
|
||||
- BUGFIX: in many occasions, when receiving a dim-level, the code was rejected
|
||||
even if the signal was correct.
|
||||
- Support decoding A-series transmitters which transmit a dim-level in
|
||||
combination with an on-signal, instead of a dim-signal.
|
||||
- Uses NewRemodeCode::on, ::off, ::dim, ::on_with_dim instead of 0, 1, 2 and 3,
|
||||
for better readability. This change is backwards compatible.
|
||||
- Updated examples to use the new NewRemodeCode::on, ::off, ::dim and
|
||||
::on_with_dim notation.
|
||||
- Reduced memory usage (Flash, RAM)
|
||||
|
||||
NewRemoteSwitch library v1.0.0 (20121229) for Arduino 1.0
|
||||
- Support for receiving A-series Klik-aan-klik-uit remote. (NewRemoteReceiver)
|
||||
- With examples to test and demonstrate.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 129 KiB |
@@ -1,23 +0,0 @@
|
||||
= Protocol of klikaanklikuit A-series devices =
|
||||
|
||||
Copied from Wieltje, http://www.circuitsonline.net/forum/view/message/1181410#1181410,
|
||||
but with slightly different timings, as measured on my device.
|
||||
_ _
|
||||
'0': | |_| |_____ (T,T,T,5T)
|
||||
_ _
|
||||
'1': | |_____| |_ (T,5T,T,T)
|
||||
_ _
|
||||
'dim': | |_| |_ (T,T,T,T)
|
||||
|
||||
T = short period of ~260µs. Use the ShowReceivedCodeNewRemote example to find the
|
||||
actual period length for your devices.
|
||||
|
||||
A full frame looks like this:
|
||||
|
||||
- start pulse: 1T high, 10.44T low
|
||||
- 26 bit: Address
|
||||
- 1 bit: group bit
|
||||
- 1 bit: on/off/[dim]
|
||||
- 4 bit: unit
|
||||
- [4 bit: dim level. Only present of [dim] is chosen]
|
||||
- stop pulse: 1T high, 40T low
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Demo for RF remote switch receiver.
|
||||
* This example is for the new KaKu / Home Easy type of remotes!
|
||||
*
|
||||
* For details, see NewRemoteReceiver.h!
|
||||
*
|
||||
* With this sketch you can control a LED connected to digital pin 13,
|
||||
* after the sketch learned the code. After start, the LED starts to blink,
|
||||
* until a valid code has been received. The led stops blinking. Now you
|
||||
* can control the LED with the remote.
|
||||
*
|
||||
* Note: only unit-switches are supported in this sketch, no group or dim.
|
||||
*
|
||||
* Set-up: connect the receiver to digital pin 2 and a LED to digital pin 13.
|
||||
*/
|
||||
|
||||
#include <NewRemoteReceiver.h>
|
||||
|
||||
boolean codeLearned = false;
|
||||
unsigned long learnedAddress;
|
||||
byte learnedUnit;
|
||||
|
||||
void setup() {
|
||||
// LED-pin as output
|
||||
pinMode(13, OUTPUT);
|
||||
|
||||
// Init a new receiver on interrupt pin 0, minimal 2 identical repeats, and callback set to processCode.
|
||||
NewRemoteReceiver::init(0, 2, processCode);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Blink led until a code has been learned
|
||||
if (!codeLearned) {
|
||||
digitalWrite(13, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(13, LOW);
|
||||
delay(500);
|
||||
}
|
||||
}
|
||||
|
||||
// Callback function is called only when a valid code is received.
|
||||
void processCode(NewRemoteCode receivedCode) {
|
||||
// A code has been received.
|
||||
// Do we already know the code?
|
||||
if (!codeLearned) {
|
||||
// No! Let's learn the received code.
|
||||
learnedAddress = receivedCode.address;
|
||||
learnedUnit = receivedCode.unit;
|
||||
codeLearned = true;
|
||||
} else {
|
||||
// Yes!
|
||||
// Is the received code identical to the learned code?
|
||||
if (receivedCode.address == learnedAddress && receivedCode.unit == learnedUnit) {
|
||||
// Yes!
|
||||
// Switch the LED off if the received code was "off".
|
||||
// Anything else (on, dim, on_with_dim) will switch the LED on.
|
||||
if (receivedCode.switchType == NewRemoteCode::off) {
|
||||
digitalWrite(13, LOW);
|
||||
} else {
|
||||
digitalWrite(13, HIGH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Demo for RF remote switch receiver.
|
||||
* For details, see NewRemoteReceiver.h!
|
||||
*
|
||||
* Connect the transmitter to digital pin 11.
|
||||
*
|
||||
* This sketch demonstrates the use of the NewRemoteTransmitter class.
|
||||
*
|
||||
* When run, this sketch switches some pre-defined devices on and off in a loop.
|
||||
*
|
||||
* NOTE: the actual receivers have the address and group numbers in this example
|
||||
* are only for demonstration! If you want to duplicate an existing remote, please
|
||||
* try the "retransmitter"-example instead.
|
||||
*
|
||||
* To use this actual example, you'd need to "learn" the used code in the receivers
|
||||
* This sketch is unsuited for that.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <NewRemoteTransmitter.h>
|
||||
|
||||
// Create a transmitter on address 123, using digital pin 11 to transmit,
|
||||
// with a period duration of 260ms (default), repeating the transmitted
|
||||
// code 2^3=8 times.
|
||||
NewRemoteTransmitter transmitter(123, 11, 260, 3);
|
||||
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Switch unit 2 off
|
||||
transmitter.sendUnit(2, false);
|
||||
|
||||
// Switch all devices in the group off
|
||||
transmitter.sendGroup(false);
|
||||
|
||||
// Set unit 1 to dim-level 3 (range 0-15)
|
||||
transmitter.sendDim(1, 3);
|
||||
|
||||
// Wait 5 seconds
|
||||
delay(5000);
|
||||
|
||||
|
||||
// Switch unit 2 on
|
||||
transmitter.sendUnit(2, true);
|
||||
|
||||
// Switch all devices in the group on
|
||||
transmitter.sendGroup(true);
|
||||
|
||||
// Set unit 1 to dim-level 15, full brightness.
|
||||
transmitter.sendDim(1, 15);
|
||||
|
||||
// Wait 5 seconds
|
||||
delay(5000);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Demo for RF remote switch receiver.
|
||||
* For details, see NewRemoteReceiver.h!
|
||||
*
|
||||
* Connect the transmitter to digital pin 11, and the receiver to digital pin 2.
|
||||
*
|
||||
* When run, this sketch waits for a valid code from a new-style the receiver,
|
||||
* decodes it, and retransmits it after 5 seconds.
|
||||
*/
|
||||
|
||||
#include <NewRemoteReceiver.h>
|
||||
#include <NewRemoteTransmitter.h>
|
||||
|
||||
void setup() {
|
||||
// See example ShowReceivedCode for info on this
|
||||
NewRemoteReceiver::init(0, 2, retransmitter);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
|
||||
void retransmitter(NewRemoteCode receivedCode) {
|
||||
// Disable the receiver; otherwise it might pick up the retransmit as well.
|
||||
NewRemoteReceiver::disable();
|
||||
|
||||
// Need interrupts for delay()
|
||||
interrupts();
|
||||
|
||||
// Wait 5 seconds before sending.
|
||||
delay(5000);
|
||||
|
||||
// Create a new transmitter with the received address and period, use digital pin 11 as output pin
|
||||
|
||||
NewRemoteTransmitter transmitter(receivedCode.address, 11, receivedCode.period);
|
||||
|
||||
if (receivedCode.switchType == NewRemoteCode::dim) {
|
||||
// Dimmer signal received
|
||||
transmitter.sendDim(receivedCode.unit, receivedCode.dimLevel);
|
||||
} else {
|
||||
// On/Off signal received
|
||||
bool isOn = receivedCode.switchType == NewRemoteCode::on || receivedCode.switchType == NewRemoteCode::on_with_dim;
|
||||
|
||||
if (receivedCode.groupBit) {
|
||||
// Send to the group
|
||||
transmitter.sendGroup(isOn);
|
||||
} else {
|
||||
// Send to a single unit
|
||||
transmitter.sendUnit(receivedCode.unit, isOn);
|
||||
}
|
||||
}
|
||||
|
||||
NewRemoteReceiver::enable();
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Demo for RF remote switch receiver.
|
||||
* This example is for the new KaKu / Home Easy type of remotes!
|
||||
|
||||
* For details, see NewRemoteReceiver.h!
|
||||
*
|
||||
* This sketch shows the received signals on the serial port.
|
||||
* Connect the receiver to digital pin 2.
|
||||
*/
|
||||
|
||||
#include <NewRemoteReceiver.h>
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize receiver on interrupt 0 (= digital pin 2), calls the callback "showCode"
|
||||
// after 2 identical codes have been received in a row. (thus, keep the button pressed
|
||||
// for a moment)
|
||||
//
|
||||
// See the interrupt-parameter of attachInterrupt for possible values (and pins)
|
||||
// to connect the receiver.
|
||||
NewRemoteReceiver::init(0, 2, showCode);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
|
||||
// Callback function is called only when a valid code is received.
|
||||
void showCode(NewRemoteCode receivedCode) {
|
||||
// Note: interrupts are disabled. You can re-enable them if needed.
|
||||
|
||||
// Print the received code.
|
||||
Serial.print("Addr ");
|
||||
Serial.print(receivedCode.address);
|
||||
|
||||
if (receivedCode.groupBit) {
|
||||
Serial.print(" group");
|
||||
} else {
|
||||
Serial.print(" unit ");
|
||||
Serial.print(receivedCode.unit);
|
||||
}
|
||||
|
||||
switch (receivedCode.switchType) {
|
||||
case NewRemoteCode::off:
|
||||
Serial.print(" off");
|
||||
break;
|
||||
case NewRemoteCode::on:
|
||||
Serial.print(" on");
|
||||
break;
|
||||
case NewRemoteCode::dim:
|
||||
Serial.print(" dim level ");
|
||||
Serial.print(receivedCode.dimLevel);
|
||||
break;
|
||||
case NewRemoteCode::on_with_dim:
|
||||
Serial.print(" on with dim level ");
|
||||
Serial.print(receivedCode.dimLevel);
|
||||
break;
|
||||
}
|
||||
|
||||
Serial.print(", period: ");
|
||||
Serial.print(receivedCode.period);
|
||||
Serial.println("us.");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
NewRemoteReceiver KEYWORD1
|
||||
NewRemoteCode KEYWORD1
|
||||
isReceiving KEYWORD2
|
||||
init KEYWORD2
|
||||
enable KEYWORD2
|
||||
disable KEYWORD2
|
||||
deinit KEYWORD2
|
||||
NewRemoteTransmitter KEYWORD1
|
||||
sendGroup KEYWORD2
|
||||
sendUnit KEYWORD2
|
||||
sendDim KEYWORD2
|
||||
@@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
@@ -1,557 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2007, Jim Studt (original old version - many contributors since)
|
||||
|
||||
The latest version of this library may be found at:
|
||||
http://www.pjrc.com/teensy/td_libs_OneWire.html
|
||||
|
||||
OneWire has been maintained by Paul Stoffregen (paul@pjrc.com) since
|
||||
January 2010. At the time, it was in need of many bug fixes, but had
|
||||
been abandoned the original author (Jim Studt). None of the known
|
||||
contributors were interested in maintaining OneWire. Paul typically
|
||||
works on OneWire every 6 to 12 months. Patches usually wait that
|
||||
long. If anyone is interested in more actively maintaining OneWire,
|
||||
please contact Paul.
|
||||
|
||||
Version 2.2:
|
||||
Teensy 3.0 compatibility, Paul Stoffregen, paul@pjrc.com
|
||||
Arduino Due compatibility, http://arduino.cc/forum/index.php?topic=141030
|
||||
Fix DS18B20 example negative temperature
|
||||
Fix DS18B20 example's low res modes, Ken Butcher
|
||||
Improve reset timing, Mark Tillotson
|
||||
Add const qualifiers, Bertrik Sikken
|
||||
Add initial value input to crc16, Bertrik Sikken
|
||||
Add target_search() function, Scott Roberts
|
||||
|
||||
Version 2.1:
|
||||
Arduino 1.0 compatibility, Paul Stoffregen
|
||||
Improve temperature example, Paul Stoffregen
|
||||
DS250x_PROM example, Guillermo Lovato
|
||||
PIC32 (chipKit) compatibility, Jason Dangel, dangel.jason AT gmail.com
|
||||
Improvements from Glenn Trewitt:
|
||||
- crc16() now works
|
||||
- check_crc16() does all of calculation/checking work.
|
||||
- Added read_bytes() and write_bytes(), to reduce tedious loops.
|
||||
- Added ds2408 example.
|
||||
Delete very old, out-of-date readme file (info is here)
|
||||
|
||||
Version 2.0: Modifications by Paul Stoffregen, January 2010:
|
||||
http://www.pjrc.com/teensy/td_libs_OneWire.html
|
||||
Search fix from Robin James
|
||||
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27
|
||||
Use direct optimized I/O in all cases
|
||||
Disable interrupts during timing critical sections
|
||||
(this solves many random communication errors)
|
||||
Disable interrupts during read-modify-write I/O
|
||||
Reduce RAM consumption by eliminating unnecessary
|
||||
variables and trimming many to 8 bits
|
||||
Optimize both crc8 - table version moved to flash
|
||||
|
||||
Modified to work with larger numbers of devices - avoids loop.
|
||||
Tested in Arduino 11 alpha with 12 sensors.
|
||||
26 Sept 2008 -- Robin James
|
||||
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27
|
||||
|
||||
Updated to work with arduino-0008 and to include skip() as of
|
||||
2007/07/06. --RJL20
|
||||
|
||||
Modified to calculate the 8-bit CRC directly, avoiding the need for
|
||||
the 256-byte lookup table to be loaded in RAM. Tested in arduino-0010
|
||||
-- Tom Pollard, Jan 23, 2008
|
||||
|
||||
Jim Studt's original library was modified by Josh Larios.
|
||||
|
||||
Tom Pollard, pollard@alum.mit.edu, contributed around May 20, 2008
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Much of the code was inspired by Derek Yerger's code, though I don't
|
||||
think much of that remains. In any event that was..
|
||||
(copyleft) 2006 by Derek Yerger - Free to distribute freely.
|
||||
|
||||
The CRC code was excerpted and inspired by the Dallas Semiconductor
|
||||
sample code bearing this copyright.
|
||||
//---------------------------------------------------------------------------
|
||||
// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// Except as contained in this notice, the name of Dallas Semiconductor
|
||||
// shall not be used except as stated in the Dallas Semiconductor
|
||||
// Branding Policy.
|
||||
//--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "OneWire.h"
|
||||
|
||||
|
||||
OneWire::OneWire(uint8_t pin)
|
||||
{
|
||||
pinMode(pin, INPUT);
|
||||
bitmask = PIN_TO_BITMASK(pin);
|
||||
baseReg = PIN_TO_BASEREG(pin);
|
||||
#if ONEWIRE_SEARCH
|
||||
reset_search();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Perform the onewire reset function. We will wait up to 250uS for
|
||||
// the bus to come high, if it doesn't then it is broken or shorted
|
||||
// and we return a 0;
|
||||
//
|
||||
// Returns 1 if a device asserted a presence pulse, 0 otherwise.
|
||||
//
|
||||
uint8_t OneWire::reset(void)
|
||||
{
|
||||
IO_REG_TYPE mask = bitmask;
|
||||
volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg;
|
||||
uint8_t r;
|
||||
uint8_t retries = 125;
|
||||
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(reg, mask);
|
||||
interrupts();
|
||||
// wait until the wire is high... just in case
|
||||
do {
|
||||
if (--retries == 0) return 0;
|
||||
delayMicroseconds(2);
|
||||
} while ( !DIRECT_READ(reg, mask));
|
||||
|
||||
noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
|
||||
interrupts();
|
||||
delayMicroseconds(480);
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(reg, mask); // allow it to float
|
||||
delayMicroseconds(70);
|
||||
r = !DIRECT_READ(reg, mask);
|
||||
interrupts();
|
||||
delayMicroseconds(410);
|
||||
return r;
|
||||
}
|
||||
|
||||
//
|
||||
// Write a bit. Port and bit is used to cut lookup time and provide
|
||||
// more certain timing.
|
||||
//
|
||||
void OneWire::write_bit(uint8_t v)
|
||||
{
|
||||
IO_REG_TYPE mask=bitmask;
|
||||
volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg;
|
||||
|
||||
if (v & 1) {
|
||||
noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
|
||||
delayMicroseconds(10);
|
||||
DIRECT_WRITE_HIGH(reg, mask); // drive output high
|
||||
interrupts();
|
||||
delayMicroseconds(55);
|
||||
} else {
|
||||
noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
|
||||
delayMicroseconds(65);
|
||||
DIRECT_WRITE_HIGH(reg, mask); // drive output high
|
||||
interrupts();
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Read a bit. Port and bit is used to cut lookup time and provide
|
||||
// more certain timing.
|
||||
//
|
||||
uint8_t OneWire::read_bit(void)
|
||||
{
|
||||
IO_REG_TYPE mask=bitmask;
|
||||
volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg;
|
||||
uint8_t r;
|
||||
|
||||
noInterrupts();
|
||||
DIRECT_MODE_OUTPUT(reg, mask);
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
delayMicroseconds(3);
|
||||
DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise
|
||||
delayMicroseconds(10);
|
||||
r = DIRECT_READ(reg, mask);
|
||||
interrupts();
|
||||
delayMicroseconds(53);
|
||||
return r;
|
||||
}
|
||||
|
||||
//
|
||||
// Write a byte. The writing code uses the active drivers to raise the
|
||||
// pin high, if you need power after the write (e.g. DS18S20 in
|
||||
// parasite power mode) then set 'power' to 1, otherwise the pin will
|
||||
// go tri-state at the end of the write to avoid heating in a short or
|
||||
// other mishap.
|
||||
//
|
||||
void OneWire::write(uint8_t v, uint8_t power /* = 0 */) {
|
||||
uint8_t bitMask;
|
||||
|
||||
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
|
||||
OneWire::write_bit( (bitMask & v)?1:0);
|
||||
}
|
||||
if ( !power) {
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(baseReg, bitmask);
|
||||
DIRECT_WRITE_LOW(baseReg, bitmask);
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
void OneWire::write_bytes(const uint8_t *buf, uint16_t count, bool power /* = 0 */) {
|
||||
for (uint16_t i = 0 ; i < count ; i++)
|
||||
write(buf[i]);
|
||||
if (!power) {
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(baseReg, bitmask);
|
||||
DIRECT_WRITE_LOW(baseReg, bitmask);
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Read a byte
|
||||
//
|
||||
uint8_t OneWire::read() {
|
||||
uint8_t bitMask;
|
||||
uint8_t r = 0;
|
||||
|
||||
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
|
||||
if ( OneWire::read_bit()) r |= bitMask;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void OneWire::read_bytes(uint8_t *buf, uint16_t count) {
|
||||
for (uint16_t i = 0 ; i < count ; i++)
|
||||
buf[i] = read();
|
||||
}
|
||||
|
||||
//
|
||||
// Do a ROM select
|
||||
//
|
||||
void OneWire::select(const uint8_t rom[8])
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
write(0x55); // Choose ROM
|
||||
|
||||
for (i = 0; i < 8; i++) write(rom[i]);
|
||||
}
|
||||
|
||||
//
|
||||
// Do a ROM skip
|
||||
//
|
||||
void OneWire::skip()
|
||||
{
|
||||
write(0xCC); // Skip ROM
|
||||
}
|
||||
|
||||
void OneWire::depower()
|
||||
{
|
||||
noInterrupts();
|
||||
DIRECT_MODE_INPUT(baseReg, bitmask);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
|
||||
//
|
||||
// You need to use this function to start a search again from the beginning.
|
||||
// You do not need to do it for the first search, though you could.
|
||||
//
|
||||
void OneWire::reset_search()
|
||||
{
|
||||
// reset the search state
|
||||
LastDiscrepancy = 0;
|
||||
LastDeviceFlag = FALSE;
|
||||
LastFamilyDiscrepancy = 0;
|
||||
for(int i = 7; ; i--) {
|
||||
ROM_NO[i] = 0;
|
||||
if ( i == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the search to find the device type 'family_code' on the next call
|
||||
// to search(*newAddr) if it is present.
|
||||
//
|
||||
void OneWire::target_search(uint8_t family_code)
|
||||
{
|
||||
// set the search state to find SearchFamily type devices
|
||||
ROM_NO[0] = family_code;
|
||||
for (uint8_t i = 1; i < 8; i++)
|
||||
ROM_NO[i] = 0;
|
||||
LastDiscrepancy = 64;
|
||||
LastFamilyDiscrepancy = 0;
|
||||
LastDeviceFlag = FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Perform a search. If this function returns a '1' then it has
|
||||
// enumerated the next device and you may retrieve the ROM from the
|
||||
// OneWire::address variable. If there are no devices, no further
|
||||
// devices, or something horrible happens in the middle of the
|
||||
// enumeration then a 0 is returned. If a new device is found then
|
||||
// its address is copied to newAddr. Use OneWire::reset_search() to
|
||||
// start over.
|
||||
//
|
||||
// --- Replaced by the one from the Dallas Semiconductor web site ---
|
||||
//--------------------------------------------------------------------------
|
||||
// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
|
||||
// search state.
|
||||
// Return TRUE : device found, ROM number in ROM_NO buffer
|
||||
// FALSE : device not found, end of search
|
||||
//
|
||||
uint8_t OneWire::search(uint8_t *newAddr)
|
||||
{
|
||||
uint8_t id_bit_number;
|
||||
uint8_t last_zero, rom_byte_number, search_result;
|
||||
uint8_t id_bit, cmp_id_bit;
|
||||
|
||||
unsigned char rom_byte_mask, search_direction;
|
||||
|
||||
// initialize for search
|
||||
id_bit_number = 1;
|
||||
last_zero = 0;
|
||||
rom_byte_number = 0;
|
||||
rom_byte_mask = 1;
|
||||
search_result = 0;
|
||||
|
||||
// if the last call was not the last one
|
||||
if (!LastDeviceFlag)
|
||||
{
|
||||
// 1-Wire reset
|
||||
if (!reset())
|
||||
{
|
||||
// reset the search
|
||||
LastDiscrepancy = 0;
|
||||
LastDeviceFlag = FALSE;
|
||||
LastFamilyDiscrepancy = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// issue the search command
|
||||
write(0xF0);
|
||||
|
||||
// loop to do the search
|
||||
do
|
||||
{
|
||||
// read a bit and its complement
|
||||
id_bit = read_bit();
|
||||
cmp_id_bit = read_bit();
|
||||
|
||||
// check for no devices on 1-wire
|
||||
if ((id_bit == 1) && (cmp_id_bit == 1))
|
||||
break;
|
||||
else
|
||||
{
|
||||
// all devices coupled have 0 or 1
|
||||
if (id_bit != cmp_id_bit)
|
||||
search_direction = id_bit; // bit write value for search
|
||||
else
|
||||
{
|
||||
// if this discrepancy if before the Last Discrepancy
|
||||
// on a previous next then pick the same as last time
|
||||
if (id_bit_number < LastDiscrepancy)
|
||||
search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
|
||||
else
|
||||
// if equal to last pick 1, if not then pick 0
|
||||
search_direction = (id_bit_number == LastDiscrepancy);
|
||||
|
||||
// if 0 was picked then record its position in LastZero
|
||||
if (search_direction == 0)
|
||||
{
|
||||
last_zero = id_bit_number;
|
||||
|
||||
// check for Last discrepancy in family
|
||||
if (last_zero < 9)
|
||||
LastFamilyDiscrepancy = last_zero;
|
||||
}
|
||||
}
|
||||
|
||||
// set or clear the bit in the ROM byte rom_byte_number
|
||||
// with mask rom_byte_mask
|
||||
if (search_direction == 1)
|
||||
ROM_NO[rom_byte_number] |= rom_byte_mask;
|
||||
else
|
||||
ROM_NO[rom_byte_number] &= ~rom_byte_mask;
|
||||
|
||||
// serial number search direction write bit
|
||||
write_bit(search_direction);
|
||||
|
||||
// increment the byte counter id_bit_number
|
||||
// and shift the mask rom_byte_mask
|
||||
id_bit_number++;
|
||||
rom_byte_mask <<= 1;
|
||||
|
||||
// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
|
||||
if (rom_byte_mask == 0)
|
||||
{
|
||||
rom_byte_number++;
|
||||
rom_byte_mask = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(rom_byte_number < 8); // loop until through all ROM bytes 0-7
|
||||
|
||||
// if the search was successful then
|
||||
if (!(id_bit_number < 65))
|
||||
{
|
||||
// search successful so set LastDiscrepancy,LastDeviceFlag,search_result
|
||||
LastDiscrepancy = last_zero;
|
||||
|
||||
// check for last device
|
||||
if (LastDiscrepancy == 0)
|
||||
LastDeviceFlag = TRUE;
|
||||
|
||||
search_result = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// if no device found then reset counters so next 'search' will be like a first
|
||||
if (!search_result || !ROM_NO[0])
|
||||
{
|
||||
LastDiscrepancy = 0;
|
||||
LastDeviceFlag = FALSE;
|
||||
LastFamilyDiscrepancy = 0;
|
||||
search_result = FALSE;
|
||||
}
|
||||
for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i];
|
||||
return search_result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if ONEWIRE_CRC
|
||||
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
|
||||
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
|
||||
//
|
||||
|
||||
#if ONEWIRE_CRC8_TABLE
|
||||
// This table comes from Dallas sample code where it is freely reusable,
|
||||
// though Copyright (C) 2000 Dallas Semiconductor Corporation
|
||||
static const uint8_t PROGMEM dscrc_table[] = {
|
||||
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
|
||||
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
|
||||
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
|
||||
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
|
||||
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
|
||||
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
|
||||
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
|
||||
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
|
||||
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
|
||||
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
|
||||
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
|
||||
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
|
||||
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
|
||||
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
|
||||
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
|
||||
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};
|
||||
|
||||
//
|
||||
// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM
|
||||
// and the registers. (note: this might better be done without to
|
||||
// table, it would probably be smaller and certainly fast enough
|
||||
// compared to all those delayMicrosecond() calls. But I got
|
||||
// confused, so I use this table from the examples.)
|
||||
//
|
||||
uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
crc = pgm_read_byte(dscrc_table + (crc ^ *addr++));
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#else
|
||||
//
|
||||
// Compute a Dallas Semiconductor 8 bit CRC directly.
|
||||
// this is much slower, but much smaller, than the lookup table.
|
||||
//
|
||||
uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
while (len--) {
|
||||
uint8_t inbyte = *addr++;
|
||||
for (uint8_t i = 8; i; i--) {
|
||||
uint8_t mix = (crc ^ inbyte) & 0x01;
|
||||
crc >>= 1;
|
||||
if (mix) crc ^= 0x8C;
|
||||
inbyte >>= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ONEWIRE_CRC16
|
||||
bool OneWire::check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc)
|
||||
{
|
||||
crc = ~crc16(input, len, crc);
|
||||
return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];
|
||||
}
|
||||
|
||||
uint16_t OneWire::crc16(const uint8_t* input, uint16_t len, uint16_t crc)
|
||||
{
|
||||
static const uint8_t oddparity[16] =
|
||||
{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
|
||||
|
||||
for (uint16_t i = 0 ; i < len ; i++) {
|
||||
// Even though we're just copying a byte from the input,
|
||||
// we'll be doing 16-bit computation with it.
|
||||
uint16_t cdata = input[i];
|
||||
cdata = (cdata ^ crc) & 0xff;
|
||||
crc >>= 8;
|
||||
|
||||
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4])
|
||||
crc ^= 0xC001;
|
||||
|
||||
cdata <<= 6;
|
||||
crc ^= cdata;
|
||||
cdata <<= 1;
|
||||
crc ^= cdata;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,229 +0,0 @@
|
||||
#ifndef OneWire_h
|
||||
#define OneWire_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h" // for delayMicroseconds, digitalPinToBitMask, etc
|
||||
#else
|
||||
#include "WProgram.h" // for delayMicroseconds
|
||||
#include "pins_arduino.h" // for digitalPinToBitMask, etc
|
||||
#endif
|
||||
|
||||
// You can exclude certain features from OneWire. In theory, this
|
||||
// might save some space. In practice, the compiler automatically
|
||||
// removes unused code (technically, the linker, using -fdata-sections
|
||||
// and -ffunction-sections when compiling, and Wl,--gc-sections
|
||||
// when linking), so most of these will not result in any code size
|
||||
// reduction. Well, unless you try to use the missing features
|
||||
// and redesign your program to not need them! ONEWIRE_CRC8_TABLE
|
||||
// is the exception, because it selects a fast but large algorithm
|
||||
// or a small but slow algorithm.
|
||||
|
||||
// you can exclude onewire_search by defining that to 0
|
||||
#ifndef ONEWIRE_SEARCH
|
||||
#define ONEWIRE_SEARCH 1
|
||||
#endif
|
||||
|
||||
// You can exclude CRC checks altogether by defining this to 0
|
||||
#ifndef ONEWIRE_CRC
|
||||
#define ONEWIRE_CRC 1
|
||||
#endif
|
||||
|
||||
// Select the table-lookup method of computing the 8-bit CRC
|
||||
// by setting this to 1. The lookup table enlarges code size by
|
||||
// about 250 bytes. It does NOT consume RAM (but did in very
|
||||
// old versions of OneWire). If you disable this, a slower
|
||||
// but very compact algorithm is used.
|
||||
#ifndef ONEWIRE_CRC8_TABLE
|
||||
#define ONEWIRE_CRC8_TABLE 1
|
||||
#endif
|
||||
|
||||
// You can allow 16-bit CRC checks by defining this to 1
|
||||
// (Note that ONEWIRE_CRC must also be 1.)
|
||||
#ifndef ONEWIRE_CRC16
|
||||
#define ONEWIRE_CRC16 1
|
||||
#endif
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
// Platform specific I/O definitions
|
||||
|
||||
#if defined(__AVR__)
|
||||
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_ASM asm("r30")
|
||||
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask))
|
||||
|
||||
#elif defined(__MK20DX128__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (1)
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_ASM
|
||||
#define DIRECT_READ(base, mask) (*((base)+512))
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0)
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1)
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1)
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1)
|
||||
|
||||
#elif defined(__SAM3X8E__)
|
||||
// Arduino 1.5.1 may have a bug in delayMicroseconds() on Arduino Due.
|
||||
// http://arduino.cc/forum/index.php/topic,141030.msg1076268.html#msg1076268
|
||||
// If you have trouble with OneWire on Arduino Due, please check the
|
||||
// status of delayMicroseconds() before reporting a bug in OneWire!
|
||||
#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_ASM
|
||||
#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask))
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM
|
||||
#endif
|
||||
#ifndef pgm_read_byte
|
||||
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
|
||||
#endif
|
||||
|
||||
#elif defined(__PIC32MX__)
|
||||
#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_ASM
|
||||
#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28
|
||||
|
||||
#else
|
||||
#error "Please define I/O register types here"
|
||||
#endif
|
||||
|
||||
|
||||
class OneWire
|
||||
{
|
||||
private:
|
||||
IO_REG_TYPE bitmask;
|
||||
volatile IO_REG_TYPE *baseReg;
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
// global search state
|
||||
unsigned char ROM_NO[8];
|
||||
uint8_t LastDiscrepancy;
|
||||
uint8_t LastFamilyDiscrepancy;
|
||||
uint8_t LastDeviceFlag;
|
||||
#endif
|
||||
|
||||
public:
|
||||
OneWire( uint8_t pin);
|
||||
|
||||
// Perform a 1-Wire reset cycle. Returns 1 if a device responds
|
||||
// with a presence pulse. Returns 0 if there is no device or the
|
||||
// bus is shorted or otherwise held low for more than 250uS
|
||||
uint8_t reset(void);
|
||||
|
||||
// Issue a 1-Wire rom select command, you do the reset first.
|
||||
void select(const uint8_t rom[8]);
|
||||
|
||||
// Issue a 1-Wire rom skip command, to address all on bus.
|
||||
void skip(void);
|
||||
|
||||
// Write a byte. If 'power' is one then the wire is held high at
|
||||
// the end for parasitically powered devices. You are responsible
|
||||
// for eventually depowering it by calling depower() or doing
|
||||
// another read or write.
|
||||
void write(uint8_t v, uint8_t power = 0);
|
||||
|
||||
void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0);
|
||||
|
||||
// Read a byte.
|
||||
uint8_t read(void);
|
||||
|
||||
void read_bytes(uint8_t *buf, uint16_t count);
|
||||
|
||||
// Write a bit. The bus is always left powered at the end, see
|
||||
// note in write() about that.
|
||||
void write_bit(uint8_t v);
|
||||
|
||||
// Read a bit.
|
||||
uint8_t read_bit(void);
|
||||
|
||||
// Stop forcing power onto the bus. You only need to do this if
|
||||
// you used the 'power' flag to write() or used a write_bit() call
|
||||
// and aren't about to do another read or write. You would rather
|
||||
// not leave this powered if you don't have to, just in case
|
||||
// someone shorts your bus.
|
||||
void depower(void);
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
// Clear the search state so that if will start from the beginning again.
|
||||
void reset_search();
|
||||
|
||||
// Setup the search to find the device type 'family_code' on the next call
|
||||
// to search(*newAddr) if it is present.
|
||||
void target_search(uint8_t family_code);
|
||||
|
||||
// Look for the next device. Returns 1 if a new address has been
|
||||
// returned. A zero might mean that the bus is shorted, there are
|
||||
// no devices, or you have already retrieved all of them. It
|
||||
// might be a good idea to check the CRC to make sure you didn't
|
||||
// get garbage. The order is deterministic. You will always get
|
||||
// the same devices in the same order.
|
||||
uint8_t search(uint8_t *newAddr);
|
||||
#endif
|
||||
|
||||
#if ONEWIRE_CRC
|
||||
// Compute a Dallas Semiconductor 8 bit CRC, these are used in the
|
||||
// ROM and scratchpad registers.
|
||||
static uint8_t crc8(const uint8_t *addr, uint8_t len);
|
||||
|
||||
#if ONEWIRE_CRC16
|
||||
// Compute the 1-Wire CRC16 and compare it against the received CRC.
|
||||
// Example usage (reading a DS2408):
|
||||
// // Put everything in a buffer so we can compute the CRC easily.
|
||||
// uint8_t buf[13];
|
||||
// buf[0] = 0xF0; // Read PIO Registers
|
||||
// buf[1] = 0x88; // LSB address
|
||||
// buf[2] = 0x00; // MSB address
|
||||
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
|
||||
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
|
||||
// if (!CheckCRC16(buf, 11, &buf[11])) {
|
||||
// // Handle error.
|
||||
// }
|
||||
//
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param inverted_crc - The two CRC16 bytes in the received data.
|
||||
// This should just point into the received data,
|
||||
// *not* at a 16-bit integer.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return True, iff the CRC matches.
|
||||
static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0);
|
||||
|
||||
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
|
||||
// the integrity of data received from many 1-Wire devices. Note that the
|
||||
// CRC computed here is *not* what you'll get from the 1-Wire network,
|
||||
// for two reasons:
|
||||
// 1) The CRC is transmitted bitwise inverted.
|
||||
// 2) Depending on the endian-ness of your processor, the binary
|
||||
// representation of the two-byte return value may have a different
|
||||
// byte order than the two bytes you get from 1-Wire.
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return The CRC16, as defined by Dallas Semiconductor.
|
||||
static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0);
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
#include <OneWire.h>
|
||||
|
||||
// OneWire DS18S20, DS18B20, DS1822 Temperature Example
|
||||
//
|
||||
// http://www.pjrc.com/teensy/td_libs_OneWire.html
|
||||
//
|
||||
// The DallasTemperature library can do all this work for you!
|
||||
// http://milesburton.com/Dallas_Temperature_Control_Library
|
||||
|
||||
OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary)
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
byte i;
|
||||
byte present = 0;
|
||||
byte type_s;
|
||||
byte data[12];
|
||||
byte addr[8];
|
||||
float celsius, fahrenheit;
|
||||
|
||||
if ( !ds.search(addr)) {
|
||||
Serial.println("No more addresses.");
|
||||
Serial.println();
|
||||
ds.reset_search();
|
||||
delay(250);
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print("ROM =");
|
||||
for( i = 0; i < 8; i++) {
|
||||
Serial.write(' ');
|
||||
Serial.print(addr[i], HEX);
|
||||
}
|
||||
|
||||
if (OneWire::crc8(addr, 7) != addr[7]) {
|
||||
Serial.println("CRC is not valid!");
|
||||
return;
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// the first ROM byte indicates which chip
|
||||
switch (addr[0]) {
|
||||
case 0x10:
|
||||
Serial.println(" Chip = DS18S20"); // or old DS1820
|
||||
type_s = 1;
|
||||
break;
|
||||
case 0x28:
|
||||
Serial.println(" Chip = DS18B20");
|
||||
type_s = 0;
|
||||
break;
|
||||
case 0x22:
|
||||
Serial.println(" Chip = DS1822");
|
||||
type_s = 0;
|
||||
break;
|
||||
default:
|
||||
Serial.println("Device is not a DS18x20 family device.");
|
||||
return;
|
||||
}
|
||||
|
||||
ds.reset();
|
||||
ds.select(addr);
|
||||
ds.write(0x44, 1); // start conversion, with parasite power on at the end
|
||||
|
||||
delay(1000); // maybe 750ms is enough, maybe not
|
||||
// we might do a ds.depower() here, but the reset will take care of it.
|
||||
|
||||
present = ds.reset();
|
||||
ds.select(addr);
|
||||
ds.write(0xBE); // Read Scratchpad
|
||||
|
||||
Serial.print(" Data = ");
|
||||
Serial.print(present, HEX);
|
||||
Serial.print(" ");
|
||||
for ( i = 0; i < 9; i++) { // we need 9 bytes
|
||||
data[i] = ds.read();
|
||||
Serial.print(data[i], HEX);
|
||||
Serial.print(" ");
|
||||
}
|
||||
Serial.print(" CRC=");
|
||||
Serial.print(OneWire::crc8(data, 8), HEX);
|
||||
Serial.println();
|
||||
|
||||
// Convert the data to actual temperature
|
||||
// because the result is a 16 bit signed integer, it should
|
||||
// be stored to an "int16_t" type, which is always 16 bits
|
||||
// even when compiled on a 32 bit processor.
|
||||
int16_t raw = (data[1] << 8) | data[0];
|
||||
if (type_s) {
|
||||
raw = raw << 3; // 9 bit resolution default
|
||||
if (data[7] == 0x10) {
|
||||
// "count remain" gives full 12 bit resolution
|
||||
raw = (raw & 0xFFF0) + 12 - data[6];
|
||||
}
|
||||
} else {
|
||||
byte cfg = (data[4] & 0x60);
|
||||
// at lower res, the low bits are undefined, so let's zero them
|
||||
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
|
||||
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
|
||||
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
|
||||
//// default is 12 bit resolution, 750 ms conversion time
|
||||
}
|
||||
celsius = (float)raw / 16.0;
|
||||
fahrenheit = celsius * 1.8 + 32.0;
|
||||
Serial.print(" Temperature = ");
|
||||
Serial.print(celsius);
|
||||
Serial.print(" Celsius, ");
|
||||
Serial.print(fahrenheit);
|
||||
Serial.println(" Fahrenheit");
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
#include <OneWire.h>
|
||||
|
||||
/*
|
||||
* DS2408 8-Channel Addressable Switch
|
||||
*
|
||||
* Writte by Glenn Trewitt, glenn at trewitt dot org
|
||||
*
|
||||
* Some notes about the DS2408:
|
||||
* - Unlike most input/output ports, the DS2408 doesn't have mode bits to
|
||||
* set whether the pins are input or output. If you issue a read command,
|
||||
* they're inputs. If you write to them, they're outputs.
|
||||
* - For reading from a switch, you should use 10K pull-up resisters.
|
||||
*/
|
||||
|
||||
void PrintBytes(uint8_t* addr, uint8_t count, bool newline=0) {
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
Serial.print(addr[i]>>4, HEX);
|
||||
Serial.print(addr[i]&0x0f, HEX);
|
||||
}
|
||||
if (newline)
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void ReadAndReport(OneWire* net, uint8_t* addr) {
|
||||
Serial.print(" Reading DS2408 ");
|
||||
PrintBytes(addr, 8);
|
||||
Serial.println();
|
||||
|
||||
uint8_t buf[13]; // Put everything in the buffer so we can compute CRC easily.
|
||||
buf[0] = 0xF0; // Read PIO Registers
|
||||
buf[1] = 0x88; // LSB address
|
||||
buf[2] = 0x00; // MSB address
|
||||
net->write_bytes(buf, 3);
|
||||
net->read_bytes(buf+3, 10); // 3 cmd bytes, 6 data bytes, 2 0xFF, 2 CRC16
|
||||
net->reset();
|
||||
|
||||
if (!OneWire::check_crc16(buf, 11, &buf[11])) {
|
||||
Serial.print("CRC failure in DS2408 at ");
|
||||
PrintBytes(addr, 8, true);
|
||||
return;
|
||||
}
|
||||
Serial.print(" DS2408 data = ");
|
||||
// First 3 bytes contain command, register address.
|
||||
Serial.println(buf[3], BIN);
|
||||
}
|
||||
|
||||
OneWire net(10); // on pin 10
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
byte i;
|
||||
byte present = 0;
|
||||
byte addr[8];
|
||||
|
||||
if (!net.search(addr)) {
|
||||
Serial.print("No more addresses.\n");
|
||||
net.reset_search();
|
||||
delay(1000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (OneWire::crc8(addr, 7) != addr[7]) {
|
||||
Serial.print("CRC is not valid!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr[0] != 0x29) {
|
||||
PrintBytes(addr, 8);
|
||||
Serial.print(" is not a DS2408.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ReadAndReport(&net, addr);
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
DS250x add-only programmable memory reader w/SKIP ROM.
|
||||
|
||||
The DS250x is a 512/1024bit add-only PROM(you can add data but cannot change the old one) that's used mainly for device identification purposes
|
||||
like serial number, mfgr data, unique identifiers, etc. It uses the Maxim 1-wire bus.
|
||||
|
||||
This sketch will use the SKIP ROM function that skips the 1-Wire search phase since we only have one device connected in the bus on digital pin 6.
|
||||
If more than one device is connected to the bus, it will fail.
|
||||
Sketch will not verify if device connected is from the DS250x family since the skip rom function effectively skips the family-id byte readout.
|
||||
thus it is possible to run this sketch with any Maxim OneWire device in which case the command CRC will most likely fail.
|
||||
Sketch will only read the first page of memory(32bits) starting from the lower address(0000h), if more than 1 device is present, then use the sketch with search functions.
|
||||
Remember to put a 4.7K pullup resistor between pin 6 and +Vcc
|
||||
|
||||
To change the range or ammount of data to read, simply change the data array size, LSB/MSB addresses and for loop iterations
|
||||
|
||||
This example code is in the public domain and is provided AS-IS.
|
||||
|
||||
Built with Arduino 0022 and PJRC OneWire 2.0 library http://www.pjrc.com/teensy/td_libs_OneWire.html
|
||||
|
||||
created by Guillermo Lovato <glovato@gmail.com>
|
||||
march/2011
|
||||
|
||||
*/
|
||||
|
||||
#include <OneWire.h>
|
||||
OneWire ds(6); // OneWire bus on digital pin 6
|
||||
void setup() {
|
||||
Serial.begin (9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
byte i; // This is for the for loops
|
||||
boolean present; // device present var
|
||||
byte data[32]; // container for the data from device
|
||||
byte leemem[3] = { // array with the commands to initiate a read, DS250x devices expect 3 bytes to start a read: command,LSB&MSB adresses
|
||||
0xF0 , 0x00 , 0x00 }; // 0xF0 is the Read Data command, followed by 00h 00h as starting address(the beginning, 0000h)
|
||||
byte ccrc; // Variable to store the command CRC
|
||||
byte ccrc_calc;
|
||||
|
||||
present = ds.reset(); // OneWire bus reset, always needed to start operation on the bus, returns a 1/TRUE if there's a device present.
|
||||
ds.skip(); // Skip ROM search
|
||||
|
||||
if (present == TRUE){ // We only try to read the data if there's a device present
|
||||
Serial.println("DS250x device present");
|
||||
ds.write(leemem[0],1); // Read data command, leave ghost power on
|
||||
ds.write(leemem[1],1); // LSB starting address, leave ghost power on
|
||||
ds.write(leemem[2],1); // MSB starting address, leave ghost power on
|
||||
|
||||
ccrc = ds.read(); // DS250x generates a CRC for the command we sent, we assign a read slot and store it's value
|
||||
ccrc_calc = OneWire::crc8(leemem, 3); // We calculate the CRC of the commands we sent using the library function and store it
|
||||
|
||||
if ( ccrc_calc != ccrc) { // Then we compare it to the value the ds250x calculated, if it fails, we print debug messages and abort
|
||||
Serial.println("Invalid command CRC!");
|
||||
Serial.print("Calculated CRC:");
|
||||
Serial.println(ccrc_calc,HEX); // HEX makes it easier to observe and compare
|
||||
Serial.print("DS250x readback CRC:");
|
||||
Serial.println(ccrc,HEX);
|
||||
return; // Since CRC failed, we abort the rest of the loop and start over
|
||||
}
|
||||
Serial.println("Data is: "); // For the printout of the data
|
||||
for ( i = 0; i < 32; i++) { // Now it's time to read the PROM data itself, each page is 32 bytes so we need 32 read commands
|
||||
data[i] = ds.read(); // we store each read byte to a different position in the data array
|
||||
Serial.print(data[i]); // printout in ASCII
|
||||
Serial.print(" "); // blank space
|
||||
}
|
||||
Serial.println();
|
||||
delay(5000); // Delay so we don't saturate the serial output
|
||||
}
|
||||
else { // Nothing is connected in the bus
|
||||
Serial.println("Nothing connected");
|
||||
delay(3000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For OneWire
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
OneWire KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
reset KEYWORD2
|
||||
write_bit KEYWORD2
|
||||
read_bit KEYWORD2
|
||||
write KEYWORD2
|
||||
write_bytes KEYWORD2
|
||||
read KEYWORD2
|
||||
read_bytes KEYWORD2
|
||||
select KEYWORD2
|
||||
skip KEYWORD2
|
||||
depower KEYWORD2
|
||||
reset_search KEYWORD2
|
||||
search KEYWORD2
|
||||
crc8 KEYWORD2
|
||||
crc16 KEYWORD2
|
||||
check_crc16 KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
@@ -1,811 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file PN532.cpp
|
||||
@author Adafruit Industries & Seeed Studio
|
||||
@license BSD (see license.txt)
|
||||
|
||||
|
||||
@section HISTORY
|
||||
v1.5 - Modified to work with I2C and SPI
|
||||
|
||||
v1.4 - Added setPassiveActivationRetries()
|
||||
|
||||
v1.3 - Modified to work with I2C
|
||||
|
||||
v1.2 - Added writeGPIO()
|
||||
- Added readGPIO()
|
||||
|
||||
v1.1 - Changed readPassiveTargetID() to handle multiple UID sizes
|
||||
- Added the following helper functions for text display
|
||||
static void PrintHex(const uint8_t * data, const uint32_t numBytes)
|
||||
static void PrintHexChar(const uint8_t * pbtData, const uint32_t numBytes)
|
||||
- Added the following Mifare Classic functions:
|
||||
bool mifareclassic_IsFirstBlock (uint32_t uiBlock)
|
||||
bool mifareclassic_IsTrailerBlock (uint32_t uiBlock)
|
||||
uint8_t mifareclassic_AuthenticateBlock (uint8_t * uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t * keyData)
|
||||
uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t * data)
|
||||
uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t * data)
|
||||
- Added the following Mifare Ultalight functions:
|
||||
uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t * buffer)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include "PN532.h"
|
||||
#include "PN532_debug.h"
|
||||
|
||||
#define HAL(func) (_interface->func)
|
||||
|
||||
PN532::PN532(PN532Interface &interface)
|
||||
{
|
||||
_interface = &interface;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void PN532::begin()
|
||||
{
|
||||
HAL(begin)();
|
||||
HAL(wakeup)();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Prints a hexadecimal value in plain characters
|
||||
|
||||
@param data Pointer to the uint8_t data
|
||||
@param numBytes Data length in bytes
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void PN532::PrintHex(const uint8_t *data, const uint32_t numBytes)
|
||||
{
|
||||
(void)data;
|
||||
for (uint8_t i = 0; i < numBytes; i++) {
|
||||
DMSG("0x");
|
||||
DMSG_HEX(data[i]);
|
||||
}
|
||||
DMSG("\n");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Prints a hexadecimal value in plain characters, along with
|
||||
the char equivalents in the following format
|
||||
|
||||
00 00 00 00 00 00 ......
|
||||
|
||||
@param data Pointer to the data
|
||||
@param numBytes Data length in bytes
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void PN532::PrintHexChar(const uint8_t *data, const uint32_t numBytes)
|
||||
{
|
||||
for (uint8_t i = 0; i < numBytes; i++) {
|
||||
DMSG_HEX(data[i]);
|
||||
}
|
||||
DMSG(" ");
|
||||
for (uint8_t i = 0; i < numBytes; i++) {
|
||||
uint8_t c = data[i];
|
||||
if (c <= 0x1f || c > 0x7f) {
|
||||
DMSG('.');
|
||||
} else {
|
||||
DMSG((char)c);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Checks the firmware version of the PN5xx chip
|
||||
|
||||
@returns The chip's firmware version and ID
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint32_t PN532::getFirmwareVersion(void)
|
||||
{
|
||||
uint32_t response;
|
||||
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION;
|
||||
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read data packet
|
||||
int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
|
||||
if (0 > status) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
response = pn532_packetbuffer[0];
|
||||
response <<= 8;
|
||||
response |= pn532_packetbuffer[1];
|
||||
response <<= 8;
|
||||
response |= pn532_packetbuffer[2];
|
||||
response <<= 8;
|
||||
response |= pn532_packetbuffer[3];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Writes an 8-bit value that sets the state of the PN532's GPIO pins
|
||||
|
||||
@warning This function is provided exclusively for board testing and
|
||||
is dangerous since it will throw an error if any pin other
|
||||
than the ones marked "Can be used as GPIO" are modified! All
|
||||
pins that can not be used as GPIO should ALWAYS be left high
|
||||
(value = 1) or the system will become unstable and a HW reset
|
||||
will be required to recover the PN532.
|
||||
|
||||
pinState[0] = P30 Can be used as GPIO
|
||||
pinState[1] = P31 Can be used as GPIO
|
||||
pinState[2] = P32 *** RESERVED (Must be 1!) ***
|
||||
pinState[3] = P33 Can be used as GPIO
|
||||
pinState[4] = P34 *** RESERVED (Must be 1!) ***
|
||||
pinState[5] = P35 Can be used as GPIO
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool PN532::writeGPIO(uint8_t pinstate)
|
||||
{
|
||||
// Make sure pinstate does not try to toggle P32 or P34
|
||||
pinstate |= (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34);
|
||||
|
||||
// Fill command buffer
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_WRITEGPIO;
|
||||
pn532_packetbuffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate; // P3 Pins
|
||||
pn532_packetbuffer[2] = 0x00; // P7 GPIO Pins (not used ... taken by I2C)
|
||||
|
||||
DMSG("Writing P3 GPIO: ");
|
||||
DMSG_HEX(pn532_packetbuffer[1]);
|
||||
DMSG("\n");
|
||||
|
||||
// Send the WRITEGPIO command (0x0E)
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 3))
|
||||
return 0;
|
||||
|
||||
return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Reads the state of the PN532's GPIO pins
|
||||
|
||||
@returns An 8-bit value containing the pin state where:
|
||||
|
||||
pinState[0] = P30
|
||||
pinState[1] = P31
|
||||
pinState[2] = P32
|
||||
pinState[3] = P33
|
||||
pinState[4] = P34
|
||||
pinState[5] = P35
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::readGPIO(void)
|
||||
{
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_READGPIO;
|
||||
|
||||
// Send the READGPIO command (0x0C)
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 1))
|
||||
return 0x0;
|
||||
|
||||
HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
|
||||
|
||||
/* READGPIO response without prefix and suffix should be in the following format:
|
||||
|
||||
byte Description
|
||||
------------- ------------------------------------------
|
||||
b0 P3 GPIO Pins
|
||||
b1 P7 GPIO Pins (not used ... taken by I2C)
|
||||
b2 Interface Mode Pins (not used ... bus select pins)
|
||||
*/
|
||||
|
||||
|
||||
DMSG("P3 GPIO: "); DMSG_HEX(pn532_packetbuffer[7]);
|
||||
DMSG("P7 GPIO: "); DMSG_HEX(pn532_packetbuffer[8]);
|
||||
DMSG("I0I1 GPIO: "); DMSG_HEX(pn532_packetbuffer[9]);
|
||||
DMSG("\n");
|
||||
|
||||
return pn532_packetbuffer[0];
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Configures the SAM (Secure Access Module)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool PN532::SAMConfig(void)
|
||||
{
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
|
||||
pn532_packetbuffer[1] = 0x01; // normal mode;
|
||||
pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second
|
||||
pn532_packetbuffer[3] = 0x01; // use IRQ pin!
|
||||
|
||||
DMSG("SAMConfig\n");
|
||||
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 4))
|
||||
return false;
|
||||
|
||||
return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Sets the MxRtyPassiveActivation uint8_t of the RFConfiguration register
|
||||
|
||||
@param maxRetries 0xFF to wait forever, 0x00..0xFE to timeout
|
||||
after mxRetries
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool PN532::setPassiveActivationRetries(uint8_t maxRetries)
|
||||
{
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION;
|
||||
pn532_packetbuffer[1] = 5; // Config item 5 (MaxRetries)
|
||||
pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF)
|
||||
pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01)
|
||||
pn532_packetbuffer[4] = maxRetries;
|
||||
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 5))
|
||||
return 0x0; // no ACK
|
||||
|
||||
return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
|
||||
}
|
||||
|
||||
/***** ISO14443A Commands ******/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Waits for an ISO14443A target to enter the field
|
||||
|
||||
@param cardBaudRate Baud rate of the card
|
||||
@param uid Pointer to the array that will be populated
|
||||
with the card's UID (up to 7 bytes)
|
||||
@param uidLength Pointer to the variable that will hold the
|
||||
length of the card's UID.
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool PN532::readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout)
|
||||
{
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
|
||||
pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later)
|
||||
pn532_packetbuffer[2] = cardbaudrate;
|
||||
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
|
||||
return 0x0; // command failed
|
||||
}
|
||||
|
||||
// read data packet
|
||||
if (HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) {
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
// check some basic stuff
|
||||
/* ISO14443A card response should be in the following format:
|
||||
|
||||
byte Description
|
||||
------------- ------------------------------------------
|
||||
b0 Tags Found
|
||||
b1 Tag Number (only one used in this example)
|
||||
b2..3 SENS_RES
|
||||
b4 SEL_RES
|
||||
b5 NFCID Length
|
||||
b6..NFCIDLen NFCID
|
||||
*/
|
||||
|
||||
if (pn532_packetbuffer[0] != 1)
|
||||
return 0;
|
||||
|
||||
uint16_t sens_res = pn532_packetbuffer[2];
|
||||
sens_res <<= 8;
|
||||
sens_res |= pn532_packetbuffer[3];
|
||||
|
||||
DMSG("ATQA: 0x"); DMSG_HEX(sens_res);
|
||||
DMSG("SAK: 0x"); DMSG_HEX(pn532_packetbuffer[4]);
|
||||
DMSG("\n");
|
||||
|
||||
/* Card appears to be Mifare Classic */
|
||||
*uidLength = pn532_packetbuffer[5];
|
||||
|
||||
for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) {
|
||||
uid[i] = pn532_packetbuffer[6 + i];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/***** Mifare Classic Functions ******/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Indicates whether the specified block number is the first block
|
||||
in the sector (block 0 relative to the current sector)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool PN532::mifareclassic_IsFirstBlock (uint32_t uiBlock)
|
||||
{
|
||||
// Test if we are in the small or big sectors
|
||||
if (uiBlock < 128)
|
||||
return ((uiBlock) % 4 == 0);
|
||||
else
|
||||
return ((uiBlock) % 16 == 0);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Indicates whether the specified block number is the sector trailer
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool PN532::mifareclassic_IsTrailerBlock (uint32_t uiBlock)
|
||||
{
|
||||
// Test if we are in the small or big sectors
|
||||
if (uiBlock < 128)
|
||||
return ((uiBlock + 1) % 4 == 0);
|
||||
else
|
||||
return ((uiBlock + 1) % 16 == 0);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Tries to authenticate a block of memory on a MIFARE card using the
|
||||
INDATAEXCHANGE command. See section 7.3.8 of the PN532 User Manual
|
||||
for more information on sending MIFARE and other commands.
|
||||
|
||||
@param uid Pointer to a byte array containing the card UID
|
||||
@param uidLen The length (in bytes) of the card's UID (Should
|
||||
be 4 for MIFARE Classic)
|
||||
@param blockNumber The block number to authenticate. (0..63 for
|
||||
1KB cards, and 0..255 for 4KB cards).
|
||||
@param keyNumber Which key type to use during authentication
|
||||
(0 = MIFARE_CMD_AUTH_A, 1 = MIFARE_CMD_AUTH_B)
|
||||
@param keyData Pointer to a byte array containing the 6 bytes
|
||||
key value
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
// Hang on to the key and uid data
|
||||
memcpy (_key, keyData, 6);
|
||||
memcpy (_uid, uid, uidLen);
|
||||
_uidLen = uidLen;
|
||||
|
||||
// Prepare the authentication command //
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
|
||||
pn532_packetbuffer[1] = 1; /* Max card numbers */
|
||||
pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A;
|
||||
pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
|
||||
memcpy (pn532_packetbuffer + 4, _key, 6);
|
||||
for (i = 0; i < _uidLen; i++) {
|
||||
pn532_packetbuffer[10 + i] = _uid[i]; /* 4 bytes card ID */
|
||||
}
|
||||
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 10 + _uidLen))
|
||||
return 0;
|
||||
|
||||
// Read the response packet
|
||||
HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
|
||||
|
||||
// Check if the response is valid and we are authenticated???
|
||||
// for an auth success it should be bytes 5-7: 0xD5 0x41 0x00
|
||||
// Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good
|
||||
if (pn532_packetbuffer[0] != 0x00) {
|
||||
DMSG("Authentification failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Tries to read an entire 16-bytes data block at the specified block
|
||||
address.
|
||||
|
||||
@param blockNumber The block number to authenticate. (0..63 for
|
||||
1KB cards, and 0..255 for 4KB cards).
|
||||
@param data Pointer to the byte array that will hold the
|
||||
retrieved data (if any)
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data)
|
||||
{
|
||||
DMSG("Trying to read 16 bytes from block ");
|
||||
DMSG_INT(blockNumber);
|
||||
|
||||
/* Prepare the command */
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
|
||||
pn532_packetbuffer[1] = 1; /* Card number */
|
||||
pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
|
||||
pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
|
||||
|
||||
/* Send the command */
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 4)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the response packet */
|
||||
HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
|
||||
|
||||
/* If byte 8 isn't 0x00 we probably have an error */
|
||||
if (pn532_packetbuffer[0] != 0x00) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the 16 data bytes to the output buffer */
|
||||
/* Block content starts at byte 9 of a valid response */
|
||||
memcpy (data, pn532_packetbuffer + 1, 16);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Tries to write an entire 16-bytes data block at the specified block
|
||||
address.
|
||||
|
||||
@param blockNumber The block number to authenticate. (0..63 for
|
||||
1KB cards, and 0..255 for 4KB cards).
|
||||
@param data The byte array that contains the data to write.
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data)
|
||||
{
|
||||
/* Prepare the first command */
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
|
||||
pn532_packetbuffer[1] = 1; /* Card number */
|
||||
pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */
|
||||
pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
|
||||
memcpy (pn532_packetbuffer + 4, data, 16); /* Data Payload */
|
||||
|
||||
/* Send the command */
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 20)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the response packet */
|
||||
return (0 < HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer)));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Formats a Mifare Classic card to store NDEF Records
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareclassic_FormatNDEF (void)
|
||||
{
|
||||
uint8_t sectorbuffer1[16] = {0x14, 0x01, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
|
||||
uint8_t sectorbuffer2[16] = {0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1, 0x03, 0xE1};
|
||||
uint8_t sectorbuffer3[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x78, 0x77, 0x88, 0xC1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
// Note 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 must be used for key A
|
||||
// for the MAD sector in NDEF records (sector 0)
|
||||
|
||||
// Write block 1 and 2 to the card
|
||||
if (!(mifareclassic_WriteDataBlock (1, sectorbuffer1)))
|
||||
return 0;
|
||||
if (!(mifareclassic_WriteDataBlock (2, sectorbuffer2)))
|
||||
return 0;
|
||||
// Write key A and access rights card
|
||||
if (!(mifareclassic_WriteDataBlock (3, sectorbuffer3)))
|
||||
return 0;
|
||||
|
||||
// Seems that everything was OK (?!)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Writes an NDEF URI Record to the specified sector (1..15)
|
||||
|
||||
Note that this function assumes that the Mifare Classic card is
|
||||
already formatted to work as an "NFC Forum Tag" and uses a MAD1
|
||||
file system. You can use the NXP TagWriter app on Android to
|
||||
properly format cards for this.
|
||||
|
||||
@param sectorNumber The sector that the URI record should be written
|
||||
to (can be 1..15 for a 1K card)
|
||||
@param uriIdentifier The uri identifier code (0 = none, 0x01 =
|
||||
"http://www.", etc.)
|
||||
@param url The uri text to write (max 38 characters).
|
||||
|
||||
@returns 1 if everything executed properly, 0 for an error
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char *url)
|
||||
{
|
||||
// Figure out how long the string is
|
||||
uint8_t len = strlen(url);
|
||||
|
||||
// Make sure we're within a 1K limit for the sector number
|
||||
if ((sectorNumber < 1) || (sectorNumber > 15))
|
||||
return 0;
|
||||
|
||||
// Make sure the URI payload is between 1 and 38 chars
|
||||
if ((len < 1) || (len > 38))
|
||||
return 0;
|
||||
|
||||
// Note 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 must be used for key A
|
||||
// in NDEF records
|
||||
|
||||
// Setup the sector buffer (w/pre-formatted TLV wrapper and NDEF message)
|
||||
uint8_t sectorbuffer1[16] = {0x00, 0x00, 0x03, (uint8_t)(len + 5), 0xD1, 0x01, (uint8_t)(len + 1), 0x55, uriIdentifier, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t sectorbuffer2[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t sectorbuffer3[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t sectorbuffer4[16] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0x7F, 0x07, 0x88, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
if (len <= 6) {
|
||||
// Unlikely we'll get a url this short, but why not ...
|
||||
memcpy (sectorbuffer1 + 9, url, len);
|
||||
sectorbuffer1[len + 9] = 0xFE;
|
||||
} else if (len == 7) {
|
||||
// 0xFE needs to be wrapped around to next block
|
||||
memcpy (sectorbuffer1 + 9, url, len);
|
||||
sectorbuffer2[0] = 0xFE;
|
||||
} else if ((len > 7) || (len <= 22)) {
|
||||
// Url fits in two blocks
|
||||
memcpy (sectorbuffer1 + 9, url, 7);
|
||||
memcpy (sectorbuffer2, url + 7, len - 7);
|
||||
sectorbuffer2[len - 7] = 0xFE;
|
||||
} else if (len == 23) {
|
||||
// 0xFE needs to be wrapped around to final block
|
||||
memcpy (sectorbuffer1 + 9, url, 7);
|
||||
memcpy (sectorbuffer2, url + 7, len - 7);
|
||||
sectorbuffer3[0] = 0xFE;
|
||||
} else {
|
||||
// Url fits in three blocks
|
||||
memcpy (sectorbuffer1 + 9, url, 7);
|
||||
memcpy (sectorbuffer2, url + 7, 16);
|
||||
memcpy (sectorbuffer3, url + 23, len - 24);
|
||||
sectorbuffer3[len - 22] = 0xFE;
|
||||
}
|
||||
|
||||
// Now write all three blocks back to the card
|
||||
if (!(mifareclassic_WriteDataBlock (sectorNumber * 4, sectorbuffer1)))
|
||||
return 0;
|
||||
if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 1, sectorbuffer2)))
|
||||
return 0;
|
||||
if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 2, sectorbuffer3)))
|
||||
return 0;
|
||||
if (!(mifareclassic_WriteDataBlock ((sectorNumber * 4) + 3, sectorbuffer4)))
|
||||
return 0;
|
||||
|
||||
// Seems that everything was OK (?!)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***** Mifare Ultralight Functions ******/
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Tries to read an entire 4-bytes page at the specified address.
|
||||
|
||||
@param page The page number (0..63 in most cases)
|
||||
@param buffer Pointer to the byte array that will hold the
|
||||
retrieved data (if any)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t PN532::mifareultralight_ReadPage (uint8_t page, uint8_t *buffer)
|
||||
{
|
||||
if (page >= 64) {
|
||||
DMSG("Page value out of range\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prepare the command */
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
|
||||
pn532_packetbuffer[1] = 1; /* Card number */
|
||||
pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
|
||||
pn532_packetbuffer[3] = page; /* Page Number (0..63 in most cases) */
|
||||
|
||||
/* Send the command */
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 4)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the response packet */
|
||||
HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer));
|
||||
|
||||
/* If byte 8 isn't 0x00 we probably have an error */
|
||||
if (pn532_packetbuffer[0] == 0x00) {
|
||||
/* Copy the 4 data bytes to the output buffer */
|
||||
/* Block content starts at byte 9 of a valid response */
|
||||
/* Note that the command actually reads 16 bytes or 4 */
|
||||
/* pages at a time ... we simply discard the last 12 */
|
||||
/* bytes */
|
||||
memcpy (buffer, pn532_packetbuffer + 1, 4);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return OK signal
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Exchanges an APDU with the currently inlisted peer
|
||||
|
||||
@param send Pointer to data to send
|
||||
@param sendLength Length of the data to send
|
||||
@param response Pointer to response data
|
||||
@param responseLength Pointer to the response data length
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool PN532::inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength)
|
||||
{
|
||||
uint8_t i;
|
||||
(void)i;
|
||||
|
||||
pn532_packetbuffer[0] = 0x40; // PN532_COMMAND_INDATAEXCHANGE;
|
||||
pn532_packetbuffer[1] = inListedTag;
|
||||
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 2, send, sendLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t status = HAL(readResponse)(response, *responseLength, 1000);
|
||||
if (status < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((response[0] & 0x3f) != 0) {
|
||||
DMSG("Status code indicates an error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t length = status;
|
||||
length -= 1;
|
||||
|
||||
if (length > *responseLength) {
|
||||
length = *responseLength; // silent truncation...
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
response[i] = response[i + 1];
|
||||
}
|
||||
*responseLength = length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief 'InLists' a passive target. PN532 acting as reader/initiator,
|
||||
peer acting as card/responder.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool PN532::inListPassiveTarget()
|
||||
{
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET;
|
||||
pn532_packetbuffer[1] = 1;
|
||||
pn532_packetbuffer[2] = 0;
|
||||
|
||||
DMSG("inList passive target\n");
|
||||
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 30000);
|
||||
if (status < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pn532_packetbuffer[0] != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inListedTag = pn532_packetbuffer[1];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Peer to Peer
|
||||
*/
|
||||
int8_t PN532::tgInitAsTarget(uint16_t timeout)
|
||||
{
|
||||
const uint8_t command[] = {
|
||||
PN532_COMMAND_TGINITASTARGET,
|
||||
0,
|
||||
0x00, 0x00, //SENS_RES
|
||||
0x00, 0x00, 0x00, //NFCID1
|
||||
0x40, //SEL_RES
|
||||
|
||||
0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, // POL_RES
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF,
|
||||
|
||||
0x01, 0xFE, 0x0F, 0xBB, 0xBA, 0xA6, 0xC9, 0x89, 0x00, 0x00, //NFCID3t: Change this to desired value
|
||||
|
||||
0x06, 0x46, 0x66, 0x6D, 0x01, 0x01, 0x10, 0x00// LLCP magic number and version parameter
|
||||
};
|
||||
|
||||
int8_t status = HAL(writeCommand)(command, sizeof(command));
|
||||
if (status < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout);
|
||||
if (status > 0) {
|
||||
return 1;
|
||||
} else if (PN532_TIMEOUT == status) {
|
||||
return 0;
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t PN532::tgGetData(uint8_t *buf, uint8_t len)
|
||||
{
|
||||
buf[0] = PN532_COMMAND_TGGETDATA;
|
||||
|
||||
if (HAL(writeCommand)(buf, 1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int16_t status = HAL(readResponse)(buf, len, 3000);
|
||||
if (0 >= status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t length = status - 1;
|
||||
|
||||
|
||||
if (buf[0] != 0) {
|
||||
DMSG("status is not ok\n");
|
||||
return -5;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
buf[i] = buf[i + 1];
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
bool PN532::tgSetData(const uint8_t *header, uint8_t hlen, const uint8_t *body, uint8_t blen)
|
||||
{
|
||||
if (hlen > (sizeof(pn532_packetbuffer) - 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int8_t i = hlen - 1; i >= 0; i--){
|
||||
pn532_packetbuffer[i + 1] = header[i];
|
||||
}
|
||||
pn532_packetbuffer[0] = PN532_COMMAND_TGSETDATA;
|
||||
|
||||
if (HAL(writeCommand)(pn532_packetbuffer, hlen + 1, body, blen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 > HAL(readResponse)(pn532_packetbuffer, sizeof(pn532_packetbuffer), 3000)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 != pn532_packetbuffer[0]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file PN532.h
|
||||
@author Adafruit Industries & Seeed Studio
|
||||
@license BSD (see license.txt)
|
||||
|
||||
|
||||
@section HISTORY
|
||||
v1.5 - Modified to work with I2C and SPI
|
||||
|
||||
v1.3 - Modified to work with I2C
|
||||
|
||||
v1.1 - Added full command list
|
||||
- Added 'verbose' mode flag to constructor to toggle debug output
|
||||
- Changed readPassiveTargetID() to return variable length values
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef PN532_h
|
||||
#define PN532_h
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "PN532Interface.h"
|
||||
|
||||
|
||||
// PN532 Commands
|
||||
#define PN532_COMMAND_DIAGNOSE (0x00)
|
||||
#define PN532_COMMAND_GETFIRMWAREVERSION (0x02)
|
||||
#define PN532_COMMAND_GETGENERALSTATUS (0x04)
|
||||
#define PN532_COMMAND_READREGISTER (0x06)
|
||||
#define PN532_COMMAND_WRITEREGISTER (0x08)
|
||||
#define PN532_COMMAND_READGPIO (0x0C)
|
||||
#define PN532_COMMAND_WRITEGPIO (0x0E)
|
||||
#define PN532_COMMAND_SETSERIALBAUDRATE (0x10)
|
||||
#define PN532_COMMAND_SETPARAMETERS (0x12)
|
||||
#define PN532_COMMAND_SAMCONFIGURATION (0x14)
|
||||
#define PN532_COMMAND_POWERDOWN (0x16)
|
||||
#define PN532_COMMAND_RFCONFIGURATION (0x32)
|
||||
#define PN532_COMMAND_RFREGULATIONTEST (0x58)
|
||||
#define PN532_COMMAND_INJUMPFORDEP (0x56)
|
||||
#define PN532_COMMAND_INJUMPFORPSL (0x46)
|
||||
#define PN532_COMMAND_INLISTPASSIVETARGET (0x4A)
|
||||
#define PN532_COMMAND_INATR (0x50)
|
||||
#define PN532_COMMAND_INPSL (0x4E)
|
||||
#define PN532_COMMAND_INDATAEXCHANGE (0x40)
|
||||
#define PN532_COMMAND_INCOMMUNICATETHRU (0x42)
|
||||
#define PN532_COMMAND_INDESELECT (0x44)
|
||||
#define PN532_COMMAND_INRELEASE (0x52)
|
||||
#define PN532_COMMAND_INSELECT (0x54)
|
||||
#define PN532_COMMAND_INAUTOPOLL (0x60)
|
||||
#define PN532_COMMAND_TGINITASTARGET (0x8C)
|
||||
#define PN532_COMMAND_TGSETGENERALBYTES (0x92)
|
||||
#define PN532_COMMAND_TGGETDATA (0x86)
|
||||
#define PN532_COMMAND_TGSETDATA (0x8E)
|
||||
#define PN532_COMMAND_TGSETMETADATA (0x94)
|
||||
#define PN532_COMMAND_TGGETINITIATORCOMMAND (0x88)
|
||||
#define PN532_COMMAND_TGRESPONSETOINITIATOR (0x90)
|
||||
#define PN532_COMMAND_TGGETTARGETSTATUS (0x8A)
|
||||
|
||||
#define PN532_RESPONSE_INDATAEXCHANGE (0x41)
|
||||
#define PN532_RESPONSE_INLISTPASSIVETARGET (0x4B)
|
||||
|
||||
|
||||
#define PN532_MIFARE_ISO14443A (0x00)
|
||||
|
||||
// Mifare Commands
|
||||
#define MIFARE_CMD_AUTH_A (0x60)
|
||||
#define MIFARE_CMD_AUTH_B (0x61)
|
||||
#define MIFARE_CMD_READ (0x30)
|
||||
#define MIFARE_CMD_WRITE (0xA0)
|
||||
#define MIFARE_CMD_TRANSFER (0xB0)
|
||||
#define MIFARE_CMD_DECREMENT (0xC0)
|
||||
#define MIFARE_CMD_INCREMENT (0xC1)
|
||||
#define MIFARE_CMD_STORE (0xC2)
|
||||
|
||||
// Prefixes for NDEF Records (to identify record type)
|
||||
#define NDEF_URIPREFIX_NONE (0x00)
|
||||
#define NDEF_URIPREFIX_HTTP_WWWDOT (0x01)
|
||||
#define NDEF_URIPREFIX_HTTPS_WWWDOT (0x02)
|
||||
#define NDEF_URIPREFIX_HTTP (0x03)
|
||||
#define NDEF_URIPREFIX_HTTPS (0x04)
|
||||
#define NDEF_URIPREFIX_TEL (0x05)
|
||||
#define NDEF_URIPREFIX_MAILTO (0x06)
|
||||
#define NDEF_URIPREFIX_FTP_ANONAT (0x07)
|
||||
#define NDEF_URIPREFIX_FTP_FTPDOT (0x08)
|
||||
#define NDEF_URIPREFIX_FTPS (0x09)
|
||||
#define NDEF_URIPREFIX_SFTP (0x0A)
|
||||
#define NDEF_URIPREFIX_SMB (0x0B)
|
||||
#define NDEF_URIPREFIX_NFS (0x0C)
|
||||
#define NDEF_URIPREFIX_FTP (0x0D)
|
||||
#define NDEF_URIPREFIX_DAV (0x0E)
|
||||
#define NDEF_URIPREFIX_NEWS (0x0F)
|
||||
#define NDEF_URIPREFIX_TELNET (0x10)
|
||||
#define NDEF_URIPREFIX_IMAP (0x11)
|
||||
#define NDEF_URIPREFIX_RTSP (0x12)
|
||||
#define NDEF_URIPREFIX_URN (0x13)
|
||||
#define NDEF_URIPREFIX_POP (0x14)
|
||||
#define NDEF_URIPREFIX_SIP (0x15)
|
||||
#define NDEF_URIPREFIX_SIPS (0x16)
|
||||
#define NDEF_URIPREFIX_TFTP (0x17)
|
||||
#define NDEF_URIPREFIX_BTSPP (0x18)
|
||||
#define NDEF_URIPREFIX_BTL2CAP (0x19)
|
||||
#define NDEF_URIPREFIX_BTGOEP (0x1A)
|
||||
#define NDEF_URIPREFIX_TCPOBEX (0x1B)
|
||||
#define NDEF_URIPREFIX_IRDAOBEX (0x1C)
|
||||
#define NDEF_URIPREFIX_FILE (0x1D)
|
||||
#define NDEF_URIPREFIX_URN_EPC_ID (0x1E)
|
||||
#define NDEF_URIPREFIX_URN_EPC_TAG (0x1F)
|
||||
#define NDEF_URIPREFIX_URN_EPC_PAT (0x20)
|
||||
#define NDEF_URIPREFIX_URN_EPC_RAW (0x21)
|
||||
#define NDEF_URIPREFIX_URN_EPC (0x22)
|
||||
#define NDEF_URIPREFIX_URN_NFC (0x23)
|
||||
|
||||
#define PN532_GPIO_VALIDATIONBIT (0x80)
|
||||
#define PN532_GPIO_P30 (0)
|
||||
#define PN532_GPIO_P31 (1)
|
||||
#define PN532_GPIO_P32 (2)
|
||||
#define PN532_GPIO_P33 (3)
|
||||
#define PN532_GPIO_P34 (4)
|
||||
#define PN532_GPIO_P35 (5)
|
||||
|
||||
class PN532
|
||||
{
|
||||
public:
|
||||
PN532(PN532Interface &interface);
|
||||
|
||||
void begin(void);
|
||||
|
||||
// Generic PN532 functions
|
||||
bool SAMConfig(void);
|
||||
uint32_t getFirmwareVersion(void);
|
||||
bool writeGPIO(uint8_t pinstate);
|
||||
uint8_t readGPIO(void);
|
||||
bool setPassiveActivationRetries(uint8_t maxRetries);
|
||||
|
||||
/**
|
||||
* @brief Init PN532 as a target
|
||||
* @param timeout max time to wait, 0 means no timeout
|
||||
* @return > 0 success
|
||||
* = 0 timeout
|
||||
* < 0 failed
|
||||
*/
|
||||
int8_t tgInitAsTarget(uint16_t timeout = 0);
|
||||
int16_t tgGetData(uint8_t *buf, uint8_t len);
|
||||
bool tgSetData(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0);
|
||||
|
||||
// ISO14443A functions
|
||||
bool inListPassiveTarget();
|
||||
bool readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout = 1000);
|
||||
bool inDataExchange(uint8_t *send, uint8_t sendLength, uint8_t *response, uint8_t *responseLength);
|
||||
|
||||
// Mifare Classic functions
|
||||
bool mifareclassic_IsFirstBlock (uint32_t uiBlock);
|
||||
bool mifareclassic_IsTrailerBlock (uint32_t uiBlock);
|
||||
uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData);
|
||||
uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data);
|
||||
uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data);
|
||||
uint8_t mifareclassic_FormatNDEF (void);
|
||||
uint8_t mifareclassic_WriteNDEFURI (uint8_t sectorNumber, uint8_t uriIdentifier, const char *url);
|
||||
|
||||
// Mifare Ultralight functions
|
||||
uint8_t mifareultralight_ReadPage (uint8_t page, uint8_t *buffer);
|
||||
|
||||
// Help functions to display formatted text
|
||||
static void PrintHex(const uint8_t *data, const uint32_t numBytes);
|
||||
static void PrintHexChar(const uint8_t *pbtData, const uint32_t numBytes);
|
||||
|
||||
uint8_t *getBuffer(uint8_t *len) {
|
||||
*len = sizeof(pn532_packetbuffer) - 4;
|
||||
return pn532_packetbuffer;
|
||||
};
|
||||
|
||||
private:
|
||||
uint8_t _uid[7]; // ISO14443A uid
|
||||
uint8_t _uidLen; // uid len
|
||||
uint8_t _key[6]; // Mifare Classic key
|
||||
uint8_t inListedTag; // Tg number of inlisted tag.
|
||||
|
||||
uint8_t pn532_packetbuffer[64];
|
||||
|
||||
PN532Interface *_interface;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
|
||||
|
||||
#ifndef __PN532_INTERFACE_H__
|
||||
#define __PN532_INTERFACE_H__
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#define PN532_PREAMBLE (0x00)
|
||||
#define PN532_STARTCODE1 (0x00)
|
||||
#define PN532_STARTCODE2 (0xFF)
|
||||
#define PN532_POSTAMBLE (0x00)
|
||||
|
||||
#define PN532_HOSTTOPN532 (0xD4)
|
||||
#define PN532_PN532TOHOST (0xD5)
|
||||
|
||||
#define PN532_ACK_WAIT_TIME (10) // ms, timeout of waiting for ACK
|
||||
|
||||
#define PN532_INVALID_ACK (-1)
|
||||
#define PN532_TIMEOUT (-2)
|
||||
#define PN532_INVALID_FRAME (-3)
|
||||
#define PN532_NO_SPACE (-4)
|
||||
|
||||
class PN532Interface
|
||||
{
|
||||
public:
|
||||
virtual void begin() = 0;
|
||||
virtual void wakeup() = 0;
|
||||
|
||||
/**
|
||||
* @brief write a command and check ack
|
||||
* @param header packet header
|
||||
* @param hlen length of header
|
||||
* @param body packet body
|
||||
* @param blen length of body
|
||||
* @return 0 success
|
||||
* not 0 failed
|
||||
*/
|
||||
virtual int8_t writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0) = 0;
|
||||
|
||||
/**
|
||||
* @brief read the response of a command, strip prefix and suffix
|
||||
* @param buf to contain the response data
|
||||
* @param len lenght to read
|
||||
* @param timeout max time to wait, 0 means no timeout
|
||||
* @return >=0 length of response without prefix and suffix
|
||||
* <0 failed to read response
|
||||
*/
|
||||
virtual int16_t readResponse(uint8_t buf[], uint8_t len, uint16_t timeout = 1000) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DMSG(args...) Serial.print(args)
|
||||
#define DMSG_STR(str) Serial.println(str)
|
||||
#define DMSG_HEX(num) Serial.print(' '); Serial.print(num, HEX)
|
||||
#define DMSG_INT(num) Serial.print(' '); Serial.print(num)
|
||||
#else
|
||||
#define DMSG(args...)
|
||||
#define DMSG_STR(str)
|
||||
#define DMSG_HEX(num)
|
||||
#define DMSG_INT(num)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
## NFC library for Arduino
|
||||
|
||||
This is an Arduino library for PN532 to use NFC technology. It's based on
|
||||
[Adafruit_NFCShield_I2C](http://goo.gl/pk3FdB)
|
||||
and improved by [Seeed Studio](http://goo.gl/zh1iQh).
|
||||
It works with:
|
||||
|
||||
+ [Elechouse NFC Module](http://goo.gl/i0EQgd)
|
||||
+ [NFC Shield](http://goo.gl/Cac2OH)
|
||||
+ [Xadow NFC](http://goo.gl/qBZMt0)
|
||||
+ [PN532 NFC/RFID controller breakout board](http://goo.gl/tby9Sw)
|
||||
|
||||
### Features
|
||||
+ Support I2C, SPI and HSU of PN532
|
||||
+ Read/write Mifare Classic Card
|
||||
+ Works with [Don's NDEF Library](http://goo.gl/jDjsXl)
|
||||
+ Support Peer to Peer communication(exchange data with android 4.0+)
|
||||
+ Support [mbed platform](http://goo.gl/kGPovZ)
|
||||
|
||||
### Getting Started
|
||||
1. Download [zip file](http://goo.gl/F6beRM) and
|
||||
extract the 4 folders(PN532, PN532_SPI, PN532_I2C and PN532_HSU) into Arduino's libraries.
|
||||
2. Downlaod [Don's NDEF library](http://goo.gl/ewxeAe) and extract it intro Arduino's libraries.
|
||||
3. Follow the examples of the two libraries.
|
||||
|
||||
|
||||
### To do
|
||||
+ Card emulation
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
This example will attempt to connect to an ISO14443A
|
||||
card or tag and retrieve some basic information about it
|
||||
that can be used to determine what type of card it is.
|
||||
|
||||
Note that you need the baud rate to be 115200 because we need to print
|
||||
out the data and read from the card at the same time!
|
||||
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
// choose to SPI or I2C or HSU
|
||||
#if 0
|
||||
#include <SPI.h>
|
||||
#include <PN532_SPI.h>
|
||||
#include "PN532.h"
|
||||
|
||||
PN532_SPI pn532spi(SPI, 10);
|
||||
PN532 nfc(pn532spi);
|
||||
#elif 0
|
||||
#include <PN532_HSU.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_HSU pn532hsu(Serial1);
|
||||
PN532 nfc(pn532hsu);
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#include <PN532_I2C.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_I2C pn532i2c(Wire);
|
||||
PN532 nfc(pn532i2c);
|
||||
#endif
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Hello!");
|
||||
|
||||
nfc.begin();
|
||||
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (! versiondata) {
|
||||
Serial.print("Didn't find PN53x board");
|
||||
while (1); // halt
|
||||
}
|
||||
|
||||
// Got ok data, print it out!
|
||||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
|
||||
// Set the max number of retry attempts to read from a card
|
||||
// This prevents us from waiting forever for a card, which is
|
||||
// the default behaviour of the PN532.
|
||||
nfc.setPassiveActivationRetries(0xFF);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
|
||||
Serial.println("Waiting for an ISO14443A card");
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
boolean success;
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
|
||||
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
|
||||
|
||||
if (success) {
|
||||
Serial.println("Found a card!");
|
||||
Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||
Serial.print("UID Value: ");
|
||||
for (uint8_t i=0; i < uidLength; i++)
|
||||
{
|
||||
Serial.print(" 0x");Serial.print(uid[i], HEX);
|
||||
}
|
||||
Serial.println("");
|
||||
// Wait 1 second before continuing
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// PN532 probably timed out waiting for a card
|
||||
Serial.println("Timed out waiting for a card");
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
This example attempts to format a clean Mifare Classic 1K card as
|
||||
an NFC Forum tag (to store NDEF messages that can be read by any
|
||||
NFC enabled Android phone, etc.)
|
||||
|
||||
Note that you need the baud rate to be 115200 because we need to print
|
||||
out the data and read from the card at the same time!
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
// choose to SPI or I2C or HSU
|
||||
#if 0
|
||||
#include <SPI.h>
|
||||
#include <PN532_SPI.h>
|
||||
#include "PN532.h"
|
||||
|
||||
PN532SPI pn532spi(SPI, 10);
|
||||
PN532 nfc(pn532spi);
|
||||
#elif 0
|
||||
#include <PN532_HSU.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_HSU pn532hsu(Serial1);
|
||||
PN532 nfc(pn532hsu);
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#include <PN532_I2C.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_I2C pn532i2c(Wire);
|
||||
PN532 nfc(pn532i2c);
|
||||
#endif
|
||||
|
||||
/*
|
||||
We can encode many different kinds of pointers to the card,
|
||||
from a URL, to an Email address, to a phone number, and many more
|
||||
check the library header .h file to see the large # of supported
|
||||
prefixes!
|
||||
*/
|
||||
// For a http://www. url:
|
||||
const char * url = "elechouse.com";
|
||||
uint8_t ndefprefix = NDEF_URIPREFIX_HTTP_WWWDOT;
|
||||
|
||||
// for an email address
|
||||
//const char * url = "mail@example.com";
|
||||
//uint8_t ndefprefix = NDEF_URIPREFIX_MAILTO;
|
||||
|
||||
// for a phone number
|
||||
//const char * url = "+1 212 555 1212";
|
||||
//uint8_t ndefprefix = NDEF_URIPREFIX_TEL;
|
||||
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Looking for PN532...");
|
||||
|
||||
nfc.begin();
|
||||
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (! versiondata) {
|
||||
Serial.print("Didn't find PN53x board");
|
||||
while (1); // halt
|
||||
}
|
||||
|
||||
// Got ok data, print it out!
|
||||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
uint8_t success; // Flag to check if there was an error with the PN532
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
bool authenticated = false; // Flag to indicate if the sector is authenticated
|
||||
|
||||
// Use the default key
|
||||
uint8_t keya[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
Serial.println("");
|
||||
Serial.println("PLEASE NOTE: Formatting your card for NDEF records will change the");
|
||||
Serial.println("authentication keys. To reformat your NDEF tag as a clean Mifare");
|
||||
Serial.println("Classic tag, use the mifareclassic_ndeftoclassic example!");
|
||||
Serial.println("");
|
||||
Serial.println("Place your Mifare Classic card on the reader to format with NDEF");
|
||||
Serial.println("and press any key to continue ...");
|
||||
// Wait for user input before proceeding
|
||||
while (!Serial.available());
|
||||
// a key was pressed1
|
||||
while (Serial.available()) Serial.read();
|
||||
|
||||
// Wait for an ISO14443A type card (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||
|
||||
if (success)
|
||||
{
|
||||
// Display some basic information about the card
|
||||
Serial.println("Found an ISO14443A card");
|
||||
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||
Serial.print(" UID Value: ");
|
||||
nfc.PrintHex(uid, uidLength);
|
||||
Serial.println("");
|
||||
|
||||
// Make sure this is a Mifare Classic card
|
||||
if (uidLength != 4)
|
||||
{
|
||||
Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
|
||||
return;
|
||||
}
|
||||
|
||||
// We probably have a Mifare Classic card ...
|
||||
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||
|
||||
// Try to format the card for NDEF data
|
||||
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 0, 0, keya);
|
||||
if (!success)
|
||||
{
|
||||
Serial.println("Unable to authenticate block 0 to enable card formatting!");
|
||||
return;
|
||||
}
|
||||
success = nfc.mifareclassic_FormatNDEF();
|
||||
if (!success)
|
||||
{
|
||||
Serial.println("Unable to format the card for NDEF");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Card has been formatted for NDEF data using MAD1");
|
||||
|
||||
// Try to authenticate block 4 (first block of sector 1) using our key
|
||||
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 4, 0, keya);
|
||||
|
||||
// Make sure the authentification process didn't fail
|
||||
if (!success)
|
||||
{
|
||||
Serial.println("Authentication failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to write a URL
|
||||
Serial.println("Writing URI to sector 1 as an NDEF Message");
|
||||
|
||||
// Authenticated seems to have worked
|
||||
// Try to write an NDEF record to sector 1
|
||||
// Use 0x01 for the URI Identifier Code to prepend "http://www."
|
||||
// to the url (and save some space). For information on URI ID Codes
|
||||
// see http://www.ladyada.net/wiki/private/articlestaging/nfc/ndef
|
||||
if (strlen(url) > 38)
|
||||
{
|
||||
// The length is also checked in the WriteNDEFURI function, but lets
|
||||
// warn users here just in case they change the value and it's bigger
|
||||
// than it should be
|
||||
Serial.println("URI is too long ... must be less than 38 characters long");
|
||||
return;
|
||||
}
|
||||
|
||||
// URI is within size limits ... write it to the card and report success/failure
|
||||
success = nfc.mifareclassic_WriteNDEFURI(1, ndefprefix, url);
|
||||
if (success)
|
||||
{
|
||||
Serial.println("NDEF URI Record written to sector 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("NDEF Record creation failed! :(");
|
||||
}
|
||||
}
|
||||
|
||||
// Wait a bit before trying again
|
||||
Serial.println("\n\nDone!");
|
||||
delay(1000);
|
||||
Serial.flush();
|
||||
while(Serial.available()) Serial.read();
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
This example attempts to dump the contents of a Mifare Classic 1K card
|
||||
|
||||
Note that you need the baud rate to be 115200 because we need to print
|
||||
out the data and read from the card at the same time!
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
// choose to SPI or I2C or HSU
|
||||
#if 0
|
||||
#include <SPI.h>
|
||||
#include <PN532_SPI.h>
|
||||
#include "PN532.h"
|
||||
|
||||
PN532SPI pn532spi(SPI, 10);
|
||||
PN532 nfc(pn532spi);
|
||||
#elif 0
|
||||
#include <PN532_HSU.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_HSU pn532hsu(Serial1);
|
||||
PN532 nfc(pn532hsu);
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#include <PN532_I2C.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_I2C pn532i2c(Wire);
|
||||
PN532 nfc(pn532i2c);
|
||||
#endif
|
||||
|
||||
void setup(void) {
|
||||
// has to be fast to dump the entire memory contents!
|
||||
Serial.begin(115200);
|
||||
Serial.println("Looking for PN532...");
|
||||
|
||||
nfc.begin();
|
||||
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (! versiondata) {
|
||||
Serial.print("Didn't find PN53x board");
|
||||
while (1); // halt
|
||||
}
|
||||
// Got ok data, print it out!
|
||||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
|
||||
Serial.println("Waiting for an ISO14443A Card ...");
|
||||
}
|
||||
|
||||
|
||||
void loop(void) {
|
||||
uint8_t success; // Flag to check if there was an error with the PN532
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
uint8_t currentblock; // Counter to keep track of which block we're on
|
||||
bool authenticated = false; // Flag to indicate if the sector is authenticated
|
||||
uint8_t data[16]; // Array to store block data during reads
|
||||
|
||||
// Keyb on NDEF and Mifare Classic should be the same
|
||||
uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||
|
||||
if (success) {
|
||||
// Display some basic information about the card
|
||||
Serial.println("Found an ISO14443A card");
|
||||
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||
Serial.print(" UID Value: ");
|
||||
nfc.PrintHex(uid, uidLength);
|
||||
Serial.println("");
|
||||
|
||||
if (uidLength == 4)
|
||||
{
|
||||
// We probably have a Mifare Classic card ...
|
||||
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||
|
||||
// Now we try to go through all 16 sectors (each having 4 blocks)
|
||||
// authenticating each sector, and then dumping the blocks
|
||||
for (currentblock = 0; currentblock < 64; currentblock++)
|
||||
{
|
||||
// Check if this is a new block so that we can reauthenticate
|
||||
if (nfc.mifareclassic_IsFirstBlock(currentblock)) authenticated = false;
|
||||
|
||||
// If the sector hasn't been authenticated, do so first
|
||||
if (!authenticated)
|
||||
{
|
||||
// Starting of a new sector ... try to to authenticate
|
||||
Serial.print("------------------------Sector ");Serial.print(currentblock/4, DEC);Serial.println("-------------------------");
|
||||
if (currentblock == 0)
|
||||
{
|
||||
// This will be 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF for Mifare Classic (non-NDEF!)
|
||||
// or 0xA0 0xA1 0xA2 0xA3 0xA4 0xA5 for NDEF formatted cards using key a,
|
||||
// but keyb should be the same for both (0xFF 0xFF 0xFF 0xFF 0xFF 0xFF)
|
||||
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 1, keyuniversal);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This will be 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF for Mifare Classic (non-NDEF!)
|
||||
// or 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7 for NDEF formatted cards using key a,
|
||||
// but keyb should be the same for both (0xFF 0xFF 0xFF 0xFF 0xFF 0xFF)
|
||||
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, currentblock, 1, keyuniversal);
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
authenticated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Authentication error");
|
||||
}
|
||||
}
|
||||
// If we're still not authenticated just skip the block
|
||||
if (!authenticated)
|
||||
{
|
||||
Serial.print("Block ");Serial.print(currentblock, DEC);Serial.println(" unable to authenticate");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Authenticated ... we should be able to read the block now
|
||||
// Dump the data into the 'data' array
|
||||
success = nfc.mifareclassic_ReadDataBlock(currentblock, data);
|
||||
if (success)
|
||||
{
|
||||
// Read successful
|
||||
Serial.print("Block ");Serial.print(currentblock, DEC);
|
||||
if (currentblock < 10)
|
||||
{
|
||||
Serial.print(" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(" ");
|
||||
}
|
||||
// Dump the raw data
|
||||
nfc.PrintHexChar(data, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Oops ... something happened
|
||||
Serial.print("Block ");Serial.print(currentblock, DEC);
|
||||
Serial.println(" unable to read this block");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
|
||||
}
|
||||
}
|
||||
// Wait a bit before trying again
|
||||
Serial.println("\n\nSend a character to run the mem dumper again!");
|
||||
Serial.flush();
|
||||
while (!Serial.available());
|
||||
while (Serial.available()) {
|
||||
Serial.read();
|
||||
}
|
||||
Serial.flush();
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
This examples attempts to take a Mifare Classic 1K card that has been
|
||||
formatted for NDEF messages using mifareclassic_formatndef, and resets
|
||||
the authentication keys back to the Mifare Classic defaults
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
// choose to SPI or I2C or HSU
|
||||
#if 0
|
||||
#include <SPI.h>
|
||||
#include <PN532_SPI.h>
|
||||
#include "PN532.h"
|
||||
|
||||
PN532SPI pn532spi(SPI, 10);
|
||||
PN532 nfc(pn532spi);
|
||||
#elif 0
|
||||
#include <PN532_HSU.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_HSU pn532hsu(Serial1);
|
||||
PN532 nfc(pn532hsu);
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#include <PN532_I2C.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_I2C pn532i2c(Wire);
|
||||
PN532 nfc(pn532i2c);
|
||||
#endif
|
||||
|
||||
|
||||
#define NR_SHORTSECTOR (32) // Number of short sectors on Mifare 1K/4K
|
||||
#define NR_LONGSECTOR (8) // Number of long sectors on Mifare 4K
|
||||
#define NR_BLOCK_OF_SHORTSECTOR (4) // Number of blocks in a short sector
|
||||
#define NR_BLOCK_OF_LONGSECTOR (16) // Number of blocks in a long sector
|
||||
|
||||
// Determine the sector trailer block based on sector number
|
||||
#define BLOCK_NUMBER_OF_SECTOR_TRAILER(sector) (((sector)<NR_SHORTSECTOR)? \
|
||||
((sector)*NR_BLOCK_OF_SHORTSECTOR + NR_BLOCK_OF_SHORTSECTOR-1):\
|
||||
(NR_SHORTSECTOR*NR_BLOCK_OF_SHORTSECTOR + (sector-NR_SHORTSECTOR)*NR_BLOCK_OF_LONGSECTOR + NR_BLOCK_OF_LONGSECTOR-1))
|
||||
|
||||
// Determine the sector's first block based on the sector number
|
||||
#define BLOCK_NUMBER_OF_SECTOR_1ST_BLOCK(sector) (((sector)<NR_SHORTSECTOR)? \
|
||||
((sector)*NR_BLOCK_OF_SHORTSECTOR):\
|
||||
(NR_SHORTSECTOR*NR_BLOCK_OF_SHORTSECTOR + (sector-NR_SHORTSECTOR)*NR_BLOCK_OF_LONGSECTOR))
|
||||
|
||||
// The default Mifare Classic key
|
||||
static const uint8_t KEY_DEFAULT_KEYAB[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Looking for PN532...");
|
||||
|
||||
nfc.begin();
|
||||
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (! versiondata) {
|
||||
Serial.print("Didn't find PN53x board");
|
||||
while (1); // halt
|
||||
}
|
||||
|
||||
// Got ok data, print it out!
|
||||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
uint8_t success; // Flag to check if there was an error with the PN532
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
bool authenticated = false; // Flag to indicate if the sector is authenticated
|
||||
uint8_t blockBuffer[16]; // Buffer to store block contents
|
||||
uint8_t blankAccessBits[3] = { 0xff, 0x07, 0x80 };
|
||||
uint8_t idx = 0;
|
||||
uint8_t numOfSector = 16; // Assume Mifare Classic 1K for now (16 4-block sectors)
|
||||
|
||||
Serial.println("Place your NDEF formatted Mifare Classic 1K card on the reader");
|
||||
Serial.println("and press any key to continue ...");
|
||||
|
||||
// Wait for user input before proceeding
|
||||
while (!Serial.available());
|
||||
while (Serial.available()) Serial.read();
|
||||
|
||||
// Wait for an ISO14443A type card (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||
|
||||
if (success)
|
||||
{
|
||||
// We seem to have a tag ...
|
||||
// Display some basic information about it
|
||||
Serial.println("Found an ISO14443A card/tag");
|
||||
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||
Serial.print(" UID Value: ");
|
||||
nfc.PrintHex(uid, uidLength);
|
||||
Serial.println("");
|
||||
|
||||
// Make sure this is a Mifare Classic card
|
||||
if (uidLength != 4)
|
||||
{
|
||||
Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||
Serial.println("");
|
||||
Serial.println("Reformatting card for Mifare Classic (please don't touch it!) ... ");
|
||||
|
||||
// Now run through the card sector by sector
|
||||
for (idx = 0; idx < numOfSector; idx++)
|
||||
{
|
||||
// Step 1: Authenticate the current sector using key B 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
|
||||
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, BLOCK_NUMBER_OF_SECTOR_TRAILER(idx), 1, (uint8_t *)KEY_DEFAULT_KEYAB);
|
||||
if (!success)
|
||||
{
|
||||
Serial.print("Authentication failed for sector "); Serial.println(numOfSector);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: Write to the other blocks
|
||||
if (idx == 16)
|
||||
{
|
||||
memset(blockBuffer, 0, sizeof(blockBuffer));
|
||||
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 3, blockBuffer)))
|
||||
{
|
||||
Serial.print("Unable to write to sector "); Serial.println(numOfSector);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((idx == 0) || (idx == 16))
|
||||
{
|
||||
memset(blockBuffer, 0, sizeof(blockBuffer));
|
||||
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 2, blockBuffer)))
|
||||
{
|
||||
Serial.print("Unable to write to sector "); Serial.println(numOfSector);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(blockBuffer, 0, sizeof(blockBuffer));
|
||||
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 3, blockBuffer)))
|
||||
{
|
||||
Serial.print("Unable to write to sector "); Serial.println(numOfSector);
|
||||
return;
|
||||
}
|
||||
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 2, blockBuffer)))
|
||||
{
|
||||
Serial.print("Unable to write to sector "); Serial.println(numOfSector);
|
||||
return;
|
||||
}
|
||||
}
|
||||
memset(blockBuffer, 0, sizeof(blockBuffer));
|
||||
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)) - 1, blockBuffer)))
|
||||
{
|
||||
Serial.print("Unable to write to sector "); Serial.println(numOfSector);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 3: Reset both keys to 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
|
||||
memcpy(blockBuffer, KEY_DEFAULT_KEYAB, sizeof(KEY_DEFAULT_KEYAB));
|
||||
memcpy(blockBuffer + 6, blankAccessBits, sizeof(blankAccessBits));
|
||||
blockBuffer[9] = 0x69;
|
||||
memcpy(blockBuffer + 10, KEY_DEFAULT_KEYAB, sizeof(KEY_DEFAULT_KEYAB));
|
||||
|
||||
// Step 4: Write the trailer block
|
||||
if (!(nfc.mifareclassic_WriteDataBlock((BLOCK_NUMBER_OF_SECTOR_TRAILER(idx)), blockBuffer)))
|
||||
{
|
||||
Serial.print("Unable to write trailer block of sector "); Serial.println(numOfSector);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait a bit before trying again
|
||||
Serial.println("\n\nDone!");
|
||||
delay(1000);
|
||||
Serial.flush();
|
||||
while(Serial.available()) Serial.read();
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
Updates a sector that is already formatted for NDEF (using
|
||||
mifareclassic_formatndef.pde for example), inserting a new url
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
// choose to SPI or I2C or HSU
|
||||
#if 0
|
||||
#include <SPI.h>
|
||||
#include <PN532_SPI.h>
|
||||
#include "PN532.h"
|
||||
|
||||
PN532SPI pn532spi(SPI, 10);
|
||||
PN532 nfc(pn532spi);
|
||||
#elif 0
|
||||
#include <PN532_HSU.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_HSU pn532hsu(Serial1);
|
||||
PN532 nfc(pn532hsu);
|
||||
#else
|
||||
#include <Wire.h>
|
||||
#include <PN532_I2C.h>
|
||||
#include <PN532.h>
|
||||
|
||||
PN532_I2C pn532i2c(Wire);
|
||||
PN532 nfc(pn532i2c);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
We can encode many different kinds of pointers to the card,
|
||||
from a URL, to an Email address, to a phone number, and many more
|
||||
check the library header .h file to see the large # of supported
|
||||
prefixes!
|
||||
*/
|
||||
// For a http://www. url:
|
||||
const char * url = "elechouse.com";
|
||||
uint8_t ndefprefix = NDEF_URIPREFIX_HTTP_WWWDOT;
|
||||
|
||||
// for an email address
|
||||
//const char * url = "sevice@elechouse.com";
|
||||
//uint8_t ndefprefix = NDEF_URIPREFIX_MAILTO;
|
||||
|
||||
// for a phone number
|
||||
//const char * url = "+1 212 555 1212";
|
||||
//uint8_t ndefprefix = NDEF_URIPREFIX_TEL;
|
||||
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Looking for PN532...");
|
||||
|
||||
nfc.begin();
|
||||
|
||||
uint32_t versiondata = nfc.getFirmwareVersion();
|
||||
if (! versiondata) {
|
||||
Serial.print("Didn't find PN53x board");
|
||||
while (1); // halt
|
||||
}
|
||||
|
||||
// Got ok data, print it out!
|
||||
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
|
||||
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
|
||||
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
|
||||
|
||||
// configure board to read RFID tags
|
||||
nfc.SAMConfig();
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
uint8_t success; // Flag to check if there was an error with the PN532
|
||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
|
||||
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
|
||||
bool authenticated = false; // Flag to indicate if the sector is authenticated
|
||||
|
||||
// Use the default NDEF keys (these would have have set by mifareclassic_formatndef.pde!)
|
||||
uint8_t keya[6] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 };
|
||||
uint8_t keyb[6] = { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 };
|
||||
|
||||
Serial.println("Place your NDEF formatted Mifare Classic card on the reader to update the");
|
||||
Serial.println("NDEF record and press any key to continue ...");
|
||||
// Wait for user input before proceeding
|
||||
while (!Serial.available());
|
||||
// a key was pressed1
|
||||
while (Serial.available()) Serial.read();
|
||||
|
||||
// Wait for an ISO14443A type card (Mifare, etc.). When one is found
|
||||
// 'uid' will be populated with the UID, and uidLength will indicate
|
||||
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
|
||||
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
|
||||
|
||||
if (success)
|
||||
{
|
||||
// Display some basic information about the card
|
||||
Serial.println("Found an ISO14443A card");
|
||||
Serial.print(" UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
|
||||
Serial.print(" UID Value: ");
|
||||
nfc.PrintHex(uid, uidLength);
|
||||
Serial.println("");
|
||||
|
||||
// Make sure this is a Mifare Classic card
|
||||
if (uidLength != 4)
|
||||
{
|
||||
Serial.println("Ooops ... this doesn't seem to be a Mifare Classic card!");
|
||||
return;
|
||||
}
|
||||
|
||||
// We probably have a Mifare Classic card ...
|
||||
Serial.println("Seems to be a Mifare Classic card (4 byte UID)");
|
||||
|
||||
// Check if this is an NDEF card (using first block of sector 1 from mifareclassic_formatndef.pde)
|
||||
// Must authenticate on the first key using 0xD3 0xF7 0xD3 0xF7 0xD3 0xF7
|
||||
success = nfc.mifareclassic_AuthenticateBlock (uid, uidLength, 4, 0, keyb);
|
||||
if (!success)
|
||||
{
|
||||
Serial.println("Unable to authenticate block 4 ... is this card NDEF formatted?");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Authentication succeeded (seems to be an NDEF/NFC Forum tag) ...");
|
||||
|
||||
// Authenticated seems to have worked
|
||||
// Try to write an NDEF record to sector 1
|
||||
// Use 0x01 for the URI Identifier Code to prepend "http://www."
|
||||
// to the url (and save some space). For information on URI ID Codes
|
||||
// see http://www.ladyada.net/wiki/private/articlestaging/nfc/ndef
|
||||
if (strlen(url) > 38)
|
||||
{
|
||||
// The length is also checked in the WriteNDEFURI function, but lets
|
||||
// warn users here just in case they change the value and it's bigger
|
||||
// than it should be
|
||||
Serial.println("URI is too long ... must be less than 38 characters!");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Updating sector 1 with URI as NDEF Message");
|
||||
|
||||
// URI is within size limits ... write it to the card and report success/failure
|
||||
success = nfc.mifareclassic_WriteNDEFURI(1, ndefprefix, url);
|
||||
if (success)
|
||||
{
|
||||
Serial.println("NDEF URI Record written to sector 1");
|
||||
Serial.println("");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("NDEF Record creation failed! :(");
|
||||
}
|
||||
}
|
||||
|
||||
// Wait a bit before trying again
|
||||
Serial.println("\n\nDone!");
|
||||
delay(1000);
|
||||
Serial.flush();
|
||||
while(Serial.available()) Serial.read();
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// snep_test.ino
|
||||
// send a SNEP message to adnroid and get a message from android
|
||||
|
||||
#include "SPI.h"
|
||||
#include "PN532_SPI.h"
|
||||
#include "llcp.h"
|
||||
#include "snep.h"
|
||||
|
||||
PN532_SPI pn532spi(SPI, 10);
|
||||
SNEP nfc(pn532spi);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println("-------Peer to Peer--------");
|
||||
}
|
||||
|
||||
uint8_t message[] = {
|
||||
0xD2, 0xA, 0xB, 0x74,0x65, 0x78, 0x74, 0x2F, 0x70, 0x6C,
|
||||
0x61, 0x69, 0x6E, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77,
|
||||
0x6F, 0x72, 0x6C, 0x64};
|
||||
|
||||
uint8_t buf[128];
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
nfc.write(message, sizeof(message));
|
||||
delay(3000);
|
||||
|
||||
int16_t len = nfc.read(buf, sizeof(buf));
|
||||
if (len > 0) {
|
||||
Serial.println("get a SNEP message:");
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
Serial.print(buf[i], HEX);
|
||||
Serial.print(' ');
|
||||
}
|
||||
Serial.print('\n');
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
char c = buf[i];
|
||||
if (c <= 0x1f || c > 0x7f) {
|
||||
Serial.print('.');
|
||||
} else {
|
||||
Serial.print(c);
|
||||
}
|
||||
}
|
||||
Serial.print('\n');
|
||||
}
|
||||
delay(3000);
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// send a NDEF message to adnroid or get a NDEF message
|
||||
//
|
||||
// note: [NDEF library](https://github.com/Don/NDEF) is needed.
|
||||
|
||||
#include "SPI.h"
|
||||
#include "PN532_SPI.h"
|
||||
#include "snep.h"
|
||||
#include "NdefMessage.h"
|
||||
|
||||
PN532_SPI pn532spi(SPI, 10);
|
||||
SNEP nfc(pn532spi);
|
||||
uint8_t ndefBuf[128];
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println("-------Peer to Peer--------");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
#if 1
|
||||
Serial.println("Send a message to Android");
|
||||
NdefMessage message = NdefMessage();
|
||||
message.addUriRecord("http://www.seeedstudio.com");
|
||||
int messageSize = message.getEncodedSize();
|
||||
if (messageSize > sizeof(ndefBuf)) {
|
||||
Serial.println("ndefBuf is too small");
|
||||
while (1) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
message.encode(ndefBuf);
|
||||
if (0 >= nfc.write(ndefBuf, messageSize)) {
|
||||
Serial.println("Failed");
|
||||
} else {
|
||||
Serial.println("Success");
|
||||
}
|
||||
|
||||
delay(3000);
|
||||
#else
|
||||
// it seems there are some issues to use NdefMessage to decode the received data from Android
|
||||
Serial.println("Get a message from Android");
|
||||
int msgSize = nfc.read(ndefBuf, sizeof(ndefBuf));
|
||||
if (msgSize > 0) {
|
||||
NdefMessage msg = NdefMessage(ndefBuf, msgSize);
|
||||
msg.print();
|
||||
Serial.println("\nSuccess");
|
||||
} else {
|
||||
Serial.println("failed");
|
||||
}
|
||||
delay(3000);
|
||||
#endif
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user